GBP Endpoint Updates 09/14709/8
authorNeale Ranns <neale.ranns@cisco.com>
Wed, 5 Sep 2018 22:42:26 +0000 (15:42 -0700)
committerNeale Ranns <nranns@cisco.com>
Tue, 11 Sep 2018 16:00:29 +0000 (16:00 +0000)
- common types on the API
- endpoints keyed in various ways for DP lookup
- conparison functions for VPP IP address types

Change-Id: If7ec0bbc5cea71fd0983fe78987d147ec1bd7ec8
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
39 files changed:
extras/vom/vom/gbp_endpoint.cpp
extras/vom/vom/gbp_endpoint.hpp
extras/vom/vom/gbp_endpoint_cmds.cpp
extras/vom/vom/gbp_endpoint_cmds.hpp
extras/vom/vom/gbp_subnet.cpp
extras/vom/vom/gbp_subnet_cmds.cpp
extras/vom/vom/prefix.hpp
src/plugins/gbp/gbp.api
src/plugins/gbp/gbp_api.c
src/plugins/gbp/gbp_classify.c
src/plugins/gbp/gbp_endpoint.c
src/plugins/gbp/gbp_endpoint.h
src/plugins/gbp/gbp_endpoint_group.c
src/plugins/gbp/gbp_policy.c
src/plugins/gbp/gbp_recirc.c
src/plugins/gbp/gbp_recirc.h
src/vnet/ip/ip6_packet.h
test/test_abf.py
test/test_bfd.py
test/test_bier.py
test/test_gbp.py
test/test_gre.py
test/test_ip6.py
test/test_ip_mcast.py
test/test_ipip.py
test/test_map.py
test/test_mpls.py
test/test_mtu.py
test/test_p2p_ethernet.py
test/test_qos.py
test/test_reassembly.py
test/test_sixrd.py
test/test_srmpls.py
test/test_srv6_ad.py
test/vpp_ip.py
test/vpp_ip_route.py
test/vpp_mac.py [new file with mode: 0644]
test/vpp_papi_provider.py
test/vpp_udp_encap.py

index 9762a91..236a961 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "vom/gbp_endpoint.hpp"
  */
 
 #include "vom/gbp_endpoint.hpp"
+#include "vom/api_types.hpp"
 #include "vom/gbp_endpoint_cmds.hpp"
 #include "vom/singular_db_funcs.hpp"
 
 #include "vom/gbp_endpoint_cmds.hpp"
 #include "vom/singular_db_funcs.hpp"
 
@@ -23,22 +24,23 @@ singular_db<gbp_endpoint::key_t, gbp_endpoint> gbp_endpoint::m_db;
 
 gbp_endpoint::event_handler gbp_endpoint::m_evh;
 
 
 gbp_endpoint::event_handler gbp_endpoint::m_evh;
 
-gbp_endpoint::gbp_endpoint(const interface& itf,
-                           const boost::asio::ip::address& ip_addr,
-                           const mac_address_t& mac,
-                           const gbp_endpoint_group& epg)
-  : m_hw(false)
+gbp_endpoint::gbp_endpoint(
+  const interface& itf,
+  const std::vector<boost::asio::ip::address>& ip_addrs,
+  const mac_address_t& mac,
+  const gbp_endpoint_group& epg)
+  : m_hdl(handle_t::INVALID)
   , m_itf(itf.singular())
   , m_itf(itf.singular())
-  , m_ip(ip_addr)
+  , m_ips(ip_addrs)
   , m_mac(mac)
   , m_epg(epg.singular())
 {
 }
 
 gbp_endpoint::gbp_endpoint(const gbp_endpoint& gbpe)
   , m_mac(mac)
   , m_epg(epg.singular())
 {
 }
 
 gbp_endpoint::gbp_endpoint(const gbp_endpoint& gbpe)
-  : m_hw(gbpe.m_hw)
+  : m_hdl(gbpe.m_hdl)
   , m_itf(gbpe.m_itf)
   , m_itf(gbpe.m_itf)
-  , m_ip(gbpe.m_ip)
+  , m_ips(gbpe.m_ips)
   , m_mac(gbpe.m_mac)
   , m_epg(gbpe.m_epg)
 {
   , m_mac(gbpe.m_mac)
   , m_epg(gbpe.m_epg)
 {
@@ -53,7 +55,7 @@ gbp_endpoint::~gbp_endpoint()
 const gbp_endpoint::key_t
 gbp_endpoint::key() const
 {
 const gbp_endpoint::key_t
 gbp_endpoint::key() const
 {
-  return (std::make_pair(m_itf->key(), m_ip));
+  return (std::make_pair(m_itf->key(), m_mac));
 }
 
 bool
 }
 
 bool
@@ -65,8 +67,8 @@ gbp_endpoint::operator==(const gbp_endpoint& gbpe) const
 void
 gbp_endpoint::sweep()
 {
 void
 gbp_endpoint::sweep()
 {
-  if (m_hw) {
-    HW::enqueue(new gbp_endpoint_cmds::delete_cmd(m_hw, m_itf->handle(), m_ip));
+  if (m_hdl) {
+    HW::enqueue(new gbp_endpoint_cmds::delete_cmd(m_hdl));
   }
   HW::write();
 }
   }
   HW::write();
 }
@@ -74,8 +76,8 @@ gbp_endpoint::sweep()
 void
 gbp_endpoint::replay()
 {
 void
 gbp_endpoint::replay()
 {
-  if (m_hw) {
-    HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(), m_ip,
+  if (m_hdl) {
+    HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hdl, m_itf->handle(), m_ips,
                                                   m_mac, m_epg->id()));
   }
 }
                                                   m_mac, m_epg->id()));
   }
 }
@@ -84,8 +86,12 @@ std::string
 gbp_endpoint::to_string() const
 {
   std::ostringstream s;
 gbp_endpoint::to_string() const
 {
   std::ostringstream s;
-  s << "gbp-endpoint:[" << m_itf->to_string() << ", " << m_ip.to_string()
-    << ", " << m_mac.to_string() << ", epg:" << m_epg->to_string() << "]";
+  s << "gbp-endpoint:[" << m_itf->to_string() << ", ips:[";
+
+  for (auto ip : m_ips)
+    s << ip.to_string();
+
+  s << "], " << m_mac.to_string() << ", epg:" << m_epg->to_string() << "]";
 
   return (s.str());
 }
 
   return (s.str());
 }
@@ -93,8 +99,8 @@ gbp_endpoint::to_string() const
 void
 gbp_endpoint::update(const gbp_endpoint& r)
 {
 void
 gbp_endpoint::update(const gbp_endpoint& r)
 {
-  if (rc_t::OK != m_hw.rc()) {
-    HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(), m_ip,
+  if (rc_t::OK != m_hdl.rc()) {
+    HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hdl, m_itf->handle(), m_ips,
                                                   m_mac, m_epg->id()));
   }
 }
                                                   m_mac, m_epg->id()));
   }
 }
@@ -147,18 +153,20 @@ gbp_endpoint::event_handler::handle_populate(const client_db::key_t& key)
   for (auto& record : *cmd) {
     auto& payload = record.get_payload();
 
   for (auto& record : *cmd) {
     auto& payload = record.get_payload();
 
-    boost::asio::ip::address address =
-      from_bytes(payload.endpoint.is_ip6, payload.endpoint.address);
+    std::vector<boost::asio::ip::address> addresses;
+
+    for (uint8_t n = 0; n < payload.endpoint.n_ips; n++)
+      addresses.push_back(from_api(payload.endpoint.ips[n]));
     std::shared_ptr<interface> itf =
       interface::find(payload.endpoint.sw_if_index);
     std::shared_ptr<gbp_endpoint_group> epg =
       gbp_endpoint_group::find(payload.endpoint.epg_id);
     std::shared_ptr<interface> itf =
       interface::find(payload.endpoint.sw_if_index);
     std::shared_ptr<gbp_endpoint_group> epg =
       gbp_endpoint_group::find(payload.endpoint.epg_id);
-    mac_address_t mac(payload.endpoint.mac);
+    mac_address_t mac = from_api(payload.endpoint.mac);
 
     VOM_LOG(log_level_t::DEBUG) << "data: " << payload.endpoint.sw_if_index;
 
     if (itf && epg) {
 
     VOM_LOG(log_level_t::DEBUG) << "data: " << payload.endpoint.sw_if_index;
 
     if (itf && epg) {
-      gbp_endpoint gbpe(*itf, address, mac, *epg);
+      gbp_endpoint gbpe(*itf, addresses, mac, *epg);
       OM::commit(key, gbpe);
 
       VOM_LOG(log_level_t::DEBUG) << "read: " << gbpe.to_string();
       OM::commit(key, gbpe);
 
       VOM_LOG(log_level_t::DEBUG) << "read: " << gbpe.to_string();
@@ -177,6 +185,15 @@ gbp_endpoint::event_handler::show(std::ostream& os)
 {
   db_dump(m_db, os);
 }
 {
   db_dump(m_db, os);
 }
+
+std::ostream&
+operator<<(std::ostream& os, const gbp_endpoint::key_t& key)
+{
+  os << key.first << "," << key.second;
+
+  return os;
+}
+
 } // namespace VOM
 
 /*
 } // namespace VOM
 
 /*
index f6466a6..d27ad90 100644 (file)
@@ -17,6 +17,7 @@
 #define __VOM_GBP_ENDPOINT_H__
 
 #include <ostream>
 #define __VOM_GBP_ENDPOINT_H__
 
 #include <ostream>
+#include <vector>
 
 #include "vom/gbp_endpoint_group.hpp"
 #include "vom/interface.hpp"
 
 #include "vom/gbp_endpoint_group.hpp"
 #include "vom/interface.hpp"
@@ -32,13 +33,13 @@ public:
   /**
    * The key for a GBP endpoint; interface and IP
    */
   /**
    * The key for a GBP endpoint; interface and IP
    */
-  typedef std::pair<interface::key_t, boost::asio::ip::address> key_t;
+  typedef std::pair<interface::key_t, mac_address_t> key_t;
 
   /**
    * Construct a GBP endpoint
    */
   gbp_endpoint(const interface& itf,
 
   /**
    * Construct a GBP endpoint
    */
   gbp_endpoint(const interface& itf,
-               const boost::asio::ip::address& ip_addr,
+               const std::vector<boost::asio::ip::address>& ip_addr,
                const mac_address_t& mac,
                const gbp_endpoint_group& epg);
 
                const mac_address_t& mac,
                const gbp_endpoint_group& epg);
 
@@ -151,7 +152,7 @@ private:
   /**
    * HW configuration for the result of creating the endpoint
    */
   /**
    * HW configuration for the result of creating the endpoint
    */
-  HW::item<bool> m_hw;
+  HW::item<handle_t> m_hdl;
 
   /**
    * The interface the endpoint is attached to.
 
   /**
    * The interface the endpoint is attached to.
@@ -161,7 +162,7 @@ private:
   /**
    * The IP address of the endpoint
    */
   /**
    * The IP address of the endpoint
    */
-  boost::asio::ip::address m_ip;
+  std::vector<boost::asio::ip::address> m_ips;
 
   /**
    * The MAC address of the endpoint
 
   /**
    * The MAC address of the endpoint
index 1f9078f..8d44c91 100644 (file)
  */
 
 #include "vom/gbp_endpoint_cmds.hpp"
  */
 
 #include "vom/gbp_endpoint_cmds.hpp"
+#include "vom/api_types.hpp"
 
 DEFINE_VAPI_MSG_IDS_GBP_API_JSON;
 
 namespace VOM {
 namespace gbp_endpoint_cmds {
 
 
 DEFINE_VAPI_MSG_IDS_GBP_API_JSON;
 
 namespace VOM {
 namespace gbp_endpoint_cmds {
 
-create_cmd::create_cmd(HW::item<bool>& item,
+create_cmd::create_cmd(HW::item<handle_t>& item,
                        const handle_t& itf,
                        const handle_t& itf,
-                       const boost::asio::ip::address& ip_addr,
+                       const std::vector<boost::asio::ip::address>& ip_addrs,
                        const mac_address_t& mac,
                        epg_id_t epg_id)
   : rpc_cmd(item)
   , m_itf(itf)
                        const mac_address_t& mac,
                        epg_id_t epg_id)
   : rpc_cmd(item)
   , m_itf(itf)
-  , m_ip_addr(ip_addr)
+  , m_ip_addrs(ip_addrs)
   , m_mac(mac)
   , m_epg_id(epg_id)
 {
   , m_mac(mac)
   , m_epg_id(epg_id)
 {
@@ -36,50 +37,76 @@ create_cmd::create_cmd(HW::item<bool>& item,
 bool
 create_cmd::operator==(const create_cmd& other) const
 {
 bool
 create_cmd::operator==(const create_cmd& other) const
 {
-  return ((m_itf == other.m_itf) && (m_ip_addr == other.m_ip_addr) &&
+  return ((m_itf == other.m_itf) && (m_ip_addrs == other.m_ip_addrs) &&
           (m_mac == other.m_mac) && (m_epg_id == other.m_epg_id));
 }
 
 rc_t
 create_cmd::issue(connection& con)
 {
           (m_mac == other.m_mac) && (m_epg_id == other.m_epg_id));
 }
 
 rc_t
 create_cmd::issue(connection& con)
 {
-  msg_t req(con.ctx(), std::ref(*this));
+  msg_t req(con.ctx(), m_ip_addrs.size() * sizeof(vapi_type_address),
+            std::ref(*this));
+  uint8_t n;
 
   auto& payload = req.get_request().get_payload();
 
   auto& payload = req.get_request().get_payload();
-  payload.is_add = 1;
   payload.endpoint.sw_if_index = m_itf.value();
   payload.endpoint.epg_id = m_epg_id;
   payload.endpoint.sw_if_index = m_itf.value();
   payload.endpoint.epg_id = m_epg_id;
-  to_bytes(m_ip_addr, &payload.endpoint.is_ip6, payload.endpoint.address);
-  m_mac.to_bytes(payload.endpoint.mac, 6);
+  payload.endpoint.n_ips = m_ip_addrs.size();
+
+  for (n = 0; n < payload.endpoint.n_ips; n++) {
+    payload.endpoint.ips[n] = to_api(m_ip_addrs[n]);
+  }
+  payload.endpoint.mac = to_api(m_mac);
 
   VAPI_CALL(req.execute());
 
   return (wait());
 }
 
 
   VAPI_CALL(req.execute());
 
   return (wait());
 }
 
+vapi_error_e
+create_cmd::operator()(vapi::Gbp_endpoint_add& reply)
+{
+  int handle = reply.get_response().get_payload().handle;
+  int retval = reply.get_response().get_payload().retval;
+
+  VOM_LOG(log_level_t::DEBUG) << this->to_string() << " " << retval;
+
+  rc_t rc = rc_t::from_vpp_retval(retval);
+  handle_t hdl = handle_t::INVALID;
+
+  if (rc_t::OK == rc) {
+    hdl = handle;
+  }
+
+  this->fulfill(HW::item<handle_t>(hdl, rc));
+
+  return (VAPI_OK);
+}
+
 std::string
 create_cmd::to_string() const
 {
   std::ostringstream s;
   s << "gbp-endpoint-create: " << m_hw_item.to_string() << " itf:" << m_itf
 std::string
 create_cmd::to_string() const
 {
   std::ostringstream s;
   s << "gbp-endpoint-create: " << m_hw_item.to_string() << " itf:" << m_itf
-    << " ip:" << m_ip_addr.to_string() << " epg-id:" << m_epg_id;
+    << " ips:[";
+  for (auto ip : m_ip_addrs)
+    s << ip.to_string();
+
+  s << "] mac:" << m_mac;
+  s << " epg-id:" << m_epg_id;
 
   return (s.str());
 }
 
 
   return (s.str());
 }
 
-delete_cmd::delete_cmd(HW::item<bool>& item,
-                       const handle_t& itf,
-                       const boost::asio::ip::address& ip_addr)
+delete_cmd::delete_cmd(HW::item<handle_t>& item)
   : rpc_cmd(item)
   : rpc_cmd(item)
-  , m_itf(itf)
-  , m_ip_addr(ip_addr)
 {
 }
 
 bool
 delete_cmd::operator==(const delete_cmd& other) const
 {
 {
 }
 
 bool
 delete_cmd::operator==(const delete_cmd& other) const
 {
-  return ((m_itf == other.m_itf) && (m_ip_addr == other.m_ip_addr));
+  return (m_hw_item == other.m_hw_item);
 }
 
 rc_t
 }
 
 rc_t
@@ -88,10 +115,7 @@ delete_cmd::issue(connection& con)
   msg_t req(con.ctx(), std::ref(*this));
 
   auto& payload = req.get_request().get_payload();
   msg_t req(con.ctx(), std::ref(*this));
 
   auto& payload = req.get_request().get_payload();
-  payload.is_add = 0;
-  payload.endpoint.sw_if_index = m_itf.value();
-  payload.endpoint.epg_id = ~0;
-  to_bytes(m_ip_addr, &payload.endpoint.is_ip6, payload.endpoint.address);
+  payload.handle = m_hw_item.data().value();
 
   VAPI_CALL(req.execute());
 
 
   VAPI_CALL(req.execute());
 
@@ -102,8 +126,7 @@ std::string
 delete_cmd::to_string() const
 {
   std::ostringstream s;
 delete_cmd::to_string() const
 {
   std::ostringstream s;
-  s << "gbp-endpoint-delete: " << m_hw_item.to_string() << " itf:" << m_itf
-    << " ip:" << m_ip_addr.to_string();
+  s << "gbp-endpoint-delete: " << m_hw_item.to_string();
 
   return (s.str());
 }
 
   return (s.str());
 }
index dea4c2c..e90fb66 100644 (file)
@@ -27,15 +27,15 @@ namespace gbp_endpoint_cmds {
 /**
 * A command class that creates or updates the GBP endpoint
 */
 /**
 * A command class that creates or updates the GBP endpoint
 */
-class create_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_add_del>
+class create_cmd : public rpc_cmd<HW::item<handle_t>, vapi::Gbp_endpoint_add>
 {
 public:
   /**
    * Constructor
    */
 {
 public:
   /**
    * Constructor
    */
-  create_cmd(HW::item<bool>& item,
+  create_cmd(HW::item<handle_t>& item,
              const handle_t& itf,
              const handle_t& itf,
-             const boost::asio::ip::address& ip_addr,
+             const std::vector<boost::asio::ip::address>& ip_addrs,
              const mac_address_t& mac,
              epg_id_t epg_id);
 
              const mac_address_t& mac,
              epg_id_t epg_id);
 
@@ -49,6 +49,8 @@ public:
    */
   std::string to_string() const;
 
    */
   std::string to_string() const;
 
+  virtual vapi_error_e operator()(vapi::Gbp_endpoint_add& reply);
+
   /**
    * Comparison operator - only used for UT
    */
   /**
    * Comparison operator - only used for UT
    */
@@ -56,7 +58,7 @@ public:
 
 private:
   const handle_t m_itf;
 
 private:
   const handle_t m_itf;
-  const boost::asio::ip::address m_ip_addr;
+  const std::vector<boost::asio::ip::address> m_ip_addrs;
   const mac_address_t m_mac;
   const epg_id_t m_epg_id;
 };
   const mac_address_t m_mac;
   const epg_id_t m_epg_id;
 };
@@ -64,15 +66,13 @@ private:
 /**
  * A cmd class that deletes a GBP endpoint
  */
 /**
  * A cmd class that deletes a GBP endpoint
  */
-class delete_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_add_del>
+class delete_cmd : public rpc_cmd<HW::item<handle_t>, vapi::Gbp_endpoint_del>
 {
 public:
   /**
    * Constructor
    */
 {
 public:
   /**
    * Constructor
    */
-  delete_cmd(HW::item<bool>& item,
-             const handle_t& itf,
-             const boost::asio::ip::address& ip_addr);
+  delete_cmd(HW::item<handle_t>& item);
 
   /**
    * Issue the command to VPP/HW
 
   /**
    * Issue the command to VPP/HW
@@ -90,8 +90,7 @@ public:
   bool operator==(const delete_cmd& i) const;
 
 private:
   bool operator==(const delete_cmd& i) const;
 
 private:
-  const handle_t m_itf;
-  const boost::asio::ip::address m_ip_addr;
+  const handle_t m_hdl;
 };
 
 /**
 };
 
 /**
index 1a9ee86..1bc024d 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "vom/gbp_subnet.hpp"
  */
 
 #include "vom/gbp_subnet.hpp"
+#include "vom/api_types.hpp"
 #include "vom/gbp_subnet_cmds.hpp"
 #include "vom/singular_db_funcs.hpp"
 
 #include "vom/gbp_subnet_cmds.hpp"
 #include "vom/singular_db_funcs.hpp"
 
@@ -190,8 +191,7 @@ gbp_subnet::event_handler::handle_populate(const client_db::key_t& key)
   for (auto& record : *cmd) {
     auto& payload = record.get_payload();
 
   for (auto& record : *cmd) {
     auto& payload = record.get_payload();
 
-    route::prefix_t pfx(payload.subnet.is_ip6, payload.subnet.address,
-                        payload.subnet.address_length);
+    route::prefix_t pfx = from_api(payload.subnet.prefix);
     std::shared_ptr<route_domain> rd =
       route_domain::find(payload.subnet.table_id);
 
     std::shared_ptr<route_domain> rd =
       route_domain::find(payload.subnet.table_id);
 
index 3816a59..79fdf17 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "vom/gbp_subnet_cmds.hpp"
  */
 
 #include "vom/gbp_subnet_cmds.hpp"
+#include "vom/api_types.hpp"
 
 namespace VOM {
 namespace gbp_subnet_cmds {
 
 namespace VOM {
 namespace gbp_subnet_cmds {
@@ -52,8 +53,7 @@ create_cmd::issue(connection& con)
   payload.subnet.table_id = m_rd;
   payload.subnet.sw_if_index = m_itf.value();
   payload.subnet.epg_id = m_epg_id;
   payload.subnet.table_id = m_rd;
   payload.subnet.sw_if_index = m_itf.value();
   payload.subnet.epg_id = m_epg_id;
-  m_prefix.to_vpp(&payload.subnet.is_ip6, payload.subnet.address,
-                  &payload.subnet.address_length);
+  payload.subnet.prefix = to_api(m_prefix);
 
   VAPI_CALL(req.execute());
 
 
   VAPI_CALL(req.execute());
 
@@ -94,8 +94,7 @@ delete_cmd::issue(connection& con)
   auto& payload = req.get_request().get_payload();
   payload.is_add = 0;
   payload.subnet.table_id = m_rd;
   auto& payload = req.get_request().get_payload();
   payload.is_add = 0;
   payload.subnet.table_id = m_rd;
-  m_prefix.to_vpp(&payload.subnet.is_ip6, payload.subnet.address,
-                  &payload.subnet.address_length);
+  payload.subnet.prefix = to_api(m_prefix);
 
   payload.subnet.is_internal = 0;
   payload.subnet.sw_if_index = ~0;
 
   payload.subnet.is_internal = 0;
   payload.subnet.sw_if_index = ~0;
index 3950f6f..8365541 100644 (file)
@@ -16,9 +16,8 @@
 #ifndef __VOM_PREFIX_H__
 #define __VOM_PREFIX_H__
 
 #ifndef __VOM_PREFIX_H__
 #define __VOM_PREFIX_H__
 
-#include <boost/asio/ip/address.hpp>
-
 #include "vom/enum_base.hpp"
 #include "vom/enum_base.hpp"
+#include <boost/asio/ip/address.hpp>
 
 namespace VOM {
 /**
 
 namespace VOM {
 /**
@@ -111,10 +110,12 @@ public:
    * Constructor with string and length
    */
   prefix_t(const std::string& s, uint8_t len);
    * Constructor with string and length
    */
   prefix_t(const std::string& s, uint8_t len);
+
   /**
    * Copy Constructor
    */
   prefix_t(const prefix_t&);
   /**
    * Copy Constructor
    */
   prefix_t(const prefix_t&);
+
   /**
    * Constructor with VPP API prefix representation
    */
   /**
    * Constructor with VPP API prefix representation
    */
index 3e27abb..d7c6d83 100644 (file)
  * limitations under the License.
  */
 
  * limitations under the License.
  */
 
-option version = "1.0.0";
+option version = "2.0.0";
+
+import "vnet/ip/ip_types.api";
+import "vnet/ethernet/ethernet_types.api";
 
 /** \brief Endpoint
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
 */
 
 
 /** \brief Endpoint
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
 */
 
-typeonly define gbp_endpoint
+typedef gbp_endpoint
 {
   u32 sw_if_index;
   u16 epg_id;
 {
   u32 sw_if_index;
   u16 epg_id;
-  u8  is_ip6;
-  u8  address[16];
-  u8  mac[6];
+  vl_api_mac_address_t mac;
+  u8 n_ips;
+  vl_api_address_t ips[n_ips];
 };
 
 };
 
-autoreply define gbp_endpoint_add_del
+define gbp_endpoint_add
 {
   u32 client_index;
   u32 context;
 {
   u32 client_index;
   u32 context;
-  u8  is_add;
   vl_api_gbp_endpoint_t endpoint;
 };
 
   vl_api_gbp_endpoint_t endpoint;
 };
 
+define gbp_endpoint_add_reply
+{
+  u32 context;
+  i32 retval;
+  u32 handle;
+};
+
+autoreply define gbp_endpoint_del
+{
+  u32 client_index;
+  u32 context;
+  u32 handle;
+};
+
 define gbp_endpoint_dump
 {
   u32 client_index;
 define gbp_endpoint_dump
 {
   u32 client_index;
@@ -111,10 +127,8 @@ typeonly define gbp_subnet
   u32 table_id;
   u32 sw_if_index;
   u16 epg_id;
   u32 table_id;
   u32 sw_if_index;
   u16 epg_id;
-  u8  is_ip6;
   u8  is_internal;
   u8  is_internal;
-  u8  address_length;
-  u8  address[16];
+  vl_api_prefix_t prefix;
 };
 
 autoreply define gbp_subnet_add_del
 };
 
 autoreply define gbp_subnet_add_del
index f487695..a541d96 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <vnet/interface.h>
 #include <vnet/api_errno.h>
 
 #include <vnet/interface.h>
 #include <vnet/api_errno.h>
+#include <vnet/ip/ip_types_api.h>
+#include <vnet/ethernet/ethernet_types_api.h>
 #include <vpp/app/version.h>
 
 #include <gbp/gbp.h>
 #include <vpp/app/version.h>
 
 #include <gbp/gbp.h>
@@ -52,7 +54,8 @@
 #include <vlibapi/api_helper_macros.h>
 
 #define foreach_gbp_api_msg                                 \
 #include <vlibapi/api_helper_macros.h>
 
 #define foreach_gbp_api_msg                                 \
-  _(GBP_ENDPOINT_ADD_DEL, gbp_endpoint_add_del)             \
+  _(GBP_ENDPOINT_ADD, gbp_endpoint_add)                     \
+  _(GBP_ENDPOINT_DEL, gbp_endpoint_del)                     \
   _(GBP_ENDPOINT_DUMP, gbp_endpoint_dump)                   \
   _(GBP_SUBNET_ADD_DEL, gbp_subnet_add_del)                 \
   _(GBP_SUBNET_DUMP, gbp_subnet_dump)                       \
   _(GBP_ENDPOINT_DUMP, gbp_endpoint_dump)                   \
   _(GBP_SUBNET_ADD_DEL, gbp_subnet_add_del)                 \
   _(GBP_SUBNET_DUMP, gbp_subnet_dump)                       \
@@ -70,39 +73,55 @@ static u16 msg_id_base;
 #define GBP_MSG_BASE msg_id_base
 
 static void
 #define GBP_MSG_BASE msg_id_base
 
 static void
-vl_api_gbp_endpoint_add_del_t_handler (vl_api_gbp_endpoint_add_del_t * mp)
+vl_api_gbp_endpoint_add_t_handler (vl_api_gbp_endpoint_add_t * mp)
 {
 {
-  vl_api_gbp_endpoint_add_del_reply_t *rmp;
-  ip46_address_t ip = { };
-  u32 sw_if_index;
-  int rv = 0;
+  vl_api_gbp_endpoint_add_reply_t *rmp;
+  u32 sw_if_index, handle;
+  ip46_address_t *ips;
+  mac_address_t mac;
+  int rv = 0, ii;
+
+  VALIDATE_SW_IF_INDEX (&(mp->endpoint));
 
   sw_if_index = ntohl (mp->endpoint.sw_if_index);
 
   sw_if_index = ntohl (mp->endpoint.sw_if_index);
-  if (!vnet_sw_if_index_is_api_valid (sw_if_index))
-    goto bad_sw_if_index;
 
 
-  if (mp->endpoint.is_ip6)
-    {
-      clib_memcpy (&ip.ip6, mp->endpoint.address, sizeof (ip.ip6));
-    }
-  else
-    {
-      clib_memcpy (&ip.ip4, mp->endpoint.address, sizeof (ip.ip4));
-    }
+  ips = NULL;
 
 
-  if (mp->is_add)
-    {
-      rv =
-       gbp_endpoint_update (sw_if_index, &ip, ntohs (mp->endpoint.epg_id));
-    }
-  else
+  if (mp->endpoint.n_ips)
     {
     {
-      gbp_endpoint_delete (sw_if_index, &ip);
+      vec_validate (ips, mp->endpoint.n_ips - 1);
+
+      vec_foreach_index (ii, ips)
+      {
+       ip_address_decode (&mp->endpoint.ips[ii], &ips[ii]);
+      }
     }
     }
+  mac_address_decode (&mp->endpoint.mac, &mac);
+
+  rv = gbp_endpoint_update (sw_if_index, ips, &mac,
+                           ntohs (mp->endpoint.epg_id), &handle);
+
+  vec_free (ips);
 
   BAD_SW_IF_INDEX_LABEL;
 
 
   BAD_SW_IF_INDEX_LABEL;
 
-  REPLY_MACRO (VL_API_GBP_ENDPOINT_ADD_DEL_REPLY + GBP_MSG_BASE);
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_GBP_ENDPOINT_ADD_REPLY + GBP_MSG_BASE,
+  ({
+    rmp->handle = htonl (handle);
+  }));
+  /* *INDENT-ON* */
+}
+
+static void
+vl_api_gbp_endpoint_del_t_handler (vl_api_gbp_endpoint_del_t * mp)
+{
+  vl_api_gbp_endpoint_del_reply_t *rmp;
+  int rv = 0;
+
+  gbp_endpoint_delete (ntohl (mp->handle));
+
+  REPLY_MACRO (VL_API_GBP_ENDPOINT_DEL_REPLY + GBP_MSG_BASE);
 }
 
 typedef struct gbp_walk_ctx_t_
 }
 
 typedef struct gbp_walk_ctx_t_
@@ -111,14 +130,16 @@ typedef struct gbp_walk_ctx_t_
   u32 context;
 } gbp_walk_ctx_t;
 
   u32 context;
 } gbp_walk_ctx_t;
 
-static int
+static walk_rc_t
 gbp_endpoint_send_details (gbp_endpoint_t * gbpe, void *args)
 {
   vl_api_gbp_endpoint_details_t *mp;
   gbp_walk_ctx_t *ctx;
 gbp_endpoint_send_details (gbp_endpoint_t * gbpe, void *args)
 {
   vl_api_gbp_endpoint_details_t *mp;
   gbp_walk_ctx_t *ctx;
+  u8 n_ips, ii;
 
   ctx = args;
 
   ctx = args;
-  mp = vl_msg_api_alloc (sizeof (*mp));
+  n_ips = vec_len (gbpe->ge_ips);
+  mp = vl_msg_api_alloc (sizeof (*mp) + (sizeof (*mp->endpoint.ips) * n_ips));
   if (!mp)
     return 1;
 
   if (!mp)
     return 1;
 
@@ -126,22 +147,20 @@ gbp_endpoint_send_details (gbp_endpoint_t * gbpe, void *args)
   mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_DETAILS + GBP_MSG_BASE);
   mp->context = ctx->context;
 
   mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_DETAILS + GBP_MSG_BASE);
   mp->context = ctx->context;
 
-  mp->endpoint.sw_if_index = ntohl (gbpe->ge_key->gek_sw_if_index);
-  mp->endpoint.is_ip6 = !ip46_address_is_ip4 (&gbpe->ge_key->gek_ip);
-  if (mp->endpoint.is_ip6)
-    clib_memcpy (&mp->endpoint.address,
-                &gbpe->ge_key->gek_ip.ip6,
-                sizeof (gbpe->ge_key->gek_ip.ip6));
-  else
-    clib_memcpy (&mp->endpoint.address,
-                &gbpe->ge_key->gek_ip.ip4,
-                sizeof (gbpe->ge_key->gek_ip.ip4));
-
+  mp->endpoint.sw_if_index = ntohl (gbpe->ge_sw_if_index);
   mp->endpoint.epg_id = ntohs (gbpe->ge_epg_id);
   mp->endpoint.epg_id = ntohs (gbpe->ge_epg_id);
+  mp->endpoint.n_ips = n_ips;
+  mac_address_encode (&gbpe->ge_mac, &mp->endpoint.mac);
+
+  vec_foreach_index (ii, gbpe->ge_ips)
+  {
+    ip_address_encode (&gbpe->ge_ips[ii], IP46_TYPE_ANY,
+                      &mp->endpoint.ips[ii]);
+  }
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
-  return (1);
+  return (WALK_CONTINUE);
 }
 
 static void
 }
 
 static void
@@ -195,18 +214,10 @@ static void
 vl_api_gbp_subnet_add_del_t_handler (vl_api_gbp_subnet_add_del_t * mp)
 {
   vl_api_gbp_subnet_add_del_reply_t *rmp;
 vl_api_gbp_subnet_add_del_t_handler (vl_api_gbp_subnet_add_del_t * mp)
 {
   vl_api_gbp_subnet_add_del_reply_t *rmp;
+  fib_prefix_t pfx;
   int rv = 0;
   int rv = 0;
-  fib_prefix_t pfx = {
-    .fp_len = mp->subnet.address_length,
-    .fp_proto = (mp->subnet.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4),
-  };
 
 
-  if (mp->subnet.is_ip6)
-    clib_memcpy (&pfx.fp_addr.ip6, mp->subnet.address,
-                sizeof (pfx.fp_addr.ip6));
-  else
-    clib_memcpy (&pfx.fp_addr.ip4, mp->subnet.address,
-                sizeof (pfx.fp_addr.ip4));
+  ip_prefix_decode (&mp->subnet.prefix, &pfx);
 
   rv = gbp_subnet_add_del (ntohl (mp->subnet.table_id),
                           &pfx,
 
   rv = gbp_subnet_add_del (ntohl (mp->subnet.table_id),
                           &pfx,
@@ -238,16 +249,8 @@ gbp_subnet_send_details (u32 table_id,
   mp->subnet.is_internal = is_internal;
   mp->subnet.sw_if_index = ntohl (sw_if_index);
   mp->subnet.epg_id = ntohs (epg);
   mp->subnet.is_internal = is_internal;
   mp->subnet.sw_if_index = ntohl (sw_if_index);
   mp->subnet.epg_id = ntohs (epg);
-  mp->subnet.is_ip6 = (pfx->fp_proto == FIB_PROTOCOL_IP6);
-  mp->subnet.address_length = pfx->fp_len;
   mp->subnet.table_id = ntohl (table_id);
   mp->subnet.table_id = ntohl (table_id);
-  if (mp->subnet.is_ip6)
-    clib_memcpy (&mp->subnet.address,
-                &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
-  else
-    clib_memcpy (&mp->subnet.address,
-                &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
-
+  ip_prefix_encode (pfx, &mp->subnet.prefix);
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
 
   vl_api_send_msg (ctx->reg, (u8 *) mp);
 
index fdb1e9f..53389f5 100644 (file)
@@ -75,6 +75,7 @@ gbp_classify_inline (vlib_main_t * vm,
       while (n_left_from > 0 && n_left_to_next > 0)
        {
          u32 next0, bi0, src_epg, sw_if_index0;
       while (n_left_from > 0 && n_left_to_next > 0)
        {
          u32 next0, bi0, src_epg, sw_if_index0;
+         const gbp_endpoint_t *gep0;
          vlib_buffer_t *b0;
 
          bi0 = from[0];
          vlib_buffer_t *b0;
 
          bi0 = from[0];
@@ -97,7 +98,8 @@ gbp_classify_inline (vlib_main_t * vm,
            }
          else
            {
            }
          else
            {
-             src_epg = gbp_port_to_epg (sw_if_index0);
+             gep0 = gbp_endpoint_get_itf (sw_if_index0);
+             src_epg = gep0->ge_epg_id;
              if (is_l3)
                {
                  /*
              if (is_l3)
                {
                  /*
index 0522f61..a261527 100644 (file)
 #include <vnet/l2/l2_output.h>
 #include <vnet/l2/feat_bitmap.h>
 
 #include <vnet/l2/l2_output.h>
 #include <vnet/l2/feat_bitmap.h>
 
-/**
- * IP4 destintion address to destination EPG mapping table
- */
-typedef struct gbp_ip4_to_epg_db_t_
-{
-  /**
-   * use a simple hash table
-   */
-  uword *g4ie_hash;
-} gbp_ip4_to_epg_db_t;
-
-static gbp_ip4_to_epg_db_t gbp_ip4_to_epg_db;
+gbp_ep_by_itf_db_t gbp_ep_by_itf_db;
+gbp_ep_by_mac_itf_db_t gbp_ep_by_mac_itf_db;
+gbp_ep_by_ip_itf_db_t gbp_ep_by_ip_itf_db;
 
 /**
 
 /**
- * IP6 destintion address to destination EPG mapping table
+ * Pool of GBP endpoints
  */
  */
-typedef struct gbp_ip6_to_epg_db_t_
+gbp_endpoint_t *gbp_endpoint_pool;
+
+/* void */
+/* gbp_itf_epg_update (u32 sw_if_index, epg_id_t src_epg, u8 do_policy) */
+/* { */
+/*   vec_validate_init_empty (gbp_itf_to_epg_db.gte_vec, */
+/*                        sw_if_index, ITF_INVALID); */
+
+/*   if (0 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count) */
+/*     { */
+/*       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY, */
+/*                               1); */
+/*       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 1); */
+/*       if (do_policy) */
+/*     l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, */
+/*                                  1); */
+/*     } */
+/*   gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = src_epg; */
+/*   gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count++; */
+/* } */
+
+/* void */
+/* gbp_itf_epg_delete (u32 sw_if_index) */
+/* { */
+/*   if (vec_len (gbp_itf_to_epg_db.gte_vec) <= sw_if_index) */
+/*     return; */
+
+/*   if (1 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count) */
+/*     { */
+/*       gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = EPG_INVALID; */
+
+/*       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY, */
+/*                               0); */
+/*       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 0); */
+/*       l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 0); */
+/*     } */
+/*   gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count--; */
+/* } */
+
+static void
+gbp_endpoint_mk_key_mac_itf (const mac_address_t * mac,
+                            u32 sw_if_index, clib_bihash_kv_16_8_t * key)
 {
 {
-  /**
-   * use a memroy hash table
-   */
-  uword *g6ie_hash;
-} gbp_ip6_to_epg_db_t;
+  key->key[0] = mac_address_as_u64 (mac);
+  key->key[1] = sw_if_index;
+}
 
 
-static gbp_ip6_to_epg_db_t gbp_ip6_to_epg_db;
+static void
+gbp_endpoint_extract_key_mac_itf (const clib_bihash_kv_16_8_t * key,
+                                 mac_address_t * mac, u32 * sw_if_index)
+{
+  mac_address_from_u64 (key->key[0], mac);
+  *sw_if_index = key->key[1];
+}
 
 
+gbp_endpoint_t *
+gbp_endpoint_find_mac_itf (const mac_address_t * mac, u32 sw_if_index)
+{
+  clib_bihash_kv_16_8_t key, value;
+  int rv;
 
 
-const static gbp_itf_t ITF_INVALID = {
-  .gi_epg = EPG_INVALID,
-  .gi_ref_count = 0,
-};
+  gbp_endpoint_mk_key_mac_itf (mac, sw_if_index, &key);
 
 
-gbp_itf_to_epg_db_t gbp_itf_to_epg_db;
+  rv =
+    clib_bihash_search_16_8 (&gbp_ep_by_mac_itf_db.gte_table, &key, &value);
 
 
-/**
- * Pool of GBP endpoints
- */
-static gbp_endpoint_t *gbp_endpoint_pool;
+  if (0 != rv)
+    return NULL;
 
 
-/**
- * DB of endpoints
- */
-static uword *gbp_endpoint_db;
+  return (gbp_endpoint_get (value.value));
+}
 
 static void
 
 static void
-gbp_ip_epg_update (const ip46_address_t * ip, epg_id_t epg_id)
+gbp_endpoint_mk_key_ip_itf (const ip46_address_t * ip,
+                           u32 sw_if_index, clib_bihash_kv_24_8_t * key)
 {
 {
-  /*
-   * we are dealing only with addresses here so this limited
-   * is_ip4 check is ok
-   */
-  if (ip46_address_is_ip4 (ip))
-    {
-      hash_set (gbp_ip4_to_epg_db.g4ie_hash, ip->ip4.as_u32, epg_id);
-    }
-  else
-    {
-      hash_set_mem (gbp_ip6_to_epg_db.g6ie_hash, &ip->ip6, epg_id);
-    }
+  key->key[0] = ip->as_u64[0];
+  key->key[1] = ip->as_u64[1];
+  key->key[2] = sw_if_index;
 }
 
 static void
 }
 
 static void
-gbp_ip_epg_delete (const ip46_address_t * ip)
+gbp_endpoint_extract_key_ip_itf (const clib_bihash_kv_24_8_t * key,
+                                ip46_address_t * ip, u32 * sw_if_index)
 {
 {
-  if (ip46_address_is_ip4 (ip))
-    {
-      hash_unset (gbp_ip4_to_epg_db.g4ie_hash, ip->ip4.as_u32);
-    }
-  else
-    {
-      hash_unset_mem (gbp_ip6_to_epg_db.g6ie_hash, &ip->ip6);
-    }
+  ip->as_u64[0] = key->key[0];
+  ip->as_u64[1] = key->key[1];
+  *sw_if_index = key->key[2];
 }
 
 }
 
-void
-gbp_itf_epg_update (u32 sw_if_index, epg_id_t src_epg, u8 do_policy)
+gbp_endpoint_t *
+gbp_endpoint_find_ip_itf (const ip46_address_t * ip, u32 sw_if_index)
 {
 {
-  vec_validate_init_empty (gbp_itf_to_epg_db.gte_vec,
-                          sw_if_index, ITF_INVALID);
+  clib_bihash_kv_24_8_t key, value;
+  int rv;
+
+  gbp_endpoint_mk_key_ip_itf (ip, sw_if_index, &key);
+
+  rv = clib_bihash_search_24_8 (&gbp_ep_by_ip_itf_db.gte_table, &key, &value);
+
+  if (0 != rv)
+    return NULL;
+
+  return (gbp_endpoint_get (value.value));
+}
+
+gbp_endpoint_t *
+gbp_endpoint_find_itf (u32 sw_if_index)
+{
+  /* if (vec_len(gbp_ep_by_itf_db.gte_vec) >= sw_if_index) */
+  /*   return NULL; */
+
+  /* vec_search(gbp_ep_by_itf_db.gte_vec[sw_if_index],  */
+  /* return (gbp_endpoint_get(gbp_ep_by_itf_db.gte_vec[sw_if_index][0])); */
+  return (NULL);
+}
+
+static bool
+gbp_endpoint_add_mac_itf (const mac_address_t * mac,
+                         u32 sw_if_index, index_t gbpei)
+{
+  clib_bihash_kv_16_8_t key;
+  int rv;
+
+  gbp_endpoint_mk_key_mac_itf (mac, sw_if_index, &key);
+  key.value = gbpei;
 
 
-  if (0 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count)
+  rv = clib_bihash_add_del_16_8 (&gbp_ep_by_mac_itf_db.gte_table, &key, 1);
+
+  return (0 == rv);
+}
+
+static bool
+gbp_endpoint_add_ip_itf (const ip46_address_t * ip,
+                        u32 sw_if_index, index_t gbpei)
+{
+  clib_bihash_kv_24_8_t key;
+  int rv;
+
+  gbp_endpoint_mk_key_ip_itf (ip, sw_if_index, &key);
+  key.value = gbpei;
+
+  rv = clib_bihash_add_del_24_8 (&gbp_ep_by_ip_itf_db.gte_table, &key, 1);
+
+  return (0 == rv);
+}
+
+static void
+gbp_endpoint_add_itf (u32 sw_if_index, index_t gbpei)
+{
+  vec_validate_init_empty (gbp_ep_by_itf_db.gte_vec, sw_if_index,
+                          INDEX_INVALID);
+
+  if (INDEX_INVALID == gbp_ep_by_itf_db.gte_vec[sw_if_index])
     {
       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY,
                                  1);
       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 1);
     {
       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY,
                                  1);
       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 1);
-      if (do_policy)
-       l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY,
-                                    1);
+      l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 1);
     }
     }
-  gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = src_epg;
-  gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count++;
+  gbp_ep_by_itf_db.gte_vec[sw_if_index] = gbpei;
 }
 
 }
 
-void
-gbp_itf_epg_delete (u32 sw_if_index)
+static void
+gbp_endpoint_del_mac_itf (const mac_address_t * mac, u32 sw_if_index)
+{
+  clib_bihash_kv_16_8_t key;
+
+  gbp_endpoint_mk_key_mac_itf (mac, sw_if_index, &key);
+
+  clib_bihash_add_del_16_8 (&gbp_ep_by_mac_itf_db.gte_table, &key, 0);
+}
+
+static void
+gbp_endpoint_del_ip_itf (const ip46_address_t * ip, u32 sw_if_index)
+{
+  clib_bihash_kv_24_8_t key;
+
+  gbp_endpoint_mk_key_ip_itf (ip, sw_if_index, &key);
+
+  clib_bihash_add_del_24_8 (&gbp_ep_by_ip_itf_db.gte_table, &key, 0);
+}
+
+static void
+gbp_endpoint_del_itf (u32 sw_if_index)
 {
 {
-  if (vec_len (gbp_itf_to_epg_db.gte_vec) <= sw_if_index)
+  if (vec_len (gbp_ep_by_itf_db.gte_vec) <= sw_if_index)
     return;
 
     return;
 
-  if (1 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count)
-    {
-      gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = EPG_INVALID;
+  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY, 0);
+  l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 0);
+  l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 0);
 
 
-      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY,
-                                 0);
-      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 0);
-      l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 0);
-    }
-  gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count--;
+  gbp_ep_by_itf_db.gte_vec[sw_if_index] = INDEX_INVALID;
+}
+
+static index_t
+gbp_endpoint_index (const gbp_endpoint_t * gbpe)
+{
+  return (gbpe - gbp_endpoint_pool);
 }
 
 int
 gbp_endpoint_update (u32 sw_if_index,
 }
 
 int
 gbp_endpoint_update (u32 sw_if_index,
-                    const ip46_address_t * ip, epg_id_t epg_id)
+                    const ip46_address_t * ips,
+                    const mac_address_t * mac, epg_id_t epg_id, u32 * handle)
 {
 {
-  gbp_endpoint_key_t key = {
-    .gek_ip = *ip,
-    .gek_sw_if_index = sw_if_index,
-  };
   gbp_endpoint_group_t *gepg;
   gbp_endpoint_group_t *gepg;
+  const ip46_address_t *ip;
   gbp_endpoint_t *gbpe;
   gbp_endpoint_t *gbpe;
-  uword *p;
 
 
+  gbpe = NULL;
   gepg = gbp_endpoint_group_find (epg_id);
 
   if (NULL == gepg)
     return (VNET_API_ERROR_NO_SUCH_ENTRY);
 
   gepg = gbp_endpoint_group_find (epg_id);
 
   if (NULL == gepg)
     return (VNET_API_ERROR_NO_SUCH_ENTRY);
 
-  p = hash_get_mem (gbp_endpoint_db, &key);
-
-  if (p)
+  /*
+   * find an existing endpoint matching one of the key types
+   */
+  if (NULL != mac)
     {
     {
-      gbpe = pool_elt_at_index (gbp_endpoint_pool, p[0]);
+      gbpe = gbp_endpoint_find_mac_itf (mac, sw_if_index);
     }
     }
-  else
+  if (NULL == gbpe && NULL != ips)
     {
     {
-      pool_get (gbp_endpoint_pool, gbpe);
-
-      gbpe->ge_key = clib_mem_alloc (sizeof (gbp_endpoint_key_t));
-      clib_memcpy (gbpe->ge_key, &key, sizeof (gbp_endpoint_key_t));
+      vec_foreach (ip, ips)
+      {
+       gbpe = gbp_endpoint_find_ip_itf (ip, sw_if_index);
 
 
-      hash_set_mem (gbp_endpoint_db, gbpe->ge_key, gbpe - gbp_endpoint_pool);
+       if (NULL != gbpe)
+         break;
+      }
+    }
+  if (NULL == gbpe)
+    {
+      gbpe = gbp_endpoint_find_itf (sw_if_index);
     }
 
     }
 
-  gbpe->ge_epg_id = epg_id;
-
-  gbp_itf_epg_update (gbpe->ge_key->gek_sw_if_index, gbpe->ge_epg_id, 1);
-
-  if (!ip46_address_is_zero (&gbpe->ge_key->gek_ip))
-    gbp_ip_epg_update (&gbpe->ge_key->gek_ip, gbpe->ge_epg_id);
-
-  /*
-   * send a gratuitous ARP on the EPG's uplink. this is done so that if
-   * this EP has moved from some other place in the 'fabric', upstream
-   * devices are informed
-   */
-  if (ip46_address_is_ip4 (&gbpe->ge_key->gek_ip))
-    send_ip4_garp_w_addr (vlib_get_main (),
-                         &gbpe->ge_key->gek_ip.ip4,
-                         gepg->gepg_uplink_sw_if_index);
+  if (NULL == gbpe)
+    {
+      index_t gbpei;
+      u32 ii;
+      /*
+       * new entry
+       */
+      pool_get (gbp_endpoint_pool, gbpe);
+      gbpei = gbp_endpoint_index (gbpe);
+
+      gbpe->ge_epg_id = epg_id;
+      gbpe->ge_sw_if_index = sw_if_index;
+      gbp_endpoint_add_itf (gbpe->ge_sw_if_index, gbpei);
+
+      if (NULL != mac)
+       {
+         gbpe->ge_mac = *mac;
+
+         // FIXME ERROR
+         gbp_endpoint_add_mac_itf (mac, sw_if_index, gbpei);
+       }
+
+      if (NULL != ips)
+       {
+         vec_validate (gbpe->ge_ips, vec_len (ips) - 1);
+         vec_foreach_index (ii, ips)
+         {
+           ip46_address_copy (&gbpe->ge_ips[ii], &ips[ii]);
+
+           // FIXME ERROR
+           gbp_endpoint_add_ip_itf (&ips[ii], sw_if_index, gbpei);
+
+           /*
+            * send a gratuitous ARP on the EPG's uplink. this is done so
+            * that if this EP has moved from some other place in the
+            * 'fabric', upstream devices are informed
+            */
+           if (ip46_address_is_ip4 (&ips[ii]))
+             send_ip4_garp_w_addr (vlib_get_main (),
+                                   &ips[ii].ip4,
+                                   gepg->gepg_uplink_sw_if_index);
+           else
+             send_ip6_na_w_addr (vlib_get_main (),
+                                 &ips[ii].ip6,
+                                 gepg->gepg_uplink_sw_if_index);
+         }
+       }
+    }
   else
   else
-    send_ip6_na_w_addr (vlib_get_main (),
-                       &gbpe->ge_key->gek_ip.ip6,
-                       gepg->gepg_uplink_sw_if_index);
+    {
+      /*
+       * update existing entry..
+       */
+      ASSERT (0);
+    }
+
+  *handle = (gbpe - gbp_endpoint_pool);
 
   return (0);
 }
 
 void
 
   return (0);
 }
 
 void
-gbp_endpoint_delete (u32 sw_if_index, const ip46_address_t * ip)
+gbp_endpoint_delete (u32 handle)
 {
 {
-  gbp_endpoint_key_t key = {
-    .gek_ip = *ip,
-    .gek_sw_if_index = sw_if_index,
-  };
   gbp_endpoint_t *gbpe;
   gbp_endpoint_t *gbpe;
-  uword *p;
 
 
-  p = hash_get_mem (gbp_endpoint_db, &key);
+  if (pool_is_free_index (gbp_endpoint_pool, handle))
+    return;
 
 
-  if (p)
-    {
-      gbpe = pool_elt_at_index (gbp_endpoint_pool, p[0]);
+  gbpe = pool_elt_at_index (gbp_endpoint_pool, handle);
 
 
-      hash_unset_mem (gbp_endpoint_db, gbpe->ge_key);
+  gbp_endpoint_del_itf (gbpe->ge_sw_if_index);
 
 
-      gbp_itf_epg_delete (gbpe->ge_key->gek_sw_if_index);
-      if (!ip46_address_is_zero (&gbpe->ge_key->gek_ip))
-       gbp_ip_epg_delete (&gbpe->ge_key->gek_ip);
+  if (!mac_address_is_zero (&gbpe->ge_mac))
+    {
+      gbp_endpoint_del_mac_itf (&gbpe->ge_mac, gbpe->ge_sw_if_index);
+    }
 
 
-      clib_mem_free (gbpe->ge_key);
+  if (NULL != gbpe->ge_ips)
+    {
+      const ip46_address_t *ip;
 
 
-      pool_put (gbp_endpoint_pool, gbpe);
+      vec_foreach (ip, gbpe->ge_ips)
+      {
+       gbp_endpoint_del_ip_itf (ip, gbpe->ge_sw_if_index);
+      }
     }
     }
+  pool_put (gbp_endpoint_pool, gbpe);
 }
 
 void
 }
 
 void
@@ -237,14 +377,19 @@ static clib_error_t *
 gbp_endpoint_cli (vlib_main_t * vm,
                  unformat_input_t * input, vlib_cli_command_t * cmd)
 {
 gbp_endpoint_cli (vlib_main_t * vm,
                  unformat_input_t * input, vlib_cli_command_t * cmd)
 {
+  ip46_address_t ip = ip46_address_initializer, *ips = NULL;
+  mac_address_t mac = ZERO_MAC_ADDRESS;
   vnet_main_t *vnm = vnet_get_main ();
   epg_id_t epg_id = EPG_INVALID;
   vnet_main_t *vnm = vnet_get_main ();
   epg_id_t epg_id = EPG_INVALID;
-  ip46_address_t ip = { };
+  u32 handle = INDEX_INVALID;
   u32 sw_if_index = ~0;
   u8 add = 1;
   u32 sw_if_index = ~0;
   u8 add = 1;
+  int rv;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
+      ip46_address_reset (&ip);
+
       if (unformat (input, "%U", unformat_vnet_sw_interface,
                    vnm, &sw_if_index))
        ;
       if (unformat (input, "%U", unformat_vnet_sw_interface,
                    vnm, &sw_if_index))
        ;
@@ -254,25 +399,41 @@ gbp_endpoint_cli (vlib_main_t * vm,
        add = 0;
       else if (unformat (input, "epg %d", &epg_id))
        ;
        add = 0;
       else if (unformat (input, "epg %d", &epg_id))
        ;
-      else if (unformat (input, "ip %U", unformat_ip4_address, &ip.ip4))
+      else if (unformat (input, "handle %d", &handle))
        ;
        ;
+      else if (unformat (input, "ip %U", unformat_ip4_address, &ip.ip4))
+       vec_add1 (ips, ip);
       else if (unformat (input, "ip %U", unformat_ip6_address, &ip.ip6))
       else if (unformat (input, "ip %U", unformat_ip6_address, &ip.ip6))
+       vec_add1 (ips, ip);
+      else if (unformat (input, "mac %U", unformat_mac_address, &mac))
        ;
       else
        break;
     }
 
        ;
       else
        break;
     }
 
-  if (~0 == sw_if_index)
-    return clib_error_return (0, "interface must be specified");
-  if (EPG_INVALID == epg_id)
-    return clib_error_return (0, "EPG-ID must be specified");
-  if (ip46_address_is_zero (&ip))
-    return clib_error_return (0, "IP address must be specified");
-
   if (add)
   if (add)
-    gbp_endpoint_update (sw_if_index, &ip, epg_id);
+    {
+      if (~0 == sw_if_index)
+       return clib_error_return (0, "interface must be specified");
+      if (EPG_INVALID == epg_id)
+       return clib_error_return (0, "EPG-ID must be specified");
+
+      rv = gbp_endpoint_update (sw_if_index, ips, &mac, epg_id, &handle);
+
+      if (rv)
+       return clib_error_return (0, "GBP Endpoint update returned %d", rv);
+      else
+       vlib_cli_output (vm, "handle %d\n", handle);
+    }
   else
   else
-    gbp_endpoint_delete (sw_if_index, &ip);
+    {
+      if (INDEX_INVALID == handle)
+       return clib_error_return (0, "handle must be specified");
+
+      gbp_endpoint_delete (handle);
+    }
+
+  vec_free (ips);
 
   return (NULL);
 }
 
   return (NULL);
 }
@@ -288,75 +449,132 @@ gbp_endpoint_cli (vlib_main_t * vm,
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
   .path = "gbp endpoint",
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
   .path = "gbp endpoint",
-  .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP>",
+  .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP> mac <MAC>",
   .function = gbp_endpoint_cli,
 };
 /* *INDENT-ON* */
 
   .function = gbp_endpoint_cli,
 };
 /* *INDENT-ON* */
 
-static int
-gbp_endpoint_show_one (gbp_endpoint_t * gbpe, void *ctx)
+u8 *
+format_gbp_endpoint (u8 * s, va_list * args)
 {
 {
+  index_t gbpei = va_arg (*args, index_t);
   vnet_main_t *vnm = vnet_get_main ();
   vnet_main_t *vnm = vnet_get_main ();
+  const ip46_address_t *ip;
+  gbp_endpoint_t *gbpe;
+
+  gbpe = gbp_endpoint_get (gbpei);
+
+  s = format (s, "[@%d] ", gbpei);
+  s =
+    format (s, "%U", format_vnet_sw_if_index_name, vnm, gbpe->ge_sw_if_index);
+  s = format (s, ", IPs:[");
+
+  vec_foreach (ip, gbpe->ge_ips)
+  {
+    s = format (s, "%U, ", format_ip46_address, ip, IP46_TYPE_ANY);
+  }
+  s = format (s, "]");
+
+  s = format (s, " MAC:%U", format_mac_address_t, &gbpe->ge_mac);
+  s = format (s, " EPG-ID:%d", gbpe->ge_epg_id);
+
+  return s;
+}
+
+static walk_rc_t
+gbp_endpoint_show_one (gbp_endpoint_t * gbpe, void *ctx)
+{
   vlib_main_t *vm;
 
   vm = ctx;
   vlib_main_t *vm;
 
   vm = ctx;
-  vlib_cli_output (vm, "  {%U, %U} -> %d",
-                  format_vnet_sw_if_index_name, vnm,
-                  gbpe->ge_key->gek_sw_if_index,
-                  format_ip46_address, &gbpe->ge_key->gek_ip, IP46_TYPE_ANY,
-                  gbpe->ge_epg_id);
+  vlib_cli_output (vm, " %U", format_gbp_endpoint, gbp_endpoint_index (gbpe));
 
 
-  return (1);
+  return (WALK_CONTINUE);
 }
 
 }
 
-static clib_error_t *
-gbp_endpoint_show (vlib_main_t * vm,
-                  unformat_input_t * input, vlib_cli_command_t * cmd)
+static void
+gbp_endpoint_walk_ip_itf (const clib_bihash_kv_24_8_t * kvp, void *arg)
 {
 {
-  vnet_main_t *vnm = vnet_get_main ();
-  ip46_address_t ip, *ipp;
-  epg_id_t epg_id;
+  ip46_address_t ip;
+  vlib_main_t *vm;
   u32 sw_if_index;
 
   u32 sw_if_index;
 
-  vlib_cli_output (vm, "Endpoints:");
-  gbp_endpoint_walk (gbp_endpoint_show_one, vm);
+  vm = arg;
 
 
-  vlib_cli_output (vm, "\nSource interface to EPG:");
+  gbp_endpoint_extract_key_ip_itf (kvp, &ip, &sw_if_index);
 
 
-  vec_foreach_index (sw_if_index, gbp_itf_to_epg_db.gte_vec)
-  {
-    if (EPG_INVALID != gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg)
-      {
-       vlib_cli_output (vm, "  %U -> %d",
-                        format_vnet_sw_if_index_name, vnm, sw_if_index,
-                        gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg);
-      }
-  }
+  vlib_cli_output (vm, " {%U, %U} -> %d",
+                  format_ip46_address, &ip, IP46_TYPE_ANY,
+                  format_vnet_sw_if_index_name, vnet_get_main (),
+                  sw_if_index, kvp->value);
+}
 
 
-  vlib_cli_output (vm, "\nDestination IP4 to EPG:");
+static void
+gbp_endpoint_walk_mac_itf (const clib_bihash_kv_16_8_t * kvp, void *arg)
+{
+  mac_address_t mac;
+  vlib_main_t *vm;
+  u32 sw_if_index;
 
 
-  /* *INDENT-OFF* */
-  hash_foreach (ip.ip4.as_u32, epg_id, gbp_ip4_to_epg_db.g4ie_hash,
-  {
-    vlib_cli_output (vm, "  %U -> %d", format_ip46_address, &ip,
-                     IP46_TYPE_IP4, epg_id);
-  });
-  /* *INDENT-ON* */
+  vm = arg;
 
 
-  vlib_cli_output (vm, "\nDestination IP6 to EPG:");
+  gbp_endpoint_extract_key_mac_itf (kvp, &mac, &sw_if_index);
 
 
-  /* *INDENT-OFF* */
-  hash_foreach_mem (ipp, epg_id, gbp_ip6_to_epg_db.g6ie_hash,
-  {
-    vlib_cli_output (vm, "  %U -> %d", format_ip46_address, ipp,
-                     IP46_TYPE_IP6, epg_id);
-  });
-  /* *INDENT-ON* */
+  vlib_cli_output (vm, " {%U, %U} -> %d",
+                  format_mac_address_t, &mac,
+                  format_vnet_sw_if_index_name, vnet_get_main (),
+                  sw_if_index, kvp->value);
+}
+
+static clib_error_t *
+gbp_endpoint_show (vlib_main_t * vm,
+                  unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  u32 sw_if_index, show_dbs, handle;
+
+  handle = INDEX_INVALID;
+  show_dbs = 0;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "%d", &handle))
+       ;
+      else if (unformat (input, "db", &handle))
+       show_dbs = 1;
+      else
+       break;
+    }
+
+  if (INDEX_INVALID != handle)
+    {
+      vlib_cli_output (vm, "%U", format_gbp_endpoint, handle);
+    }
+  else if (show_dbs)
+    {
+      vlib_cli_output (vm, "\nDatabases:");
+      clib_bihash_foreach_key_value_pair_24_8 (&gbp_ep_by_ip_itf_db.gte_table,
+                                              gbp_endpoint_walk_ip_itf, vm);
+      clib_bihash_foreach_key_value_pair_16_8
+       (&gbp_ep_by_mac_itf_db.gte_table, gbp_endpoint_walk_mac_itf, vm);
+
+      vec_foreach_index (sw_if_index, gbp_ep_by_itf_db.gte_vec)
+      {
+       if (INDEX_INVALID != gbp_ep_by_itf_db.gte_vec[sw_if_index])
+         vlib_cli_output (vm, " {%U} -> %d",
+                          format_vnet_sw_if_index_name, vnet_get_main (),
+                          sw_if_index,
+                          gbp_ep_by_itf_db.gte_vec[sw_if_index]);
+      }
+    }
+  else
+    {
+      vlib_cli_output (vm, "Endpoints:");
+      gbp_endpoint_walk (gbp_endpoint_show_one, vm);
+    }
 
   return (NULL);
 }
 
 
   return (NULL);
 }
 
-
 /*?
  * Show Group Based Policy Endpoints and derived information
  *
 /*?
  * Show Group Based Policy Endpoints and derived information
  *
@@ -372,15 +590,21 @@ VLIB_CLI_COMMAND (gbp_endpoint_show_node, static) = {
 };
 /* *INDENT-ON* */
 
 };
 /* *INDENT-ON* */
 
+#define GBP_EP_HASH_NUM_BUCKETS (2 * 1024)
+#define GBP_EP_HASH_MEMORY_SIZE (1 << 20)
+
 static clib_error_t *
 gbp_endpoint_init (vlib_main_t * vm)
 {
 static clib_error_t *
 gbp_endpoint_init (vlib_main_t * vm)
 {
-  gbp_endpoint_db = hash_create_mem (0,
-                                    sizeof (gbp_endpoint_key_t),
-                                    sizeof (u32));
-  gbp_ip6_to_epg_db.g6ie_hash =
-    hash_create_mem (0, sizeof (ip6_address_t), sizeof (u32));
-  return 0;
+  clib_bihash_init_24_8 (&gbp_ep_by_ip_itf_db.gte_table,
+                        "GBP Endpoints - IP/Interface",
+                        GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
+
+  clib_bihash_init_16_8 (&gbp_ep_by_mac_itf_db.gte_table,
+                        "GBP Endpoints - MAC/Interface",
+                        GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
+
+  return (NULL);
 }
 
 VLIB_INIT_FUNCTION (gbp_endpoint_init);
 }
 
 VLIB_INIT_FUNCTION (gbp_endpoint_init);
index 000c211..275897d 100644 (file)
 
 #include <plugins/gbp/gbp_types.h>
 #include <vnet/ip/ip.h>
 
 #include <plugins/gbp/gbp_types.h>
 #include <vnet/ip/ip.h>
+#include <vnet/ethernet/mac_address.h>
+
+#include <vppinfra/bihash_16_8.h>
+#include <vppinfra/bihash_template.h>
+#include <vppinfra/bihash_24_8.h>
+#include <vppinfra/bihash_template.h>
 
 /**
 
 /**
- * The key for an Endpoint
+ * Flags for each endpoint
  */
  */
-typedef struct gbp_endpoint_key_t_
+typedef enum gbp_endpoint_flags_t_
+{
+  GBP_ENDPOINT_FLAG_NONE = 0,
+  GBP_ENDPOINT_FLAG_BOUNCE = (1 << 0),
+  GBP_ENDPOINT_FLAG_DYNAMIC = (1 << 1),
+} gbp_endpoint_flags_t;
+
+/**
+ * A Group Based Policy Endpoint.
+ * This is typcially a VM or container. If the endpoint is local (i.e. on
+ * the smae compute node as VPP) then there is one interface per-endpoint.
+ * If the EP is remote,e.g. reachable onver a [vxlan] tunnel, then there
+ * will be multiple EPs reachable over the tunnel and they can be distingusihed
+ * via either their MAC or IP Address[es].
+ */
+typedef struct gbp_endpoint_t_
 {
   /**
    * The interface on which the EP is connected
    */
 {
   /**
    * The interface on which the EP is connected
    */
-  u32 gek_sw_if_index;
+  u32 ge_sw_if_index;
 
   /**
 
   /**
-   * The IP[46] address of the endpoint
+   * A vector of ip addresses that below to the endpoint
    */
    */
-  ip46_address_t gek_ip;
-} gbp_endpoint_key_t;
+  ip46_address_t *ge_ips;
 
 
-/**
- * A Group Based Policy Endpoint.
- * This is typcially a VM on the local compute node for which policy must be
- * locally applied
- */
-typedef struct gbp_endpoint_t_
-{
   /**
   /**
-   * The endpoint's interface and IP address
+   * MAC address of the endpoint
    */
    */
-  gbp_endpoint_key_t *ge_key;
+  mac_address_t ge_mac;
 
   /**
    * The endpoint's designated EPG
    */
   epg_id_t ge_epg_id;
 
   /**
    * The endpoint's designated EPG
    */
   epg_id_t ge_epg_id;
+
+  /**
+   * Endpoint flags
+   */
+  gbp_endpoint_flags_t ge_flags;
 } gbp_endpoint_t;
 
 } gbp_endpoint_t;
 
-/**
- * Result of a interface to EPG mapping.
- * multiple Endpoints can occur on the same interface, so this
- * mapping needs to be reference counted.
- */
-typedef struct gbp_itf_t_
-{
-  epg_id_t gi_epg;
-  u32 gi_ref_count;
-} gbp_itf_t;
+extern u8 *format_gbp_endpoint (u8 * s, va_list * args);
 
 /**
  * Interface to source EPG DB - a per-interface vector
  */
 
 /**
  * Interface to source EPG DB - a per-interface vector
  */
-typedef struct gbp_itf_to_epg_db_t_
+typedef struct gbp_ep_by_itf_db_t_
 {
 {
-  gbp_itf_t *gte_vec;
-} gbp_itf_to_epg_db_t;
+  index_t *gte_vec;
+} gbp_ep_by_itf_db_t;
+
+typedef struct gbp_ep_by_ip_itf_db_t_
+{
+  clib_bihash_24_8_t gte_table;
+} gbp_ep_by_ip_itf_db_t;
+
+typedef struct gbp_ep_by_mac_itf_db_t_
+{
+  clib_bihash_16_8_t gte_table;
+} gbp_ep_by_mac_itf_db_t;
 
 extern int gbp_endpoint_update (u32 sw_if_index,
 
 extern int gbp_endpoint_update (u32 sw_if_index,
-                               const ip46_address_t * ip, epg_id_t epg_id);
-extern void gbp_endpoint_delete (u32 sw_if_index, const ip46_address_t * ip);
+                               const ip46_address_t * ip,
+                               const mac_address_t * mac,
+                               epg_id_t epg_id, u32 * handle);
+extern void gbp_endpoint_delete (u32 handle);
 
 
-typedef int (*gbp_endpoint_cb_t) (gbp_endpoint_t * gbpe, void *ctx);
+typedef walk_rc_t (*gbp_endpoint_cb_t) (gbp_endpoint_t * gbpe, void *ctx);
 extern void gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx);
 
 extern void gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx);
 
-/**
- * Port to EPG mapping management
- */
-extern void gbp_itf_epg_update (u32 sw_if_index, epg_id_t src_epg,
-                               u8 do_policy);
-extern void gbp_itf_epg_delete (u32 sw_if_index);
 
 /**
  * DP functions and databases
  */
 
 /**
  * DP functions and databases
  */
-extern gbp_itf_to_epg_db_t gbp_itf_to_epg_db;
+extern gbp_ep_by_itf_db_t gbp_ep_by_itf_db;
+extern gbp_ep_by_mac_itf_db_t gbp_ep_by_mac_itf_db;
+extern gbp_ep_by_ip_itf_db_t gbp_ep_by_ip_itf_db;
+extern gbp_endpoint_t *gbp_endpoint_pool;
 
 /**
 
 /**
- * Get the source EPG for a port/interface
+ * Get the endpoint from a port/interface
  */
  */
-always_inline u32
-gbp_port_to_epg (u32 sw_if_index)
+always_inline gbp_endpoint_t *
+gbp_endpoint_get (index_t gbpei)
+{
+  return (pool_elt_at_index (gbp_endpoint_pool, gbpei));
+}
+
+always_inline gbp_endpoint_t *
+gbp_endpoint_get_itf (u32 sw_if_index)
 {
 {
-  return (gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg);
+  return (gbp_endpoint_get (gbp_ep_by_itf_db.gte_vec[sw_if_index]));
 }
 
 #endif
 }
 
 #endif
index c5c0666..27d404e 100644 (file)
@@ -209,7 +209,7 @@ gbp_endpoint_group_cli (vlib_main_t * vm,
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (gbp_endpoint_group_cli_node, static) = {
   .path = "gbp endpoint-group",
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (gbp_endpoint_group_cli_node, static) = {
   .path = "gbp endpoint-group",
-  .short_help = "gbp endpoint-group [del] epg <ID> bd <ID> <interface>",
+  .short_help = "gbp endpoint-group [del] epg <ID> bd <ID> rd <ID> <interface>",
   .function = gbp_endpoint_group_cli,
 };
 
   .function = gbp_endpoint_group_cli,
 };
 
index c0a8866..f57aa07 100644 (file)
@@ -85,6 +85,7 @@ gbp_policy (vlib_main_t * vm,
 
       while (n_left_from > 0 && n_left_to_next > 0)
        {
 
       while (n_left_from > 0 && n_left_to_next > 0)
        {
+         const gbp_endpoint_t *gep0;
          gbp_policy_next_t next0;
          gbp_contract_key_t key0;
          gbp_contract_value_t value0 = {
          gbp_policy_next_t next0;
          gbp_contract_key_t key0;
          gbp_contract_value_t value0 = {
@@ -107,7 +108,8 @@ gbp_policy (vlib_main_t * vm,
           * determine the src and dst EPG
           */
          sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
           * determine the src and dst EPG
           */
          sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
-         key0.gck_dst = gbp_port_to_epg (sw_if_index0);
+         gep0 = gbp_endpoint_get_itf (sw_if_index0);
+         key0.gck_dst = gep0->ge_epg_id;
          key0.gck_src = vnet_buffer2 (b0)->gbp.src_epg;
 
          if (EPG_INVALID != key0.gck_src)
          key0.gck_src = vnet_buffer2 (b0)->gbp.src_epg;
 
          if (EPG_INVALID != key0.gck_src)
index 1debbe4..c44fc21 100644 (file)
@@ -85,7 +85,8 @@ gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext)
           * the external EPG, these are classified to the NAT EPG
           * based on its port
           */
           * the external EPG, these are classified to the NAT EPG
           * based on its port
           */
-         gbp_itf_epg_update (gr->gr_sw_if_index, gr->gr_epg, 0);
+         gbp_endpoint_update (gr->gr_sw_if_index,
+                              NULL, NULL, gr->gr_epg, &gr->gr_ep);
          vnet_feature_enable_disable ("ip4-unicast",
                                       "ip4-gbp-src-classify",
                                       gr->gr_sw_if_index, 1, 0, 0);
          vnet_feature_enable_disable ("ip4-unicast",
                                       "ip4-gbp-src-classify",
                                       gr->gr_sw_if_index, 1, 0, 0);
@@ -128,7 +129,7 @@ gbp_recirc_delete (u32 sw_if_index)
 
       if (gr->gr_is_ext)
        {
 
       if (gr->gr_is_ext)
        {
-         gbp_itf_epg_delete (gr->gr_sw_if_index);
+         gbp_endpoint_delete (gr->gr_ep);
          vnet_feature_enable_disable ("ip4-unicast",
                                       "ip4-gbp-src-classify",
                                       gr->gr_sw_if_index, 0, 0, 0);
          vnet_feature_enable_disable ("ip4-unicast",
                                       "ip4-gbp-src-classify",
                                       gr->gr_sw_if_index, 0, 0, 0);
index 10f3da6..04a2378 100644 (file)
@@ -44,6 +44,10 @@ typedef struct gpb_recirc_t_
    */
   u32 gr_sw_if_index;
 
    */
   u32 gr_sw_if_index;
 
+  /**
+   * The endpoint created to represent the reric interface
+   */
+  index_t gr_ep;
 } gbp_recirc_t;
 
 extern int gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext);
 } gbp_recirc_t;
 
 extern int gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext);
index b1c9be4..6207400 100644 (file)
@@ -93,6 +93,13 @@ typedef CLIB_PACKED (union {
 #define ip46_address_is_zero(ip46)     (((ip46)->as_u64[0] == 0) && ((ip46)->as_u64[1] == 0))
 #define ip46_address_is_equal(a1, a2)  (((a1)->as_u64[0] == (a2)->as_u64[0]) \
                                          && ((a1)->as_u64[1] == (a2)->as_u64[1]))
 #define ip46_address_is_zero(ip46)     (((ip46)->as_u64[0] == 0) && ((ip46)->as_u64[1] == 0))
 #define ip46_address_is_equal(a1, a2)  (((a1)->as_u64[0] == (a2)->as_u64[0]) \
                                          && ((a1)->as_u64[1] == (a2)->as_u64[1]))
+static_always_inline void
+ip46_address_copy (ip46_address_t * dst, const ip46_address_t * src)
+{
+  dst->as_u64[0] = src->as_u64[0];
+  dst->as_u64[1] = src->as_u64[1];
+}
+
 #define ip46_address_initializer {{{ 0 }}}
 
 always_inline ip46_address_t
 #define ip46_address_initializer {{{ 0 }}}
 
 always_inline ip46_address_t
index ce53e53..fb30fc3 100644 (file)
@@ -2,7 +2,8 @@
 
 from framework import VppTestCase, VppTestRunner
 from vpp_udp_encap import *
 
 from framework import VppTestCase, VppTestRunner
 from vpp_udp_encap import *
-from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, DpoProto
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP
index b3ac635..f14ff71 100644 (file)
@@ -20,7 +20,8 @@ from vpp_pg_interface import CaptureTimeoutError, is_ipv6_misc
 from vpp_lo_interface import VppLoInterface
 from util import ppp
 from vpp_papi_provider import UnexpectedApiReturnValueError
 from vpp_lo_interface import VppLoInterface
 from util import ppp
 from vpp_papi_provider import UnexpectedApiReturnValueError
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath
 
 USEC_IN_SEC = 1000000
 
 
 USEC_IN_SEC = 1000000
 
index c4f64bd..0276f95 100644 (file)
@@ -4,9 +4,10 @@ import unittest
 import socket
 
 from framework import VppTestCase, VppTestRunner, running_extended_tests
 import socket
 
 from framework import VppTestCase, VppTestRunner, running_extended_tests
+from vpp_ip import DpoProto
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
     VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
     VppMplsTable, VppIpMRoute, VppMRoutePath, VppIpTable, \
-    MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, DpoProto, \
+    MRouteEntryFlags, MRouteItfFlags, MPLS_LABEL_INVALID, \
     VppMplsLabel
 from vpp_bier import *
 from vpp_udp_encap import *
     VppMplsLabel
 from vpp_bier import *
 from vpp_udp_encap import *
index 894690b..0d5dd15 100644 (file)
@@ -5,7 +5,10 @@ import unittest
 from framework import VppTestCase, VppTestRunner
 from vpp_object import VppObject
 from vpp_neighbor import VppNeighbor
 from framework import VppTestCase, VppTestRunner
 from vpp_object import VppObject
 from vpp_neighbor import VppNeighbor
-from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
+
+from vpp_ip import *
+from vpp_mac import *
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP
@@ -19,6 +22,19 @@ from scapy.utils import inet_pton, inet_ntop
 from util import mactobinary
 
 
 from util import mactobinary
 
 
+def find_gbp_endpoint(test, sw_if_index, ip=None, mac=None):
+    vip = VppIpAddress(ip)
+
+    eps = test.vapi.gbp_endpoint_dump()
+    for ep in eps:
+        if ep.endpoint.sw_if_index != sw_if_index:
+            continue
+        for eip in ep.endpoint.ips:
+            if vip == eip:
+                return True
+    return False
+
+
 class VppGbpEndpoint(VppObject):
     """
     GBP Endpoint
 class VppGbpEndpoint(VppObject):
     """
     GBP Endpoint
@@ -32,64 +48,67 @@ class VppGbpEndpoint(VppObject):
     def mac(self):
         return self.itf.remote_mac
 
     def mac(self):
         return self.itf.remote_mac
 
-    def __init__(self, test, itf, epg, recirc, ip, fip, is_ip6=False):
+    @property
+    def ip4(self):
+        return self._ip4
+
+    @property
+    def fip4(self):
+        return self._fip4
+
+    @property
+    def ip6(self):
+        return self._ip6
+
+    @property
+    def fip6(self):
+        return self._fip6
+
+    @property
+    def ips(self):
+        return [self.ip4, self.ip6]
+
+    @property
+    def fips(self):
+        return [self.fip4, self.fip6]
+
+    def __init__(self, test, itf, epg, recirc, ip4, fip4, ip6, fip6):
         self._test = test
         self.itf = itf
         self.epg = epg
         self.recirc = recirc
         self._test = test
         self.itf = itf
         self.epg = epg
         self.recirc = recirc
-        self.ip = ip
-        self.floating_ip = fip
-        self.is_ip6 = is_ip6
-        if is_ip6:
-            self.proto = DpoProto.DPO_PROTO_IP6
-            self.af = AF_INET6
-            self.is_ip6 = True
-            self.ip_len = 128
-        else:
-            self.proto = DpoProto.DPO_PROTO_IP4
-            self.af = AF_INET
-            self.is_ip6 = False
-            self.ip_len = 32
-        self.ip_n = inet_pton(self.af, ip)
-        self.floating_ip_n = inet_pton(self.af, fip)
+
+        self._ip4 = VppIpAddress(ip4)
+        self._fip4 = VppIpAddress(fip4)
+        self._ip6 = VppIpAddress(ip6)
+        self._fip6 = VppIpAddress(fip6)
+
+        self.vmac = VppMacAddress(self.itf.remote_mac)
 
     def add_vpp_config(self):
 
     def add_vpp_config(self):
-        self._test.vapi.gbp_endpoint_add_del(
-            1,
+        res = self._test.vapi.gbp_endpoint_add(
             self.itf.sw_if_index,
             self.itf.sw_if_index,
-            self.ip_n,
-            self.is_ip6,
+            [self.ip4.encode(), self.ip6.encode()],
+            self.vmac.encode(),
             self.epg.epg)
             self.epg.epg)
+        self.handle = res.handle
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
-        self._test.vapi.gbp_endpoint_add_del(
-            0,
-            self.itf.sw_if_index,
-            self.ip_n,
-            self.is_ip6,
-            self.epg.epg)
+        self._test.vapi.gbp_endpoint_del(self.handle)
 
     def __str__(self):
         return self.object_id()
 
     def object_id(self):
         return "gbp-endpoint;[%d:%s:%d]" % (self.itf.sw_if_index,
 
     def __str__(self):
         return self.object_id()
 
     def object_id(self):
         return "gbp-endpoint;[%d:%s:%d]" % (self.itf.sw_if_index,
-                                            self.ip,
+                                            self.ip4.address,
                                             self.epg.epg)
 
     def query_vpp_config(self):
                                             self.epg.epg)
 
     def query_vpp_config(self):
-        eps = self._test.vapi.gbp_endpoint_dump()
-        for ep in eps:
-            if self.is_ip6:
-                if ep.endpoint.address == self.ip_n \
-                   and ep.endpoint.sw_if_index == self.itf.sw_if_index:
-                    return True
-            else:
-                if ep.endpoint.address[:4] == self.ip_n \
-                   and ep.endpoint.sw_if_index == self.itf.sw_if_index:
-                    return True
-        return False
+        return find_gbp_endpoint(self._test,
+                                 self.itf.sw_if_index,
+                                 self.ip4.address)
 
 
 class VppGbpRecirc(VppObject):
 
 
 class VppGbpRecirc(VppObject):
@@ -138,17 +157,11 @@ class VppGbpSubnet(VppObject):
     """
 
     def __init__(self, test, table_id, address, address_len,
     """
 
     def __init__(self, test, table_id, address, address_len,
-                 is_internal=True, is_ip6=False,
+                 is_internal=True,
                  sw_if_index=None, epg=None):
         self._test = test
         self.table_id = table_id
                  sw_if_index=None, epg=None):
         self._test = test
         self.table_id = table_id
-        self.address = address
-        self.address_len = address_len
-        self.is_ip6 = is_ip6
-        if is_ip6:
-            self.address_n = inet_pton(AF_INET6, address)
-        else:
-            self.address_n = inet_pton(AF_INET, address)
+        self.prefix = VppIpPrefix(address, address_len)
         self.is_internal = is_internal
         self.sw_if_index = sw_if_index
         self.epg = epg
         self.is_internal = is_internal
         self.sw_if_index = sw_if_index
         self.epg = epg
@@ -158,11 +171,9 @@ class VppGbpSubnet(VppObject):
             1,
             self.table_id,
             self.is_internal,
             1,
             self.table_id,
             self.is_internal,
-            self.address_n,
-            self.address_len,
+            self.prefix.encode(),
             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
             sw_if_index=self.sw_if_index if self.sw_if_index else 0xffffffff,
-            epg_id=self.epg if self.epg else 0xffff,
-            is_ip6=self.is_ip6)
+            epg_id=self.epg if self.epg else 0xffff)
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
@@ -170,30 +181,21 @@ class VppGbpSubnet(VppObject):
             0,
             self.table_id,
             self.is_internal,
             0,
             self.table_id,
             self.is_internal,
-            self.address_n,
-            self.address_len,
-            is_ip6=self.is_ip6)
+            self.prefix.encode())
 
     def __str__(self):
         return self.object_id()
 
     def object_id(self):
 
     def __str__(self):
         return self.object_id()
 
     def object_id(self):
-        return "gbp-subnet;[%d:%s/%d]" % (self.table_id,
-                                          self.address,
-                                          self.address_len)
+        return "gbp-subnet;[%d-%s]" % (self.table_id,
+                                       self.prefix)
 
     def query_vpp_config(self):
         ss = self._test.vapi.gbp_subnet_dump()
         for s in ss:
             if s.subnet.table_id == self.table_id and \
 
     def query_vpp_config(self):
         ss = self._test.vapi.gbp_subnet_dump()
         for s in ss:
             if s.subnet.table_id == self.table_id and \
-               s.subnet.address_length == self.address_len and \
-               s.subnet.is_ip6 == self.is_ip6:
-                if self.is_ip6:
-                    if s.subnet.address == self.address_n:
-                        return True
-                else:
-                    if s.subnet.address[:4] == self.address_n:
-                        return True
+               s.subnet.prefix == self.prefix:
+                return True
         return False
 
 
         return False
 
 
@@ -481,43 +483,38 @@ class TestGBP(VppTestCase):
 
         #
         # 3 EPGs, 2 of which share a BD.
 
         #
         # 3 EPGs, 2 of which share a BD.
-        #
-        epgs = []
-        recircs = []
-        epgs.append(VppGbpEndpointGroup(self, 220, 0, 1, self.pg4,
-                                        self.loop0,
-                                        "10.0.0.128",
-                                        "2001:10::128"))
-        recircs.append(VppGbpRecirc(self, epgs[0],
-                                    self.loop3))
-        epgs.append(VppGbpEndpointGroup(self, 221, 0, 1, self.pg5,
-                                        self.loop0,
-                                        "10.0.1.128",
-                                        "2001:10:1::128"))
-        recircs.append(VppGbpRecirc(self, epgs[1],
-                                    self.loop4))
-        epgs.append(VppGbpEndpointGroup(self, 222, 0, 2, self.pg6,
-                                        self.loop1,
-                                        "10.0.2.128",
-                                        "2001:10:2::128"))
-        recircs.append(VppGbpRecirc(self, epgs[2],
-                                    self.loop5))
-
-        #
         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
         #
         # 2 NAT EPGs, one for floating-IP subnets, the other for internet
         #
-        epgs.append(VppGbpEndpointGroup(self, 333, 20, 20, self.pg7,
-                                        self.loop2,
-                                        "11.0.0.128",
-                                        "3001::128"))
-        recircs.append(VppGbpRecirc(self, epgs[3],
-                                    self.loop6, is_ext=True))
-        epgs.append(VppGbpEndpointGroup(self, 444, 20, 20, self.pg8,
-                                        self.loop2,
-                                        "11.0.0.129",
-                                        "3001::129"))
-        recircs.append(VppGbpRecirc(self, epgs[4],
-                                    self.loop8, is_ext=True))
+        epgs = [VppGbpEndpointGroup(self, 220, 0, 1, self.pg4,
+                                    self.loop0,
+                                    "10.0.0.128",
+                                    "2001:10::128"),
+                VppGbpEndpointGroup(self, 221, 0, 1, self.pg5,
+                                    self.loop0,
+                                    "10.0.1.128",
+                                    "2001:10:1::128"),
+                VppGbpEndpointGroup(self, 222, 0, 2, self.pg6,
+                                    self.loop1,
+                                    "10.0.2.128",
+                                    "2001:10:2::128"),
+                VppGbpEndpointGroup(self, 333, 20, 20, self.pg7,
+                                    self.loop2,
+                                    "11.0.0.128",
+                                    "3001::128"),
+                VppGbpEndpointGroup(self, 444, 20, 20, self.pg8,
+                                    self.loop2,
+                                    "11.0.0.129",
+                                    "3001::129")]
+        recircs = [VppGbpRecirc(self, epgs[0],
+                                self.loop3),
+                   VppGbpRecirc(self, epgs[1],
+                                self.loop4),
+                   VppGbpRecirc(self, epgs[2],
+                                self.loop5),
+                   VppGbpRecirc(self, epgs[3],
+                                self.loop6, is_ext=True),
+                   VppGbpRecirc(self, epgs[4],
+                                self.loop8, is_ext=True)]
 
         epg_nat = epgs[3]
         recirc_nat = recircs[3]
 
         epg_nat = epgs[3]
         recirc_nat = recircs[3]
@@ -525,43 +522,22 @@ class TestGBP(VppTestCase):
         #
         # 4 end-points, 2 in the same subnet, 3 in the same BD
         #
         #
         # 4 end-points, 2 in the same subnet, 3 in the same BD
         #
-        eps = []
-        eps.append(VppGbpEndpoint(self, self.pg0,
-                                  epgs[0], recircs[0],
-                                  "10.0.0.1",
-                                  "11.0.0.1"))
-        eps.append(VppGbpEndpoint(self, self.pg1,
-                                  epgs[0], recircs[0],
-                                  "10.0.0.2",
-                                  "11.0.0.2"))
-        eps.append(VppGbpEndpoint(self, self.pg2,
-                                  epgs[1], recircs[1],
-                                  "10.0.1.1",
-                                  "11.0.0.3"))
-        eps.append(VppGbpEndpoint(self, self.pg3,
-                                  epgs[2], recircs[2],
-                                  "10.0.2.1",
-                                  "11.0.0.4"))
-        eps.append(VppGbpEndpoint(self, self.pg0,
-                                  epgs[0], recircs[0],
-                                  "2001:10::1",
-                                  "3001::1",
-                                  is_ip6=True))
-        eps.append(VppGbpEndpoint(self, self.pg1,
-                                  epgs[0], recircs[0],
-                                  "2001:10::2",
-                                  "3001::2",
-                                  is_ip6=True))
-        eps.append(VppGbpEndpoint(self, self.pg2,
-                                  epgs[1], recircs[1],
-                                  "2001:10:1::1",
-                                  "3001::3",
-                                  is_ip6=True))
-        eps.append(VppGbpEndpoint(self, self.pg3,
-                                  epgs[2], recircs[2],
-                                  "2001:10:2::1",
-                                  "3001::4",
-                                  is_ip6=True))
+        eps = [VppGbpEndpoint(self, self.pg0,
+                              epgs[0], recircs[0],
+                              "10.0.0.1", "11.0.0.1",
+                              "2001:10::1", "3001::1"),
+               VppGbpEndpoint(self, self.pg1,
+                              epgs[0], recircs[0],
+                              "10.0.0.2", "11.0.0.2",
+                              "2001:10::2", "3001::2"),
+               VppGbpEndpoint(self, self.pg2,
+                              epgs[1], recircs[1],
+                              "10.0.1.1", "11.0.0.3",
+                              "2001:10:1::1", "3001::3"),
+               VppGbpEndpoint(self, self.pg3,
+                              epgs[2], recircs[2],
+                              "10.0.2.1", "11.0.0.4",
+                              "2001:10:2::1", "3001::4")]
 
         #
         # Config related to each of the EPGs
 
         #
         # Config related to each of the EPGs
@@ -653,83 +629,91 @@ class TestGBP(VppTestCase):
             # adj-fibs due to the fact the the BVI address has /32 and
             # the subnet is not attached.
             #
             # adj-fibs due to the fact the the BVI address has /32 and
             # the subnet is not attached.
             #
-            r = VppIpRoute(self, ep.ip, ep.ip_len,
-                           [VppRoutePath(ep.ip,
-                                         ep.epg.bvi.sw_if_index,
-                                         proto=ep.proto)],
-                           is_ip6=ep.is_ip6)
-            r.add_vpp_config()
-            ep_routes.append(r)
-
-            #
-            # ARP entries for the endpoints
-            #
-            a = VppNeighbor(self,
-                            ep.epg.bvi.sw_if_index,
-                            ep.itf.remote_mac,
-                            ep.ip, af=ep.af)
-            a.add_vpp_config()
-            ep_arps.append(a)
+            for (ip, fip) in zip(ep.ips, ep.fips):
+                r = VppIpRoute(self, ip.address, ip.length,
+                               [VppRoutePath(ip.address,
+                                             ep.epg.bvi.sw_if_index,
+                                             proto=ip.dpo_proto)],
+                               is_ip6=ip.is_ip6)
+                r.add_vpp_config()
+                ep_routes.append(r)
+
+                #
+                # ARP entries for the endpoints
+                #
+                a = VppNeighbor(self,
+                                ep.epg.bvi.sw_if_index,
+                                ep.itf.remote_mac,
+                                ip.address,
+                                af=ip.af)
+                a.add_vpp_config()
+                ep_arps.append(a)
+
+                # add the BD ARP termination entry
+                self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd,
+                                            mac=ep.bin_mac,
+                                            ip=ip.bytes,
+                                            is_ipv6=ip.is_ip6,
+                                            is_add=1)
+
+                # Add static mappings for each EP from the 10/8 to 11/8 network
+                if ip.af == AF_INET:
+                    self.vapi.nat44_add_del_static_mapping(ip.bytes,
+                                                           fip.bytes,
+                                                           vrf_id=0,
+                                                           addr_only=1)
+                else:
+                    self.vapi.nat66_add_del_static_mapping(ip.bytes,
+                                                           fip.bytes,
+                                                           vrf_id=0)
 
             # add each EP itf to the its BD
             self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index,
                                                  ep.epg.bd)
 
 
             # add each EP itf to the its BD
             self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index,
                                                  ep.epg.bd)
 
-            # add the BD ARP termination entry
-            self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd,
-                                        mac=ep.bin_mac,
-                                        ip=ep.ip_n,
-                                        is_ipv6=0,
-                                        is_add=1)
-
             # L2 FIB entry
             self.vapi.l2fib_add_del(ep.mac,
                                     ep.epg.bd,
                                     ep.itf.sw_if_index,
                                     is_add=1)
 
             # L2 FIB entry
             self.vapi.l2fib_add_del(ep.mac,
                                     ep.epg.bd,
                                     ep.itf.sw_if_index,
                                     is_add=1)
 
-            # Add static mappings for each EP from the 10/8 to 11/8 network
-            if ep.af == AF_INET:
-                self.vapi.nat44_add_del_static_mapping(ep.ip_n,
-                                                       ep.floating_ip_n,
-                                                       vrf_id=0,
-                                                       addr_only=1)
-            else:
-                self.vapi.nat66_add_del_static_mapping(ep.ip_n,
-                                                       ep.floating_ip_n,
-                                                       vrf_id=0)
-
             # VPP EP create ...
             ep.add_vpp_config()
 
             # VPP EP create ...
             ep.add_vpp_config()
 
+            self.logger.info(self.vapi.cli("sh gbp endpoint"))
+
             # ... results in a Gratuitous ARP/ND on the EPG's uplink
             # ... results in a Gratuitous ARP/ND on the EPG's uplink
-            rx = ep.epg.uplink.get_capture(1, timeout=0.2)
+            rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2)
 
 
-            if ep.is_ip6:
-                self.assertTrue(rx[0].haslayer(ICMPv6ND_NA))
-                self.assertEqual(rx[0][ICMPv6ND_NA].tgt, ep.ip)
-            else:
-                self.assertTrue(rx[0].haslayer(ARP))
-                self.assertEqual(rx[0][ARP].psrc, ep.ip)
-                self.assertEqual(rx[0][ARP].pdst, ep.ip)
+            for ii, ip in enumerate(ep.ips):
+                p = rx[ii]
 
 
-            # add the BD ARP termination entry for floating IP
-            self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd,
-                                        mac=ep.bin_mac,
-                                        ip=ep.floating_ip_n,
-                                        is_ipv6=ep.is_ip6,
-                                        is_add=1)
+                if ip.is_ip6:
+                    self.assertTrue(p.haslayer(ICMPv6ND_NA))
+                    self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address)
+                else:
+                    self.assertTrue(p.haslayer(ARP))
+                    self.assertEqual(p[ARP].psrc, ip.address)
+                    self.assertEqual(p[ARP].pdst, ip.address)
 
 
-            # floating IPs route via EPG recirc
-            r = VppIpRoute(self, ep.floating_ip, ep.ip_len,
-                           [VppRoutePath(ep.floating_ip,
-                                         ep.recirc.recirc.sw_if_index,
-                                         is_dvr=1,
-                                         proto=ep.proto)],
-                           table_id=20,
-                           is_ip6=ep.is_ip6)
-            r.add_vpp_config()
-            ep_routes.append(r)
+            # add the BD ARP termination entry for floating IP
+            for fip in ep.fips:
+                self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd,
+                                            mac=ep.bin_mac,
+                                            ip=fip.bytes,
+                                            is_ipv6=fip.is_ip6,
+                                            is_add=1)
+
+                # floating IPs route via EPG recirc
+                r = VppIpRoute(self, fip.address, fip.length,
+                               [VppRoutePath(fip.address,
+                                             ep.recirc.recirc.sw_if_index,
+                                             is_dvr=1,
+                                             proto=fip.dpo_proto)],
+                               table_id=20,
+                               is_ip6=fip.is_ip6)
+                r.add_vpp_config()
+                ep_routes.append(r)
 
             # L2 FIB entries in the NAT EPG BD to bridge the packets from
             # the outside direct to the internal EPG
 
             # L2 FIB entries in the NAT EPG BD to bridge the packets from
             # the outside direct to the internal EPG
@@ -760,14 +744,14 @@ class TestGBP(VppTestCase):
                        hwdst="ff:ff:ff:ff:ff:ff",
                        hwsrc=self.pg0.remote_mac,
                        pdst=epgs[0].bvi_ip4,
                        hwdst="ff:ff:ff:ff:ff:ff",
                        hwsrc=self.pg0.remote_mac,
                        pdst=epgs[0].bvi_ip4,
-                       psrc=eps[0].ip))
+                       psrc=eps[0].ip4.address))
 
         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
 
 
         self.send_and_expect(self.pg0, [pkt_arp], self.pg0)
 
-        nsma = in6_getnsma(inet_pton(AF_INET6, eps[4].ip))
+        nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address))
         d = inet_ntop(AF_INET6, nsma)
         pkt_nd = (Ether(dst=in6_getnsmac(nsma)) /
         d = inet_ntop(AF_INET6, nsma)
         pkt_nd = (Ether(dst=in6_getnsmac(nsma)) /
-                  IPv6(dst=d, src=eps[4].ip) /
+                  IPv6(dst=d, src=eps[0].ip6.address) /
                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) /
                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
                   ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) /
                   ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
         self.send_and_expect(self.pg0, [pkt_nd], self.pg0)
@@ -777,7 +761,7 @@ class TestGBP(VppTestCase):
         #
         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
                            src=self.pg0.remote_mac) /
         #
         pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff",
                            src=self.pg0.remote_mac) /
-                     IP(src=eps[0].ip, dst="232.1.1.1") /
+                     IP(src=eps[0].ip4.address, dst="232.1.1.1") /
                      UDP(sport=1234, dport=1234) /
                      Raw('\xa5' * 100))
 
                      UDP(sport=1234, dport=1234) /
                      Raw('\xa5' * 100))
 
@@ -797,12 +781,14 @@ class TestGBP(VppTestCase):
         #
         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
                                        dst=self.router_mac) /
         #
         pkt_intra_epg_220_ip4 = (Ether(src=self.pg0.remote_mac,
                                        dst=self.router_mac) /
-                                 IP(src=eps[0].ip, dst="10.0.0.99") /
+                                 IP(src=eps[0].ip4.address,
+                                    dst="10.0.0.99") /
                                  UDP(sport=1234, dport=1234) /
                                  Raw('\xa5' * 100))
         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
                                        dst=self.router_mac) /
                                  UDP(sport=1234, dport=1234) /
                                  Raw('\xa5' * 100))
         pkt_inter_epg_222_ip4 = (Ether(src=self.pg0.remote_mac,
                                        dst=self.router_mac) /
-                                 IP(src=eps[0].ip, dst="10.0.1.99") /
+                                 IP(src=eps[0].ip4.address,
+                                    dst="10.0.1.99") /
                                  UDP(sport=1234, dport=1234) /
                                  Raw('\xa5' * 100))
 
                                  UDP(sport=1234, dport=1234) /
                                  Raw('\xa5' * 100))
 
@@ -810,7 +796,8 @@ class TestGBP(VppTestCase):
 
         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
                                        dst=self.router_mac) /
 
         pkt_inter_epg_222_ip6 = (Ether(src=self.pg0.remote_mac,
                                        dst=self.router_mac) /
-                                 IPv6(src=eps[4].ip, dst="2001:10::99") /
+                                 IPv6(src=eps[0].ip6.address,
+                                      dst="2001:10::99") /
                                  UDP(sport=1234, dport=1234) /
                                  Raw('\xa5' * 100))
         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
                                  UDP(sport=1234, dport=1234) /
                                  Raw('\xa5' * 100))
         self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65)
@@ -824,9 +811,9 @@ class TestGBP(VppTestCase):
         s41.add_vpp_config()
         s42.add_vpp_config()
         s43.add_vpp_config()
         s41.add_vpp_config()
         s42.add_vpp_config()
         s43.add_vpp_config()
-        s61 = VppGbpSubnet(self, 0, "2001:10::1", 64, is_ip6=True)
-        s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64, is_ip6=True)
-        s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64, is_ip6=True)
+        s61 = VppGbpSubnet(self, 0, "2001:10::1", 64)
+        s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64)
+        s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64)
         s61.add_vpp_config()
         s62.add_vpp_config()
         s63.add_vpp_config()
         s61.add_vpp_config()
         s62.add_vpp_config()
         s63.add_vpp_config()
@@ -856,7 +843,8 @@ class TestGBP(VppTestCase):
         #
         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
                                              dst="00:00:00:33:44:55") /
         #
         pkt_intra_epg_220_to_uplink = (Ether(src=self.pg0.remote_mac,
                                              dst="00:00:00:33:44:55") /
-                                       IP(src=eps[0].ip, dst="10.0.0.99") /
+                                       IP(src=eps[0].ip4.address,
+                                          dst="10.0.0.99") /
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
@@ -869,7 +857,8 @@ class TestGBP(VppTestCase):
 
         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
                                              dst="00:00:00:33:44:66") /
 
         pkt_intra_epg_221_to_uplink = (Ether(src=self.pg2.remote_mac,
                                              dst="00:00:00:33:44:66") /
-                                       IP(src=eps[0].ip, dst="10.0.0.99") /
+                                       IP(src=eps[0].ip4.address,
+                                          dst="10.0.0.99") /
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
@@ -882,7 +871,8 @@ class TestGBP(VppTestCase):
         #
         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
                                                dst=self.pg0.remote_mac) /
         #
         pkt_intra_epg_220_from_uplink = (Ether(src="00:00:00:33:44:55",
                                                dst=self.pg0.remote_mac) /
-                                         IP(src=eps[0].ip, dst="10.0.0.99") /
+                                         IP(src=eps[0].ip4.address,
+                                            dst="10.0.0.99") /
                                          UDP(sport=1234, dport=1234) /
                                          Raw('\xa5' * 100))
 
                                          UDP(sport=1234, dport=1234) /
                                          Raw('\xa5' * 100))
 
@@ -896,7 +886,8 @@ class TestGBP(VppTestCase):
         #
         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
                                dst=self.pg1.remote_mac) /
         #
         pkt_intra_epg = (Ether(src=self.pg0.remote_mac,
                                dst=self.pg1.remote_mac) /
-                         IP(src=eps[0].ip, dst=eps[1].ip) /
+                         IP(src=eps[0].ip4.address,
+                            dst=eps[1].ip4.address) /
                          UDP(sport=1234, dport=1234) /
                          Raw('\xa5' * 100))
 
                          UDP(sport=1234, dport=1234) /
                          Raw('\xa5' * 100))
 
@@ -908,17 +899,20 @@ class TestGBP(VppTestCase):
         #
         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
                                           dst=self.pg2.remote_mac) /
         #
         pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
                                           dst=self.pg2.remote_mac) /
-                                    IP(src=eps[0].ip, dst=eps[2].ip) /
+                                    IP(src=eps[0].ip4.address,
+                                       dst=eps[2].ip4.address) /
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
                                           dst=self.pg0.remote_mac) /
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
         pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
                                           dst=self.pg0.remote_mac) /
-                                    IP(src=eps[2].ip, dst=eps[0].ip) /
+                                    IP(src=eps[2].ip4.address,
+                                       dst=eps[0].ip4.address) /
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
                                           dst=self.router_mac) /
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
         pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
                                           dst=self.router_mac) /
-                                    IP(src=eps[0].ip, dst=eps[3].ip) /
+                                    IP(src=eps[0].ip4.address,
+                                       dst=eps[3].ip4.address) /
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
 
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
 
@@ -1008,8 +1002,7 @@ class TestGBP(VppTestCase):
         se16 = VppGbpSubnet(self, 0, "::", 0,
                             is_internal=False,
                             sw_if_index=recirc_nat.recirc.sw_if_index,
         se16 = VppGbpSubnet(self, 0, "::", 0,
                             is_internal=False,
                             sw_if_index=recirc_nat.recirc.sw_if_index,
-                            epg=epg_nat.epg,
-                            is_ip6=True)
+                            epg=epg_nat.epg)
         se16.add_vpp_config()
         # in the NAT RD an external subnet via the NAT EPG's uplink
         se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0,
         se16.add_vpp_config()
         # in the NAT RD an external subnet via the NAT EPG's uplink
         se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0,
@@ -1019,8 +1012,7 @@ class TestGBP(VppTestCase):
         se36 = VppGbpSubnet(self, 20, "::", 0,
                             is_internal=False,
                             sw_if_index=epg_nat.uplink.sw_if_index,
         se36 = VppGbpSubnet(self, 20, "::", 0,
                             is_internal=False,
                             sw_if_index=epg_nat.uplink.sw_if_index,
-                            epg=epg_nat.epg,
-                            is_ip6=True)
+                            epg=epg_nat.epg)
         se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8,
                            is_internal=False,
                            sw_if_index=epg_nat.uplink.sw_if_index,
         se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8,
                            is_internal=False,
                            sw_if_index=epg_nat.uplink.sw_if_index,
@@ -1033,14 +1025,15 @@ class TestGBP(VppTestCase):
         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
         self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1"))
         self.logger.info(self.vapi.cli("sh ip6 fib ::/0"))
         self.logger.info(self.vapi.cli("sh ip6 fib %s" %
-                                       eps[4].floating_ip))
+                                       eps[0].fip6))
 
         #
         # From an EP to an outside addess: IN2OUT
         #
         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
                                              dst=self.router_mac) /
 
         #
         # From an EP to an outside addess: IN2OUT
         #
         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
                                              dst=self.router_mac) /
-                                       IP(src=eps[0].ip, dst="1.1.1.1") /
+                                       IP(src=eps[0].ip4.address,
+                                          dst="1.1.1.1") /
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
@@ -1062,25 +1055,26 @@ class TestGBP(VppTestCase):
         self.send_and_expect_natted(self.pg0,
                                     pkt_inter_epg_220_to_global * 65,
                                     self.pg7,
         self.send_and_expect_natted(self.pg0,
                                     pkt_inter_epg_220_to_global * 65,
                                     self.pg7,
-                                    eps[0].floating_ip)
+                                    eps[0].fip4.address)
 
         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
                                              dst=self.router_mac) /
 
         pkt_inter_epg_220_to_global = (Ether(src=self.pg0.remote_mac,
                                              dst=self.router_mac) /
-                                       IPv6(src=eps[4].ip, dst="6001::1") /
+                                       IPv6(src=eps[0].ip6.address,
+                                            dst="6001::1") /
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
         self.send_and_expect_natted6(self.pg0,
                                      pkt_inter_epg_220_to_global * 65,
                                      self.pg7,
                                        UDP(sport=1234, dport=1234) /
                                        Raw('\xa5' * 100))
 
         self.send_and_expect_natted6(self.pg0,
                                      pkt_inter_epg_220_to_global * 65,
                                      self.pg7,
-                                     eps[4].floating_ip)
+                                     eps[0].fip6.address)
 
         #
         # From a global address to an EP: OUT2IN
         #
         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
                                                dst=self.pg0.remote_mac) /
 
         #
         # From a global address to an EP: OUT2IN
         #
         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
                                                dst=self.pg0.remote_mac) /
-                                         IP(dst=eps[0].floating_ip,
+                                         IP(dst=eps[0].fip4.address,
                                             src="1.1.1.1") /
                                          UDP(sport=1234, dport=1234) /
                                          Raw('\xa5' * 100))
                                             src="1.1.1.1") /
                                          UDP(sport=1234, dport=1234) /
                                          Raw('\xa5' * 100))
@@ -1094,19 +1088,19 @@ class TestGBP(VppTestCase):
         self.send_and_expect_unnatted(self.pg7,
                                       pkt_inter_epg_220_from_global * 65,
                                       eps[0].itf,
         self.send_and_expect_unnatted(self.pg7,
                                       pkt_inter_epg_220_from_global * 65,
                                       eps[0].itf,
-                                      eps[0].ip)
+                                      eps[0].ip4.address)
 
         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
                                                dst=self.pg0.remote_mac) /
 
         pkt_inter_epg_220_from_global = (Ether(src=self.router_mac,
                                                dst=self.pg0.remote_mac) /
-                                         IPv6(dst=eps[4].floating_ip,
+                                         IPv6(dst=eps[0].fip6.address,
                                               src="6001::1") /
                                          UDP(sport=1234, dport=1234) /
                                          Raw('\xa5' * 100))
 
         self.send_and_expect_unnatted6(self.pg7,
                                        pkt_inter_epg_220_from_global * 65,
                                               src="6001::1") /
                                          UDP(sport=1234, dport=1234) /
                                          Raw('\xa5' * 100))
 
         self.send_and_expect_unnatted6(self.pg7,
                                        pkt_inter_epg_220_from_global * 65,
-                                       eps[4].itf,
-                                       eps[4].ip)
+                                       eps[0].itf,
+                                       eps[0].ip6.address)
 
         #
         # From a local VM to another local VM using resp. public addresses:
 
         #
         # From a local VM to another local VM using resp. public addresses:
@@ -1114,46 +1108,44 @@ class TestGBP(VppTestCase):
         #
         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
                                           dst=self.router_mac) /
         #
         pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
                                           dst=self.router_mac) /
-                                    IP(src=eps[0].ip,
-                                       dst=eps[1].floating_ip) /
+                                    IP(src=eps[0].ip4.address,
+                                       dst=eps[1].fip4.address) /
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
 
         self.send_and_expect_double_natted(eps[0].itf,
                                            pkt_intra_epg_220_global * 65,
                                            eps[1].itf,
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
 
         self.send_and_expect_double_natted(eps[0].itf,
                                            pkt_intra_epg_220_global * 65,
                                            eps[1].itf,
-                                           eps[0].floating_ip,
-                                           eps[1].ip)
+                                           eps[0].fip4.address,
+                                           eps[1].ip4.address)
 
 
-        pkt_intra_epg_220_global = (Ether(src=self.pg4.remote_mac,
+        pkt_intra_epg_220_global = (Ether(src=self.pg0.remote_mac,
                                           dst=self.router_mac) /
                                           dst=self.router_mac) /
-                                    IPv6(src=eps[4].ip,
-                                         dst=eps[5].floating_ip) /
+                                    IPv6(src=eps[0].ip6.address,
+                                         dst=eps[1].fip6.address) /
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
 
                                     UDP(sport=1234, dport=1234) /
                                     Raw('\xa5' * 100))
 
-        self.send_and_expect_double_natted6(eps[4].itf,
+        self.send_and_expect_double_natted6(eps[0].itf,
                                             pkt_intra_epg_220_global * 65,
                                             pkt_intra_epg_220_global * 65,
-                                            eps[5].itf,
-                                            eps[4].floating_ip,
-                                            eps[5].ip)
+                                            eps[1].itf,
+                                            eps[0].fip6.address,
+                                            eps[1].ip6.address)
 
         #
         # cleanup
         #
         for ep in eps:
             # del static mappings for each EP from the 10/8 to 11/8 network
 
         #
         # cleanup
         #
         for ep in eps:
             # del static mappings for each EP from the 10/8 to 11/8 network
-            if ep.af == AF_INET:
-                self.vapi.nat44_add_del_static_mapping(ep.ip_n,
-                                                       ep.floating_ip_n,
-                                                       vrf_id=0,
-                                                       addr_only=1,
-                                                       is_add=0)
-            else:
-                self.vapi.nat66_add_del_static_mapping(ep.ip_n,
-                                                       ep.floating_ip_n,
-                                                       vrf_id=0,
-                                                       is_add=0)
+            self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes,
+                                                   ep.fip4.bytes,
+                                                   vrf_id=0,
+                                                   addr_only=1,
+                                                   is_add=0)
+            self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes,
+                                                   ep.fip6.bytes,
+                                                   vrf_id=0,
+                                                   is_add=0)
 
         for epg in epgs:
             # IP config on the BVI interfaces
 
         for epg in epgs:
             # IP config on the BVI interfaces
index 2559381..4d40b3b 100644 (file)
@@ -6,7 +6,8 @@ from logging import *
 from framework import VppTestCase, VppTestRunner
 from vpp_sub_interface import VppDot1QSubint
 from vpp_gre_interface import VppGreInterface, VppGre6Interface
 from framework import VppTestCase, VppTestRunner
 from vpp_sub_interface import VppDot1QSubint
 from vpp_gre_interface import VppGreInterface, VppGre6Interface
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppIpTable
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
 from vpp_papi_provider import L2_VTR_OP
 
 from scapy.packet import Raw
 from vpp_papi_provider import L2_VTR_OP
 
 from scapy.packet import Raw
index 9a0c752..95f9229 100644 (file)
@@ -7,9 +7,10 @@ from framework import VppTestCase, VppTestRunner
 from util import ppp, ip6_normalize
 from vpp_sub_interface import VppSubInterface, VppDot1QSubint
 from vpp_pg_interface import is_ipv6_misc
 from util import ppp, ip6_normalize
 from vpp_sub_interface import VppSubInterface, VppDot1QSubint
 from vpp_pg_interface import is_ipv6_misc
+from vpp_ip import DpoProto
 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \
     VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
 from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \
     VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
-    VppMplsRoute, DpoProto, VppMplsTable, VppIpTable
+    VppMplsRoute, VppMplsTable, VppIpTable
 from vpp_neighbor import find_nbr, VppNeighbor
 
 from scapy.packet import Raw
 from vpp_neighbor import find_nbr, VppNeighbor
 
 from scapy.packet import Raw
index 9c216d5..64eb304 100644 (file)
@@ -3,8 +3,9 @@
 import unittest
 
 from framework import VppTestCase, VppTestRunner
 import unittest
 
 from framework import VppTestCase, VppTestRunner
+from vpp_ip import DpoProto
 from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \
 from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \
-    MRouteItfFlags, MRouteEntryFlags, VppIpTable, DpoProto
+    MRouteItfFlags, MRouteEntryFlags, VppIpTable
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether
index 5754bd0..350eae0 100644 (file)
@@ -5,7 +5,8 @@ import unittest
 from scapy.layers.inet6 import IPv6, Ether, IP, UDP
 from scapy.all import fragment, RandShort
 from framework import VppTestCase, VppTestRunner
 from scapy.layers.inet6 import IPv6, Ether, IP, UDP
 from scapy.all import fragment, RandShort
 from framework import VppTestCase, VppTestRunner
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppIpTable
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
 from socket import AF_INET, AF_INET6, inet_pton
 import StringIO
 
 from socket import AF_INET, AF_INET6, inet_pton
 import StringIO
 
index c5e193a..1a53492 100644 (file)
@@ -4,7 +4,8 @@ import unittest
 import socket
 
 from framework import VppTestCase, VppTestRunner
 import socket
 
 from framework import VppTestCase, VppTestRunner
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath
 
 from scapy.layers.l2 import Ether, Raw
 from scapy.layers.inet import IP, UDP, ICMP
 
 from scapy.layers.l2 import Ether, Raw
 from scapy.layers.inet import IP, UDP, ICMP
index 33fed68..d943f82 100644 (file)
@@ -4,9 +4,10 @@ import unittest
 import socket
 
 from framework import VppTestCase, VppTestRunner
 import socket
 
 from framework import VppTestCase, VppTestRunner
+from vpp_ip import DpoProto
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
     VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
     VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
-    MRouteItfFlags, MRouteEntryFlags, DpoProto, VppIpTable, VppMplsTable, \
+    MRouteItfFlags, MRouteEntryFlags, VppIpTable, VppMplsTable, \
     VppMplsLabel, MplsLspMode
 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
 
     VppMplsLabel, MplsLspMode
 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
 
index d6be2e2..a70d513 100644 (file)
@@ -12,7 +12,8 @@ import unittest
 from scapy.layers.inet6 import IPv6, Ether, IP, UDP, ICMPv6PacketTooBig
 from scapy.layers.inet import ICMP
 from framework import VppTestCase, VppTestRunner
 from scapy.layers.inet6 import IPv6, Ether, IP, UDP, ICMPv6PacketTooBig
 from scapy.layers.inet import ICMP
 from framework import VppTestCase, VppTestRunner
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath
 from socket import AF_INET, AF_INET6, inet_pton
 import StringIO
 
 from socket import AF_INET, AF_INET6, inet_pton
 import StringIO
 
index d6d5c50..c901eea 100644 (file)
@@ -11,7 +11,8 @@ from scapy.layers.inet6 import IPv6
 
 from framework import VppTestCase, VppTestRunner
 from vpp_sub_interface import VppP2PSubint
 
 from framework import VppTestCase, VppTestRunner
 from vpp_sub_interface import VppP2PSubint
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath
 from util import mactobinary
 
 
 from util import mactobinary
 
 
index 76fa8a1..4916550 100644 (file)
@@ -5,8 +5,9 @@ import unittest
 from framework import VppTestCase, VppTestRunner
 from vpp_papi_provider import QOS_SOURCE
 from vpp_sub_interface import VppDot1QSubint
 from framework import VppTestCase, VppTestRunner
 from vpp_papi_provider import QOS_SOURCE
 from vpp_sub_interface import VppDot1QSubint
+from vpp_ip import DpoProto
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
-    VppMplsLabel, VppMplsTable, DpoProto
+    VppMplsLabel, VppMplsTable
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, Dot1Q
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, Dot1Q
index 76aabcb..b2c271d 100644 (file)
@@ -11,7 +11,8 @@ from util import ppp, fragment_rfc791, fragment_rfc8200
 from scapy.layers.inet6 import IPv6, IPv6ExtHdrFragment, ICMPv6ParamProblem,\
     ICMPv6TimeExceeded
 from vpp_gre_interface import VppGreInterface, VppGre6Interface
 from scapy.layers.inet6 import IPv6, IPv6ExtHdrFragment, ICMPv6ParamProblem,\
     ICMPv6TimeExceeded
 from vpp_gre_interface import VppGreInterface, VppGre6Interface
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath
 
 test_packet_count = 257
 
 
 test_packet_count = 257
 
index 7656c3f..a469ac5 100644 (file)
@@ -6,7 +6,8 @@ from scapy.layers.inet import IP, UDP, Ether
 from scapy.layers.inet6 import IPv6
 from scapy.packet import Raw
 from framework import VppTestCase, VppTestRunner
 from scapy.layers.inet6 import IPv6
 from scapy.packet import Raw
 from framework import VppTestCase, VppTestRunner
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppIpTable
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
 from socket import AF_INET, AF_INET6, inet_pton
 
 """ Test6rd is a subclass of  VPPTestCase classes.
 from socket import AF_INET, AF_INET6, inet_pton
 
 """ Test6rd is a subclass of  VPPTestCase classes.
index ded4a71..756405a 100644 (file)
@@ -4,10 +4,9 @@ import unittest
 import socket
 
 from framework import VppTestCase, VppTestRunner
 import socket
 
 from framework import VppTestCase, VppTestRunner
+from vpp_ip import DpoProto
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
-    VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
-    MRouteItfFlags, MRouteEntryFlags, DpoProto, VppIpTable, VppMplsTable, \
-    VppMplsLabel, MplsLspMode
+    VppIpTable, VppMplsTable, VppMplsLabel
 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
 
 from scapy.packet import Raw
 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
 
 from scapy.packet import Raw
index 75d9d12..299f343 100644 (file)
@@ -5,7 +5,8 @@ import binascii
 from socket import AF_INET6
 
 from framework import VppTestCase, VppTestRunner
 from socket import AF_INET6
 
 from framework import VppTestCase, VppTestRunner
-from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppIpTable
+from vpp_ip import DpoProto
+from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
 from vpp_srv6 import SRv6LocalSIDBehaviors, VppSRv6LocalSID, VppSRv6Policy, \
     SRv6PolicyType, VppSRv6Steering, SRv6PolicySteeringTypes
 
 from vpp_srv6 import SRv6LocalSIDBehaviors, VppSRv6LocalSID, VppSRv6Policy, \
     SRv6PolicyType, VppSRv6Steering, SRv6PolicySteeringTypes
 
index 912d843..e44e6b5 100644 (file)
@@ -4,6 +4,7 @@
 """
 
 from ipaddress import ip_address
 """
 
 from ipaddress import ip_address
+from socket import AF_INET, AF_INET6
 
 
 class IpAddressFamily:
 
 
 class IpAddressFamily:
@@ -11,17 +12,16 @@ class IpAddressFamily:
     ADDRESS_IP6 = 1
 
 
     ADDRESS_IP6 = 1
 
 
-INVALID_INDEX = 0xffffffff
+class DpoProto:
+    DPO_PROTO_IP4 = 0
+    DPO_PROTO_IP6 = 1
+    DPO_PROTO_MPLS = 2
+    DPO_PROTO_ETHERNET = 3
+    DPO_PROTO_BIER = 4
+    DPO_PROTO_NSH = 5
 
 
 
 
-def compare_ip_address(api_address, py_address):
-    if 4 is py_address.version:
-        if py_address.packed == api_address.ip4.address:
-            return True
-    else:
-        if py_address.packed == api_address.ip6.address:
-            return True
-    return False
+INVALID_INDEX = 0xffffffff
 
 
 class VppIpAddressUnion():
 
 
 class VppIpAddressUnion():
@@ -29,16 +29,8 @@ class VppIpAddressUnion():
         self.addr = addr
         self.ip_addr = ip_address(unicode(self.addr))
 
         self.addr = addr
         self.ip_addr = ip_address(unicode(self.addr))
 
-    @property
-    def version(self):
-        return self.ip_addr.version
-
-    @property
-    def address(self):
-        return self.addr
-
     def encode(self):
     def encode(self):
-        if self.ip_addr.version is 6:
+        if self.version is 6:
             return {
                 'ip6': {
                     'address': self.ip_addr.packed
             return {
                 'ip6': {
                     'address': self.ip_addr.packed
@@ -51,6 +43,41 @@ class VppIpAddressUnion():
                 },
             }
 
                 },
             }
 
+    @property
+    def version(self):
+        return self.ip_addr.version
+
+    @property
+    def address(self):
+        return self.addr
+
+    @property
+    def length(self):
+        if self.version is 6:
+            return 128
+        else:
+            return 32
+
+    @property
+    def bytes(self):
+        return self.ip_addr.packed
+
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.ip_addr == other.ip_addr
+        elif hasattr(other, "ip4") and hasattr(other, "ip6"):
+            # vl_api_address_union_t
+            if 4 is self.version:
+                return self.ip_addr.packed == other.ip4.address
+            else:
+                return self.ip_addr.packed == other.ip6.address
+        else:
+            raise Exception("Comparing VppIpAddresUnions:%s"
+                            " with unknown type: %s" %
+                            (self, other))
+
+        return False
+
 
 class VppIpAddress():
     def __init__(self, addr):
 
 class VppIpAddress():
     def __init__(self, addr):
@@ -68,10 +95,62 @@ class VppIpAddress():
                 'un': self.addr.encode()
             }
 
                 'un': self.addr.encode()
             }
 
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.addr == other.addr
+        elif hasattr(other, "af") and hasattr(other, "un"):
+            # a vp_api_address_t
+            if 4 is self.version:
+                return other.af == IpAddressFamily.ADDRESS_IP4 and \
+                    other.un == self.addr
+            else:
+                return other.af == IpAddressFamily.ADDRESS_IP6 and \
+                    other.un == self.addr
+        else:
+            raise Exception("Comparing VppIpAddress:%s with unknown type: %s" %
+                            (self, other))
+        return False
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    def __str__(self):
+        return self.address
+
+    @property
+    def bytes(self):
+        return self.addr.bytes
+
     @property
     def address(self):
         return self.addr.address
 
     @property
     def address(self):
         return self.addr.address
 
+    @property
+    def length(self):
+        return self.addr.length
+
+    @property
+    def version(self):
+        return self.addr.version
+
+    @property
+    def is_ip6(self):
+        return (self.version == 6)
+
+    @property
+    def af(self):
+        if self.version == 6:
+            return AF_INET6
+        else:
+            return AF_INET
+
+    @property
+    def dpo_proto(self):
+        if self.version is 6:
+            return DpoProto.DPO_PROTO_IP6
+        else:
+            return DpoProto.DPO_PROTO_IP4
+
 
 class VppIpPrefix():
     def __init__(self, addr, len):
 
 class VppIpPrefix():
     def __init__(self, addr, len):
@@ -91,6 +170,25 @@ class VppIpPrefix():
     def address(self):
         return self.addr.address
 
     def address(self):
         return self.addr.address
 
+    @property
+    def length(self):
+        return self.len
+
+    def __str__(self):
+        return "%s/%d" % (self.address, self.length)
+
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return (self.len == other.len and self.addr == other.addr)
+        elif hasattr(other, "address") and hasattr(other, "address_length"):
+            # vl_api_prefix_t
+            return self.len == other.address_length and \
+                self.addr == other.address
+        else:
+            raise Exception("Comparing VppIpPrefix:%s with unknown type: %s" %
+                            (self, other))
+        return False
+
 
 class VppIpMPrefix():
     def __init__(self, saddr, gaddr, len):
 
 class VppIpMPrefix():
     def __init__(self, saddr, gaddr, len):
index 216f5c7..9d6bfb7 100644 (file)
@@ -6,6 +6,7 @@
 
 from vpp_object import *
 from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
 
 from vpp_object import *
 from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
+from vpp_ip import *
 
 # from vnet/vnet/mpls/mpls_types.h
 MPLS_IETF_MAX_LABEL = 0xfffff
 
 # from vnet/vnet/mpls/mpls_types.h
 MPLS_IETF_MAX_LABEL = 0xfffff
@@ -29,15 +30,6 @@ class MRouteEntryFlags:
     MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8
 
 
     MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8
 
 
-class DpoProto:
-    DPO_PROTO_IP4 = 0
-    DPO_PROTO_IP6 = 1
-    DPO_PROTO_MPLS = 2
-    DPO_PROTO_ETHERNET = 3
-    DPO_PROTO_BIER = 4
-    DPO_PROTO_NSH = 5
-
-
 class MplsLspMode:
     PIPE = 0
     UNIFORM = 1
 class MplsLspMode:
     PIPE = 0
     UNIFORM = 1
diff --git a/test/vpp_mac.py b/test/vpp_mac.py
new file mode 100644 (file)
index 0000000..c9ee11e
--- /dev/null
@@ -0,0 +1,24 @@
+"""
+  MAC Types
+
+"""
+
+from util import mactobinary
+
+
+class VppMacAddress():
+    def __init__(self, addr):
+        self.address = addr
+
+    def encode(self):
+        return {
+            'bytes': self.bytes
+        }
+
+    @property
+    def bytes(self):
+        return mactobinary(self.address)
+
+    @property
+    def address(self):
+        return self.addr.address
index b575b8a..3028a25 100644 (file)
@@ -3432,15 +3432,20 @@ class VppPapiProvider(object):
                          'enable_ip6': 1 if enable_ip6 else 0,
                          })
 
                          'enable_ip6': 1 if enable_ip6 else 0,
                          })
 
-    def gbp_endpoint_add_del(self, is_add, sw_if_index, addr, is_ip6, epg):
-        """ GBP endpoint Add/Del """
-        return self.api(self.papi.gbp_endpoint_add_del,
-                        {'is_add': is_add,
-                         'endpoint': {
-                             'is_ip6': is_ip6,
-                             'sw_if_index': sw_if_index,
-                             'address': addr,
-                             'epg_id': epg}})
+    def gbp_endpoint_add(self, sw_if_index, ips, mac, epg):
+        """ GBP endpoint Add """
+        return self.api(self.papi.gbp_endpoint_add,
+                        {'endpoint': {
+                            'sw_if_index': sw_if_index,
+                            'ips': ips,
+                            'n_ips': len(ips),
+                            'mac': mac,
+                            'epg_id': epg}})
+
+    def gbp_endpoint_del(self, handle):
+        """ GBP endpoint Del """
+        return self.api(self.papi.gbp_endpoint_del,
+                        {'handle': handle})
 
     def gbp_endpoint_dump(self):
         """ GBP endpoint Dump """
 
     def gbp_endpoint_dump(self):
         """ GBP endpoint Dump """
@@ -3479,7 +3484,7 @@ class VppPapiProvider(object):
 
     def gbp_subnet_add_del(self, is_add, table_id,
                            is_internal,
 
     def gbp_subnet_add_del(self, is_add, table_id,
                            is_internal,
-                           addr, addr_len,
+                           prefix,
                            sw_if_index=0xffffffff,
                            epg_id=0xffff,
                            is_ip6=False):
                            sw_if_index=0xffffffff,
                            epg_id=0xffff,
                            is_ip6=False):
@@ -3491,8 +3496,7 @@ class VppPapiProvider(object):
                              'is_ip6': is_ip6,
                              'sw_if_index': sw_if_index,
                              'epg_id': epg_id,
                              'is_ip6': is_ip6,
                              'sw_if_index': sw_if_index,
                              'epg_id': epg_id,
-                             'address': addr,
-                             'address_length': addr_len,
+                             'prefix': prefix,
                              'table_id': table_id}})
 
     def gbp_subnet_dump(self):
                              'table_id': table_id}})
 
     def gbp_subnet_dump(self):
index 002f9f4..826378b 100644 (file)
@@ -12,10 +12,8 @@ def find_udp_encap(test, ue):
     encaps = test.vapi.udp_encap_dump()
     for e in encaps:
         if ue.id == e.udp_encap.id \
     encaps = test.vapi.udp_encap_dump()
     for e in encaps:
         if ue.id == e.udp_encap.id \
-           and compare_ip_address(e.udp_encap.src_ip.un,
-                                  ue.src_ip.addr.ip_addr) \
-           and compare_ip_address(e.udp_encap.dst_ip.un,
-                                  ue.dst_ip.addr.ip_addr) \
+           and ue.src_ip == e.udp_encap.src_ip \
+           and ue.dst_ip == e.udp_encap.dst_ip \
            and e.udp_encap.dst_port == ue.dst_port \
            and e.udp_encap.src_port == ue.src_port:
             return True
            and e.udp_encap.dst_port == ue.dst_port \
            and e.udp_encap.src_port == ue.src_port:
             return True