GBP V2
update the GBP plugin to implement the full NAT feature set of opflex agent
Change-Id: Ic06a039c889445ed0b9087fa1f292634192b0f8d
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
diff --git a/src/vpp-api/vom/Makefile.am b/src/vpp-api/vom/Makefile.am
index dad4863..f802849 100644
--- a/src/vpp-api/vom/Makefile.am
+++ b/src/vpp-api/vom/Makefile.am
@@ -66,8 +66,14 @@
GBP_SOURCES =
if ENABLE_GBP_PLUGIN
GBP_SOURCES += \
+ gbp_recirc_cmds.cpp \
+ gbp_recirc.cpp \
+ gbp_subnet_cmds.cpp \
+ gbp_subnet.cpp \
gbp_endpoint_cmds.cpp \
gbp_endpoint.cpp \
+ gbp_endpoint_group_cmds.cpp \
+ gbp_endpoint_group.cpp \
gbp_contract_cmds.cpp \
gbp_contract.cpp
endif
@@ -142,7 +148,7 @@
ACL_INCLUDES =
if ENABLE_ACL_PLUGIN
-ACL_INCLUDES += \
+ACL_INCLUDES += \
acl_binding.hpp \
acl_ethertype.hpp \
acl_l2_rule.hpp \
@@ -153,7 +159,7 @@
NAT_INCLUDES =
if ENABLE_NAT_PLUGIN
-NAT_INCLUDES += \
+NAT_INCLUDES += \
nat_static.hpp \
nat_binding.hpp
endif
@@ -166,8 +172,11 @@
GBP_INCLUDES =
if ENABLE_GBP_PLUGIN
-GBP_INCLUDES += \
+GBP_INCLUDES += \
gbp_endpoint.hpp \
+ gbp_endpoint_group.hpp \
+ gbp_subnet.hpp \
+ gbp_recirc.hpp \
gbp_contract.hpp
endif
diff --git a/src/vpp-api/vom/acl_l2_rule.cpp b/src/vpp-api/vom/acl_l2_rule.cpp
index 1fb06e2..2b12e68 100644
--- a/src/vpp-api/vom/acl_l2_rule.cpp
+++ b/src/vpp-api/vom/acl_l2_rule.cpp
@@ -65,7 +65,7 @@
return m_priority;
}
-action_t
+const action_t&
l2_rule::action() const
{
return m_action;
diff --git a/src/vpp-api/vom/acl_l2_rule.hpp b/src/vpp-api/vom/acl_l2_rule.hpp
index 4faa628..8c094ae 100644
--- a/src/vpp-api/vom/acl_l2_rule.hpp
+++ b/src/vpp-api/vom/acl_l2_rule.hpp
@@ -69,7 +69,7 @@
* Getters
*/
uint32_t priority() const;
- action_t action() const;
+ const action_t& action() const;
const route::prefix_t& src_ip() const;
const mac_address_t& mac() const;
const mac_address_t& mac_mask() const;
diff --git a/src/vpp-api/vom/acl_l3_rule.cpp b/src/vpp-api/vom/acl_l3_rule.cpp
index 4b96cae..417dc5f 100644
--- a/src/vpp-api/vom/acl_l3_rule.cpp
+++ b/src/vpp-api/vom/acl_l3_rule.cpp
@@ -147,7 +147,7 @@
return m_priority;
}
-action_t
+const action_t&
l3_rule::action() const
{
return m_action;
diff --git a/src/vpp-api/vom/acl_l3_rule.hpp b/src/vpp-api/vom/acl_l3_rule.hpp
index 25a2a47..c1f1cee 100644
--- a/src/vpp-api/vom/acl_l3_rule.hpp
+++ b/src/vpp-api/vom/acl_l3_rule.hpp
@@ -121,7 +121,7 @@
*/
const route::prefix_t& src() const;
uint32_t priority() const;
- action_t action() const;
+ const action_t& action() const;
const route::prefix_t& dst() const;
uint8_t proto() const;
uint16_t srcport_or_icmptype_first() const;
diff --git a/src/vpp-api/vom/acl_types.hpp b/src/vpp-api/vom/acl_types.hpp
index ccf0a1c..cf5bee3 100644
--- a/src/vpp-api/vom/acl_types.hpp
+++ b/src/vpp-api/vom/acl_types.hpp
@@ -26,16 +26,6 @@
struct action_t : public enum_base<action_t>
{
/**
- * Constructor
- */
- action_t(int v, const std::string s);
-
- /**
- * Destructor
- */
- ~action_t() = default;
-
- /**
* Permit and Reflexive
*/
const static action_t PERMITANDREFLEX;
@@ -60,6 +50,9 @@
*which implements the connection tracking ....
*/
static const action_t& from_bool(bool b, uint8_t c);
+
+private:
+ action_t(int v, const std::string s);
};
};
};
diff --git a/src/vpp-api/vom/bridge_domain.cpp b/src/vpp-api/vom/bridge_domain.cpp
index be520f5..b8c89e1 100644
--- a/src/vpp-api/vom/bridge_domain.cpp
+++ b/src/vpp-api/vom/bridge_domain.cpp
@@ -31,6 +31,33 @@
{
}
+const bridge_domain::flood_mode_t bridge_domain::flood_mode_t::ON(1, "on");
+const bridge_domain::flood_mode_t bridge_domain::flood_mode_t::OFF(0, "off");
+
+bridge_domain::flood_mode_t::flood_mode_t(int v, const std::string& s)
+ : enum_base<bridge_domain::flood_mode_t>(v, s)
+{
+}
+
+const bridge_domain::mac_age_mode_t bridge_domain::mac_age_mode_t::ON(1, "on");
+const bridge_domain::mac_age_mode_t bridge_domain::mac_age_mode_t::OFF(0,
+ "off");
+
+bridge_domain::mac_age_mode_t::mac_age_mode_t(int v, const std::string& s)
+ : enum_base<bridge_domain::mac_age_mode_t>(v, s)
+{
+}
+
+const bridge_domain::arp_term_mode_t bridge_domain::arp_term_mode_t::ON(1,
+ "on");
+const bridge_domain::arp_term_mode_t bridge_domain::arp_term_mode_t::OFF(0,
+ "off");
+
+bridge_domain::arp_term_mode_t::arp_term_mode_t(int v, const std::string& s)
+ : enum_base<bridge_domain::arp_term_mode_t>(v, s)
+{
+}
+
/**
* A DB of al the interfaces, key on the name
*/
@@ -41,15 +68,25 @@
/**
* Construct a new object matching the desried state
*/
-bridge_domain::bridge_domain(uint32_t id, const learning_mode_t& lmode)
+bridge_domain::bridge_domain(uint32_t id,
+ const learning_mode_t& lmode,
+ const arp_term_mode_t& amode,
+ const flood_mode_t& fmode,
+ const mac_age_mode_t& mmode)
: m_id(id)
, m_learning_mode(lmode)
+ , m_arp_term_mode(amode)
+ , m_flood_mode(fmode)
+ , m_mac_age_mode(mmode)
{
}
bridge_domain::bridge_domain(const bridge_domain& o)
: m_id(o.m_id)
, m_learning_mode(o.m_learning_mode)
+ , m_arp_term_mode(o.m_arp_term_mode)
+ , m_flood_mode(o.m_flood_mode)
+ , m_mac_age_mode(o.m_mac_age_mode)
{
}
@@ -68,7 +105,10 @@
bool
bridge_domain::operator==(const bridge_domain& b) const
{
- return ((m_learning_mode == b.m_learning_mode) && id() == b.id());
+ return ((m_learning_mode == b.m_learning_mode) &&
+ (m_flood_mode == b.m_flood_mode) &&
+ (m_mac_age_mode == b.m_mac_age_mode) &&
+ (m_arp_term_mode == b.m_arp_term_mode) && id() == b.id());
}
void
@@ -84,7 +124,8 @@
bridge_domain::replay()
{
if (rc_t::OK == m_id.rc()) {
- HW::enqueue(new bridge_domain_cmds::create_cmd(m_id, m_learning_mode));
+ HW::enqueue(new bridge_domain_cmds::create_cmd(
+ m_id, m_learning_mode, m_arp_term_mode, m_flood_mode, m_mac_age_mode));
}
}
@@ -119,7 +160,8 @@
* the desired state is always that the interface should be created
*/
if (rc_t::OK != m_id.rc()) {
- HW::enqueue(new bridge_domain_cmds::create_cmd(m_id, m_learning_mode));
+ HW::enqueue(new bridge_domain_cmds::create_cmd(
+ m_id, m_learning_mode, m_arp_term_mode, m_flood_mode, m_mac_age_mode));
}
}
@@ -173,8 +215,10 @@
for (unsigned int ii = 0; ii < payload.n_sw_ifs; ii++) {
std::shared_ptr<interface> itf =
interface::find(payload.sw_if_details[ii].sw_if_index);
- l2_binding l2(*itf, bd);
- OM::commit(key, l2);
+ if (itf) {
+ l2_binding l2(*itf, bd);
+ OM::commit(key, l2);
+ }
}
}
}
diff --git a/src/vpp-api/vom/bridge_domain.hpp b/src/vpp-api/vom/bridge_domain.hpp
index c7f84e9..d345da2 100644
--- a/src/vpp-api/vom/bridge_domain.hpp
+++ b/src/vpp-api/vom/bridge_domain.hpp
@@ -52,6 +52,51 @@
};
/**
+ * Bridge Domain ARP termination mode
+ */
+ struct arp_term_mode_t : enum_base<arp_term_mode_t>
+ {
+ const static arp_term_mode_t ON;
+ const static arp_term_mode_t OFF;
+
+ private:
+ /**
+ * Private constructor taking the value and the string name
+ */
+ arp_term_mode_t(int v, const std::string& s);
+ };
+
+ /**
+ * Bridge Domain MAC aging mode
+ */
+ struct mac_age_mode_t : enum_base<mac_age_mode_t>
+ {
+ const static mac_age_mode_t ON;
+ const static mac_age_mode_t OFF;
+
+ private:
+ /**
+ * Private constructor taking the value and the string name
+ */
+ mac_age_mode_t(int v, const std::string& s);
+ };
+
+ /**
+ * Bridge Domain Learning mode
+ */
+ struct flood_mode_t : enum_base<flood_mode_t>
+ {
+ const static flood_mode_t ON;
+ const static flood_mode_t OFF;
+
+ private:
+ /**
+ * Private constructor taking the value and the string name
+ */
+ flood_mode_t(int v, const std::string& s);
+ };
+
+ /**
* The value of the defaultbridge domain
*/
const static uint32_t DEFAULT_TABLE = 0;
@@ -60,7 +105,10 @@
* Construct a new object matching the desried state
*/
bridge_domain(uint32_t id,
- const learning_mode_t& lmode = learning_mode_t::ON);
+ const learning_mode_t& lmode = learning_mode_t::ON,
+ const arp_term_mode_t& amode = arp_term_mode_t::ON,
+ const flood_mode_t& fmode = flood_mode_t::ON,
+ const mac_age_mode_t& mmode = mac_age_mode_t::OFF);
/**
* Copy Constructor
@@ -179,11 +227,26 @@
HW::item<uint32_t> m_id;
/**
- * The leanring mode of the bridge
+ * The learning mode of the bridge
*/
learning_mode_t m_learning_mode;
/**
+ * The ARP termination mode of the bridge
+ */
+ arp_term_mode_t m_arp_term_mode;
+
+ /**
+ * The flood mode of the bridge
+ */
+ flood_mode_t m_flood_mode;
+
+ /**
+ * The MAC aging mode of the bridge
+ */
+ mac_age_mode_t m_mac_age_mode;
+
+ /**
* A map of all interfaces key against the interface's name
*/
static singular_db<key_t, bridge_domain> m_db;
diff --git a/src/vpp-api/vom/bridge_domain_cmds.cpp b/src/vpp-api/vom/bridge_domain_cmds.cpp
index 498569f..d1d536f 100644
--- a/src/vpp-api/vom/bridge_domain_cmds.cpp
+++ b/src/vpp-api/vom/bridge_domain_cmds.cpp
@@ -20,9 +20,15 @@
namespace VOM {
namespace bridge_domain_cmds {
create_cmd::create_cmd(HW::item<uint32_t>& item,
- const bridge_domain::learning_mode_t& lmode)
+ const bridge_domain::learning_mode_t& lmode,
+ const bridge_domain::arp_term_mode_t& amode,
+ const bridge_domain::flood_mode_t& fmode,
+ const bridge_domain::mac_age_mode_t& mmode)
: rpc_cmd(item)
, m_learning_mode(lmode)
+ , m_arp_term_mode(amode)
+ , m_flood_mode(fmode)
+ , m_mac_age_mode(mmode)
{
}
@@ -39,12 +45,12 @@
auto& payload = req.get_request().get_payload();
payload.bd_id = m_hw_item.data();
- payload.flood = 1;
- payload.uu_flood = 1;
+ payload.flood = m_flood_mode.value();
+ payload.uu_flood = m_flood_mode.value();
payload.forward = 1;
payload.learn = m_learning_mode.value();
- payload.arp_term = 1;
- payload.mac_age = 0;
+ payload.arp_term = m_arp_term_mode.value();
+ payload.mac_age = m_mac_age_mode.value();
payload.is_add = 1;
VAPI_CALL(req.execute());
diff --git a/src/vpp-api/vom/bridge_domain_cmds.hpp b/src/vpp-api/vom/bridge_domain_cmds.hpp
index f263b32..0216236 100644
--- a/src/vpp-api/vom/bridge_domain_cmds.hpp
+++ b/src/vpp-api/vom/bridge_domain_cmds.hpp
@@ -35,7 +35,10 @@
* Constructor
*/
create_cmd(HW::item<uint32_t>& item,
- const bridge_domain::learning_mode_t& lmode);
+ const bridge_domain::learning_mode_t& lmode,
+ const bridge_domain::arp_term_mode_t& amode,
+ const bridge_domain::flood_mode_t& fmode,
+ const bridge_domain::mac_age_mode_t& mmode);
/**
* Issue the command to VPP/HW
@@ -56,6 +59,18 @@
* the learning mode for the bridge
*/
bridge_domain::learning_mode_t m_learning_mode;
+ /**
+ * the learning mode for the bridge
+ */
+ bridge_domain::arp_term_mode_t m_arp_term_mode;
+ /**
+ * the flood mode for the bridge
+ */
+ bridge_domain::flood_mode_t m_flood_mode;
+ /**
+ * the flood mode for the bridge
+ */
+ bridge_domain::mac_age_mode_t m_mac_age_mode;
};
/**
diff --git a/src/vpp-api/vom/gbp_endpoint.cpp b/src/vpp-api/vom/gbp_endpoint.cpp
index cd5d7e1..9762a91 100644
--- a/src/vpp-api/vom/gbp_endpoint.cpp
+++ b/src/vpp-api/vom/gbp_endpoint.cpp
@@ -25,48 +25,48 @@
gbp_endpoint::gbp_endpoint(const interface& itf,
const boost::asio::ip::address& ip_addr,
- epg_id_t epg_id)
+ const mac_address_t& mac,
+ const gbp_endpoint_group& epg)
: m_hw(false)
, m_itf(itf.singular())
- , m_ip_addr(ip_addr)
- , m_epg_id(epg_id)
+ , m_ip(ip_addr)
+ , m_mac(mac)
+ , m_epg(epg.singular())
{
}
gbp_endpoint::gbp_endpoint(const gbp_endpoint& gbpe)
: m_hw(gbpe.m_hw)
, m_itf(gbpe.m_itf)
- , m_ip_addr(gbpe.m_ip_addr)
- , m_epg_id(gbpe.m_epg_id)
+ , m_ip(gbpe.m_ip)
+ , m_mac(gbpe.m_mac)
+ , m_epg(gbpe.m_epg)
{
}
gbp_endpoint::~gbp_endpoint()
{
sweep();
-
- // not in the DB anymore.
m_db.release(key(), this);
}
const gbp_endpoint::key_t
gbp_endpoint::key() const
{
- return (std::make_pair(m_itf->key(), m_ip_addr));
+ return (std::make_pair(m_itf->key(), m_ip));
}
bool
gbp_endpoint::operator==(const gbp_endpoint& gbpe) const
{
- return ((key() == gbpe.key()) && (m_epg_id == gbpe.m_epg_id));
+ return ((key() == gbpe.key()) && (m_epg == gbpe.m_epg));
}
void
gbp_endpoint::sweep()
{
if (m_hw) {
- HW::enqueue(
- new gbp_endpoint_cmds::delete_cmd(m_hw, m_itf->handle(), m_ip_addr));
+ HW::enqueue(new gbp_endpoint_cmds::delete_cmd(m_hw, m_itf->handle(), m_ip));
}
HW::write();
}
@@ -75,8 +75,8 @@
gbp_endpoint::replay()
{
if (m_hw) {
- HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(),
- m_ip_addr, m_epg_id));
+ HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(), m_ip,
+ m_mac, m_epg->id()));
}
}
@@ -84,8 +84,8 @@
gbp_endpoint::to_string() const
{
std::ostringstream s;
- s << "gbp-endpoint:[" << m_itf->to_string() << ", " << m_ip_addr.to_string()
- << ", epg-id:" << m_epg_id << "]";
+ s << "gbp-endpoint:[" << m_itf->to_string() << ", " << m_ip.to_string()
+ << ", " << m_mac.to_string() << ", epg:" << m_epg->to_string() << "]";
return (s.str());
}
@@ -93,12 +93,9 @@
void
gbp_endpoint::update(const gbp_endpoint& r)
{
- /*
- * create the table if it is not yet created
- */
if (rc_t::OK != m_hw.rc()) {
- HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(),
- m_ip_addr, m_epg_id));
+ HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(), m_ip,
+ m_mac, m_epg->id()));
}
}
@@ -154,11 +151,14 @@
from_bytes(payload.endpoint.is_ip6, payload.endpoint.address);
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);
VOM_LOG(log_level_t::DEBUG) << "data: " << payload.endpoint.sw_if_index;
- if (itf) {
- gbp_endpoint gbpe(*itf, address, payload.endpoint.epg_id);
+ if (itf && epg) {
+ gbp_endpoint gbpe(*itf, address, mac, *epg);
OM::commit(key, gbpe);
VOM_LOG(log_level_t::DEBUG) << "read: " << gbpe.to_string();
diff --git a/src/vpp-api/vom/gbp_endpoint.hpp b/src/vpp-api/vom/gbp_endpoint.hpp
index 6ece4fa..f6466a6 100644
--- a/src/vpp-api/vom/gbp_endpoint.hpp
+++ b/src/vpp-api/vom/gbp_endpoint.hpp
@@ -18,19 +18,13 @@
#include <ostream>
+#include "vom/gbp_endpoint_group.hpp"
#include "vom/interface.hpp"
#include "vom/singular_db.hpp"
-#include "vom/types.hpp"
namespace VOM {
-
/**
- * EPG IDs are 32 bit integers
- */
-typedef uint32_t epg_id_t;
-
-/**
- * A entry in the ARP termination table of a Bridge Domain
+ * A GBP Enpoint (i.e. a VM)
*/
class gbp_endpoint : public object_base
{
@@ -45,7 +39,8 @@
*/
gbp_endpoint(const interface& itf,
const boost::asio::ip::address& ip_addr,
- epg_id_t epg_id);
+ const mac_address_t& mac,
+ const gbp_endpoint_group& epg);
/**
* Copy Construct
@@ -166,12 +161,17 @@
/**
* The IP address of the endpoint
*/
- boost::asio::ip::address m_ip_addr;
+ boost::asio::ip::address m_ip;
/**
- * The EPG ID
+ * The MAC address of the endpoint
*/
- epg_id_t m_epg_id;
+ mac_address_t m_mac;
+
+ /**
+ * The EPG the endpoint is in
+ */
+ std::shared_ptr<gbp_endpoint_group> m_epg;
/**
* A map of all bridge_domains
diff --git a/src/vpp-api/vom/gbp_endpoint_cmds.cpp b/src/vpp-api/vom/gbp_endpoint_cmds.cpp
index 4f85b7e..88d2f37 100644
--- a/src/vpp-api/vom/gbp_endpoint_cmds.cpp
+++ b/src/vpp-api/vom/gbp_endpoint_cmds.cpp
@@ -23,10 +23,12 @@
create_cmd::create_cmd(HW::item<bool>& item,
const handle_t& itf,
const boost::asio::ip::address& ip_addr,
+ const mac_address_t& mac,
epg_id_t epg_id)
: rpc_cmd(item)
, m_itf(itf)
, m_ip_addr(ip_addr)
+ , m_mac(mac)
, m_epg_id(epg_id)
{
}
@@ -35,7 +37,7 @@
create_cmd::operator==(const create_cmd& other) const
{
return ((m_itf == other.m_itf) && (m_ip_addr == other.m_ip_addr) &&
- (m_epg_id == other.m_epg_id));
+ (m_mac == other.m_mac) && (m_epg_id == other.m_epg_id));
}
rc_t
@@ -48,6 +50,7 @@
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);
VAPI_CALL(req.execute());
diff --git a/src/vpp-api/vom/gbp_endpoint_cmds.hpp b/src/vpp-api/vom/gbp_endpoint_cmds.hpp
index cc78849..2893ef5 100644
--- a/src/vpp-api/vom/gbp_endpoint_cmds.hpp
+++ b/src/vpp-api/vom/gbp_endpoint_cmds.hpp
@@ -37,6 +37,7 @@
create_cmd(HW::item<bool>& item,
const handle_t& itf,
const boost::asio::ip::address& ip_addr,
+ const mac_address_t& mac,
epg_id_t epg_id);
/**
@@ -57,6 +58,7 @@
private:
const handle_t m_itf;
const boost::asio::ip::address m_ip_addr;
+ const mac_address_t m_mac;
const epg_id_t m_epg_id;
};
diff --git a/src/vpp-api/vom/gbp_endpoint_group.cpp b/src/vpp-api/vom/gbp_endpoint_group.cpp
new file mode 100644
index 0000000..d9f0d38
--- /dev/null
+++ b/src/vpp-api/vom/gbp_endpoint_group.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "vom/gbp_endpoint_group.hpp"
+#include "vom/gbp_endpoint_group_cmds.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+singular_db<gbp_endpoint_group::key_t, gbp_endpoint_group>
+ gbp_endpoint_group::m_db;
+
+gbp_endpoint_group::event_handler gbp_endpoint_group::m_evh;
+
+gbp_endpoint_group::gbp_endpoint_group(epg_id_t epg_id,
+ const interface& itf,
+ const route_domain& rd,
+ const bridge_domain& bd)
+ : m_hw(false)
+ , m_epg_id(epg_id)
+ , m_itf(itf.singular())
+ , m_rd(rd.singular())
+ , m_bd(bd.singular())
+{
+}
+
+gbp_endpoint_group::gbp_endpoint_group(const gbp_endpoint_group& epg)
+ : m_hw(epg.m_hw)
+ , m_epg_id(epg.m_epg_id)
+ , m_itf(epg.m_itf)
+ , m_rd(epg.m_rd)
+ , m_bd(epg.m_bd)
+{
+}
+
+gbp_endpoint_group::~gbp_endpoint_group()
+{
+ sweep();
+ m_db.release(key(), this);
+}
+
+const gbp_endpoint_group::key_t
+gbp_endpoint_group::key() const
+{
+ return (m_epg_id);
+}
+
+epg_id_t
+gbp_endpoint_group::id() const
+{
+ return (m_epg_id);
+}
+
+bool
+gbp_endpoint_group::operator==(const gbp_endpoint_group& gbpe) const
+{
+ return (key() == gbpe.key() && (m_itf == gbpe.m_itf) && (m_rd == gbpe.m_rd) &&
+ (m_bd == gbpe.m_bd));
+}
+
+void
+gbp_endpoint_group::sweep()
+{
+ if (m_hw) {
+ HW::enqueue(new gbp_endpoint_group_cmds::delete_cmd(m_hw, m_epg_id));
+ }
+ HW::write();
+}
+
+void
+gbp_endpoint_group::replay()
+{
+ if (m_hw) {
+ HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
+ m_hw, m_epg_id, m_bd->id(), m_rd->table_id(), m_itf->handle()));
+ }
+}
+
+std::string
+gbp_endpoint_group::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-endpoint-group:["
+ << "epg:" << m_epg_id << ", " << m_itf->to_string() << ", "
+ << m_bd->to_string() << ", " << m_rd->to_string() << "]";
+
+ return (s.str());
+}
+
+void
+gbp_endpoint_group::update(const gbp_endpoint_group& r)
+{
+ if (rc_t::OK != m_hw.rc()) {
+ HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
+ m_hw, m_epg_id, m_bd->id(), m_rd->table_id(), m_itf->handle()));
+ }
+}
+
+std::shared_ptr<gbp_endpoint_group>
+gbp_endpoint_group::find_or_add(const gbp_endpoint_group& temp)
+{
+ return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<gbp_endpoint_group>
+gbp_endpoint_group::find(const key_t& k)
+{
+ return (m_db.find(k));
+}
+
+std::shared_ptr<gbp_endpoint_group>
+gbp_endpoint_group::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_endpoint_group::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+gbp_endpoint_group::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "gbp-endpoint-group" }, "GBP Endpoint_Groups",
+ this);
+}
+
+void
+gbp_endpoint_group::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+void
+gbp_endpoint_group::event_handler::handle_populate(const client_db::key_t& key)
+{
+ std::shared_ptr<gbp_endpoint_group_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_endpoint_group_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ std::shared_ptr<interface> itf =
+ interface::find(payload.epg.uplink_sw_if_index);
+ std::shared_ptr<route_domain> rd =
+ route_domain::find(payload.epg.ip4_table_id);
+ std::shared_ptr<bridge_domain> bd = bridge_domain::find(payload.epg.bd_id);
+
+ VOM_LOG(log_level_t::DEBUG) << "data: [" << payload.epg.uplink_sw_if_index
+ << ", " << payload.epg.ip4_table_id << ", "
+ << payload.epg.bd_id << "]";
+
+ if (itf && bd && rd) {
+ gbp_endpoint_group gbpe(payload.epg.epg_id, *itf, *rd, *bd);
+ OM::commit(key, gbpe);
+
+ VOM_LOG(log_level_t::DEBUG) << "read: " << gbpe.to_string();
+ }
+ }
+}
+
+dependency_t
+gbp_endpoint_group::event_handler::order() const
+{
+ return (dependency_t::ACL);
+}
+
+void
+gbp_endpoint_group::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+} // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/src/vpp-api/vom/gbp_endpoint_group.hpp b/src/vpp-api/vom/gbp_endpoint_group.hpp
new file mode 100644
index 0000000..f7c900f
--- /dev/null
+++ b/src/vpp-api/vom/gbp_endpoint_group.hpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VOM_GBP_ENDPOINT_GROUP_H__
+#define __VOM_GBP_ENDPOINT_GROUP_H__
+
+#include "vom/interface.hpp"
+#include "vom/singular_db.hpp"
+#include "vom/types.hpp"
+
+#include "vom/bridge_domain.hpp"
+#include "vom/route_domain.hpp"
+
+namespace VOM {
+
+/**
+ * EPG IDs are 32 bit integers
+ */
+typedef uint32_t epg_id_t;
+
+/**
+ * A entry in the ARP termination table of a Bridge Domain
+ */
+class gbp_endpoint_group : public object_base
+{
+public:
+ /**
+ * The key for a GBP endpoint group is its ID
+ */
+ typedef epg_id_t key_t;
+
+ /**
+ * Construct a GBP endpoint_group
+ */
+ gbp_endpoint_group(epg_id_t epg_id,
+ const interface& itf,
+ const route_domain& rd,
+ const bridge_domain& bd);
+
+ /**
+ * Copy Construct
+ */
+ gbp_endpoint_group(const gbp_endpoint_group& r);
+
+ /**
+ * Destructor
+ */
+ ~gbp_endpoint_group();
+
+ /**
+ * Return the object's key
+ */
+ const key_t key() const;
+
+ /**
+ * comparison operator
+ */
+ bool operator==(const gbp_endpoint_group& bdae) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<gbp_endpoint_group> singular() const;
+
+ /**
+ * Find the instnace of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_endpoint_group> find(const key_t& k);
+
+ /**
+ * Dump all bridge_domain-doamin into the stream provided
+ */
+ static void dump(std::ostream& os);
+
+ /**
+ * replay the object to create it in hardware
+ */
+ void replay(void);
+
+ /**
+ * Convert to string for debugging
+ */
+ std::string to_string() const;
+
+ /**
+ * Get the ID of the EPG
+ */
+ epg_id_t id() const;
+
+private:
+ /**
+ * Class definition for listeners to OM events
+ */
+ class event_handler : public OM::listener, public inspect::command_handler
+ {
+ public:
+ event_handler();
+ virtual ~event_handler() = default;
+
+ /**
+ * Handle a populate event
+ */
+ void handle_populate(const client_db::key_t& key);
+
+ /**
+ * Handle a replay event
+ */
+ void handle_replay();
+
+ /**
+ * Show the object in the Singular DB
+ */
+ void show(std::ostream& os);
+
+ /**
+ * Get the sortable Id of the listener
+ */
+ dependency_t order() const;
+ };
+
+ /**
+ * event_handler to register with OM
+ */
+ static event_handler m_evh;
+
+ /**
+ * Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
+ */
+ void update(const gbp_endpoint_group& obj);
+
+ /**
+ * Find or add the instnace of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_endpoint_group> find_or_add(
+ const gbp_endpoint_group& temp);
+
+ /*
+ * It's the VPPHW class that updates the objects in HW
+ */
+ friend class OM;
+
+ /**
+ * It's the singular_db class that calls replay()
+ */
+ friend class singular_db<key_t, gbp_endpoint_group>;
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * HW configuration for the result of creating the endpoint_group
+ */
+ HW::item<bool> m_hw;
+
+ /**
+ * The EPG ID
+ */
+ epg_id_t m_epg_id;
+
+ /**
+ * The uplink interface for the endpoint group
+ */
+ std::shared_ptr<interface> m_itf;
+
+ /**
+ * The route-domain the EPG uses
+ */
+ std::shared_ptr<route_domain> m_rd;
+
+ /**
+ * The bridge-domain the EPG uses
+ */
+ std::shared_ptr<bridge_domain> m_bd;
+
+ /**
+ * A map of all bridge_domains
+ */
+ static singular_db<key_t, gbp_endpoint_group> m_db;
+};
+
+}; // namespace
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/src/vpp-api/vom/gbp_endpoint_group_cmds.cpp b/src/vpp-api/vom/gbp_endpoint_group_cmds.cpp
new file mode 100644
index 0000000..55e81d3
--- /dev/null
+++ b/src/vpp-api/vom/gbp_endpoint_group_cmds.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "vom/gbp_endpoint_group_cmds.hpp"
+
+namespace VOM {
+namespace gbp_endpoint_group_cmds {
+
+create_cmd::create_cmd(HW::item<bool>& item,
+ epg_id_t epg_id,
+ uint32_t bd_id,
+ route::table_id_t rd_id,
+ const handle_t& itf)
+ : rpc_cmd(item)
+ , m_epg_id(epg_id)
+ , m_bd_id(bd_id)
+ , m_rd_id(rd_id)
+ , m_itf(itf)
+{
+}
+
+bool
+create_cmd::operator==(const create_cmd& other) const
+{
+ return ((m_itf == other.m_itf) && (m_bd_id == other.m_bd_id) &&
+ (m_rd_id == other.m_rd_id) && (m_epg_id == other.m_epg_id));
+}
+
+rc_t
+create_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.is_add = 1;
+ payload.epg.uplink_sw_if_index = m_itf.value();
+ payload.epg.epg_id = m_epg_id;
+ payload.epg.bd_id = m_bd_id;
+ payload.epg.ip4_table_id = m_rd_id;
+ payload.epg.ip6_table_id = m_rd_id;
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return rc_t::OK;
+}
+
+std::string
+create_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-endpoint-group-create: " << m_hw_item.to_string()
+ << " epg-id:" << m_epg_id << " bd-id:" << m_bd_id << " rd-id:" << m_rd_id
+ << " itf:" << m_itf;
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<bool>& item, epg_id_t epg_id)
+ : rpc_cmd(item)
+ , m_epg_id(epg_id)
+{
+}
+
+bool
+delete_cmd::operator==(const delete_cmd& other) const
+{
+ return (m_epg_id == other.m_epg_id);
+}
+
+rc_t
+delete_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.is_add = 0;
+ payload.epg.epg_id = m_epg_id;
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return rc_t::OK;
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-endpoint-group-delete: " << m_hw_item.to_string()
+ << " epg:" << m_epg_id;
+
+ return (s.str());
+}
+
+dump_cmd::dump_cmd()
+{
+}
+
+bool
+dump_cmd::operator==(const dump_cmd& other) const
+{
+ return (true);
+}
+
+rc_t
+dump_cmd::issue(connection& con)
+{
+ m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
+
+ VAPI_CALL(m_dump->execute());
+
+ wait();
+
+ return rc_t::OK;
+}
+
+std::string
+dump_cmd::to_string() const
+{
+ return ("gbp-endpoint-group-dump");
+}
+
+}; // namespace gbp_endpoint_group_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/src/vpp-api/vom/gbp_endpoint_group_cmds.hpp b/src/vpp-api/vom/gbp_endpoint_group_cmds.hpp
new file mode 100644
index 0000000..4da3a42
--- /dev/null
+++ b/src/vpp-api/vom/gbp_endpoint_group_cmds.hpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VOM_GBP_ENDPOINT_GROUP_CMDS_H__
+#define __VOM_GBP_ENDPOINT_GROUP_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/gbp_endpoint_group.hpp"
+
+#include <vapi/gbp.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_endpoint_group_cmds {
+
+/**
+* A command class that creates or updates the GBP endpoint_group
+*/
+class create_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_endpoint_group_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_cmd(HW::item<bool>& item,
+ epg_id_t epg_id,
+ uint32_t bd_id,
+ route::table_id_t rd_id,
+ const handle_t& itf);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const create_cmd& i) const;
+
+private:
+ const epg_id_t m_epg_id;
+ const uint32_t m_bd_id;
+ const route::table_id_t m_rd_id;
+ const handle_t m_itf;
+};
+
+/**
+ * A cmd class that deletes a GBP endpoint_group
+ */
+class delete_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_endpoint_group_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<bool>& item, epg_id_t epg_id);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const delete_cmd& i) const;
+
+private:
+ const epg_id_t m_epg_id;
+};
+
+/**
+ * A cmd class that Dumps all the GBP endpoint_groups
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::Gbp_endpoint_group_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_cmd();
+ dump_cmd(const dump_cmd& d);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const dump_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+}; // namespace gbp_enpoint_cms
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/src/vpp-api/vom/gbp_recirc.cpp b/src/vpp-api/vom/gbp_recirc.cpp
new file mode 100644
index 0000000..250e304
--- /dev/null
+++ b/src/vpp-api/vom/gbp_recirc.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "vom/gbp_recirc.hpp"
+#include "vom/gbp_recirc_cmds.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+gbp_recirc::type_t::type_t(int v, const std::string s)
+ : enum_base<gbp_recirc::type_t>(v, s)
+{
+}
+
+const gbp_recirc::type_t gbp_recirc::type_t::INTERNAL(0, "internal");
+const gbp_recirc::type_t gbp_recirc::type_t::EXTERNAL(1, "external");
+
+singular_db<gbp_recirc::key_t, gbp_recirc> gbp_recirc::m_db;
+
+gbp_recirc::event_handler gbp_recirc::m_evh;
+
+gbp_recirc::gbp_recirc(const interface& itf,
+ const type_t& type,
+ const gbp_endpoint_group& epg)
+ : m_hw(false)
+ , m_itf(itf.singular())
+ , m_type(type)
+ , m_epg(epg.singular())
+{
+}
+
+gbp_recirc::gbp_recirc(const gbp_recirc& gbpe)
+ : m_hw(gbpe.m_hw)
+ , m_itf(gbpe.m_itf)
+ , m_type(gbpe.m_type)
+ , m_epg(gbpe.m_epg)
+{
+}
+
+gbp_recirc::~gbp_recirc()
+{
+ sweep();
+ m_db.release(key(), this);
+}
+
+const gbp_recirc::key_t
+gbp_recirc::key() const
+{
+ return (m_itf->key());
+}
+
+const handle_t&
+gbp_recirc::handle() const
+{
+ return m_itf->handle();
+}
+
+bool
+gbp_recirc::operator==(const gbp_recirc& gbpe) const
+{
+ return ((key() == gbpe.key()) && (m_type == gbpe.m_type) &&
+ (m_itf == gbpe.m_itf) && (m_epg == gbpe.m_epg));
+}
+
+void
+gbp_recirc::sweep()
+{
+ if (m_hw) {
+ HW::enqueue(new gbp_recirc_cmds::delete_cmd(m_hw, m_itf->handle()));
+ }
+ HW::write();
+}
+
+void
+gbp_recirc::replay()
+{
+ if (m_hw) {
+ HW::enqueue(new gbp_recirc_cmds::create_cmd(
+ m_hw, m_itf->handle(), (m_type == type_t::EXTERNAL), m_epg->id()));
+ }
+}
+
+std::string
+gbp_recirc::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-recirc:[" << m_itf->to_string() << ", type:" << m_type.to_string()
+ << ", " << m_epg->to_string() << "]";
+
+ return (s.str());
+}
+
+void
+gbp_recirc::update(const gbp_recirc& r)
+{
+ if (rc_t::OK != m_hw.rc()) {
+ HW::enqueue(new gbp_recirc_cmds::create_cmd(
+ m_hw, m_itf->handle(), (m_type == type_t::EXTERNAL), m_epg->id()));
+ }
+}
+
+std::shared_ptr<gbp_recirc>
+gbp_recirc::find_or_add(const gbp_recirc& temp)
+{
+ return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<gbp_recirc>
+gbp_recirc::find(const key_t& k)
+{
+ return (m_db.find(k));
+}
+
+std::shared_ptr<gbp_recirc>
+gbp_recirc::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_recirc::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+gbp_recirc::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "gbp-recirc" }, "GBP Recircs", this);
+}
+
+void
+gbp_recirc::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+void
+gbp_recirc::event_handler::handle_populate(const client_db::key_t& key)
+{
+ std::shared_ptr<gbp_recirc_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_recirc_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ std::shared_ptr<interface> itf =
+ interface::find(payload.recirc.sw_if_index);
+ std::shared_ptr<gbp_endpoint_group> epg =
+ gbp_endpoint_group::find(payload.recirc.epg_id);
+
+ VOM_LOG(log_level_t::DEBUG) << "data: [" << payload.recirc.sw_if_index
+ << ", " << payload.recirc.epg_id << "]";
+
+ if (itf && epg) {
+ gbp_recirc recirc(
+ *itf, (payload.recirc.is_ext ? type_t::EXTERNAL : type_t::INTERNAL),
+ *epg);
+ OM::commit(key, recirc);
+
+ VOM_LOG(log_level_t::DEBUG) << "read: " << recirc.to_string();
+ }
+ }
+}
+
+dependency_t
+gbp_recirc::event_handler::order() const
+{
+ return (dependency_t::BINDING);
+}
+
+void
+gbp_recirc::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+} // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/src/vpp-api/vom/gbp_recirc.hpp b/src/vpp-api/vom/gbp_recirc.hpp
new file mode 100644
index 0000000..fee4f6c
--- /dev/null
+++ b/src/vpp-api/vom/gbp_recirc.hpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VOM_GBP_RECIRC_H__
+#define __VOM_GBP_RECIRC_H__
+
+#include "vom/gbp_endpoint_group.hpp"
+#include "vom/interface.hpp"
+#include "vom/singular_db.hpp"
+
+namespace VOM {
+/**
+ * A recirculation interface for GBP use pre/post NAT
+ */
+class gbp_recirc : public object_base
+{
+public:
+ /**
+ * The key for a GBP recirc interface
+ */
+ typedef interface::key_t key_t;
+
+ struct type_t : public enum_base<type_t>
+ {
+ /**
+ * Internal recirclation interfaces accept per-NAT translation
+ * traffic from the external/NAT EPG and inject into the
+ * private/NAT-inside EPG
+ */
+ const static type_t INTERNAL;
+
+ /**
+ * External recirculation interfaces accept post-NAT translation
+ * traffic from the internal EPG and inject into the
+ * NAT EPG
+ */
+ const static type_t EXTERNAL;
+
+ private:
+ type_t(int v, const std::string s);
+ };
+
+ /**
+ * Construct a GBP recirc
+ */
+ gbp_recirc(const interface& itf,
+ const type_t& type,
+ const gbp_endpoint_group& epg);
+
+ /**
+ * Copy Construct
+ */
+ gbp_recirc(const gbp_recirc& r);
+
+ /**
+ * Destructor
+ */
+ ~gbp_recirc();
+
+ /**
+ * Return the object's key
+ */
+ const key_t key() const;
+
+ /**
+ * comparison operator
+ */
+ bool operator==(const gbp_recirc& bdae) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<gbp_recirc> singular() const;
+
+ /**
+ * Find the instnace of the recirc interface in the OM
+ */
+ static std::shared_ptr<gbp_recirc> find(const key_t& k);
+
+ /**
+ * Dump all bridge_domain-doamin into the stream provided
+ */
+ static void dump(std::ostream& os);
+
+ /**
+ * replay the object to create it in hardware
+ */
+ void replay(void);
+
+ /**
+ * Convert to string for debugging
+ */
+ std::string to_string() const;
+
+ /**
+ * return the recirculation interface's handle
+ */
+ const handle_t& handle() const;
+
+private:
+ /**
+ * Class definition for listeners to OM events
+ */
+ class event_handler : public OM::listener, public inspect::command_handler
+ {
+ public:
+ event_handler();
+ virtual ~event_handler() = default;
+
+ /**
+ * Handle a populate event
+ */
+ void handle_populate(const client_db::key_t& key);
+
+ /**
+ * Handle a replay event
+ */
+ void handle_replay();
+
+ /**
+ * Show the object in the Singular DB
+ */
+ void show(std::ostream& os);
+
+ /**
+ * Get the sortable Id of the listener
+ */
+ dependency_t order() const;
+ };
+
+ /**
+ * event_handler to register with OM
+ */
+ static event_handler m_evh;
+
+ /**
+ * Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
+ */
+ void update(const gbp_recirc& obj);
+
+ /**
+ * Find or add the instnace of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_recirc> find_or_add(const gbp_recirc& temp);
+
+ /*
+ * It's the VPPHW class that updates the objects in HW
+ */
+ friend class OM;
+
+ /**
+ * It's the singular_db class that calls replay()
+ */
+ friend class singular_db<key_t, gbp_recirc>;
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * HW configuration for the result of creating the recirc
+ */
+ HW::item<bool> m_hw;
+
+ /**
+ * The interface the recirc is attached to.
+ */
+ std::shared_ptr<interface> m_itf;
+
+ /**
+ * Is the reicrc for the external (i.e. post-NAT) or internal
+ */
+ type_t m_type;
+
+ /**
+ * The EPG the recirc is in
+ */
+ std::shared_ptr<gbp_endpoint_group> m_epg;
+
+ /**
+ * A map of all bridge_domains
+ */
+ static singular_db<key_t, gbp_recirc> m_db;
+};
+
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/src/vpp-api/vom/gbp_recirc_cmds.cpp b/src/vpp-api/vom/gbp_recirc_cmds.cpp
new file mode 100644
index 0000000..757fcb9
--- /dev/null
+++ b/src/vpp-api/vom/gbp_recirc_cmds.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "vom/gbp_recirc_cmds.hpp"
+
+namespace VOM {
+namespace gbp_recirc_cmds {
+
+create_cmd::create_cmd(HW::item<bool>& item,
+ const handle_t& itf,
+ bool is_ext,
+ epg_id_t epg_id)
+ : rpc_cmd(item)
+ , m_itf(itf)
+ , m_is_ext(is_ext)
+ , m_epg_id(epg_id)
+{
+}
+
+bool
+create_cmd::operator==(const create_cmd& other) const
+{
+ return ((m_itf == other.m_itf) && (m_is_ext == other.m_is_ext) &&
+ (m_epg_id == other.m_epg_id));
+}
+
+rc_t
+create_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.is_add = 1;
+ payload.recirc.sw_if_index = m_itf.value();
+ payload.recirc.epg_id = m_epg_id;
+ payload.recirc.is_ext = m_is_ext;
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return rc_t::OK;
+}
+
+std::string
+create_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-recirc-create: " << m_hw_item.to_string() << " itf:" << m_itf
+ << " ext:" << m_is_ext << " epg-id:" << m_epg_id;
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<bool>& item, const handle_t& itf)
+ : rpc_cmd(item)
+ , m_itf(itf)
+{
+}
+
+bool
+delete_cmd::operator==(const delete_cmd& other) const
+{
+ return (m_itf == other.m_itf);
+}
+
+rc_t
+delete_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.is_add = 0;
+ payload.recirc.sw_if_index = m_itf.value();
+ payload.recirc.epg_id = ~0;
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return rc_t::OK;
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-recirc-delete: " << m_hw_item.to_string() << " itf:" << m_itf;
+
+ return (s.str());
+}
+
+dump_cmd::dump_cmd()
+{
+}
+
+bool
+dump_cmd::operator==(const dump_cmd& other) const
+{
+ return (true);
+}
+
+rc_t
+dump_cmd::issue(connection& con)
+{
+ m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
+
+ VAPI_CALL(m_dump->execute());
+
+ wait();
+
+ return rc_t::OK;
+}
+
+std::string
+dump_cmd::to_string() const
+{
+ return ("gbp-recirc-dump");
+}
+
+}; // namespace gbp_recirc_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/src/vpp-api/vom/gbp_recirc_cmds.hpp b/src/vpp-api/vom/gbp_recirc_cmds.hpp
new file mode 100644
index 0000000..fe17834
--- /dev/null
+++ b/src/vpp-api/vom/gbp_recirc_cmds.hpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VOM_GBP_RECIRC_CMDS_H__
+#define __VOM_GBP_RECIRC_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/gbp_recirc.hpp"
+
+#include <vapi/gbp.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_recirc_cmds {
+
+/**
+* A command class that creates or updates the GBP recirc
+*/
+class create_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_recirc_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_cmd(HW::item<bool>& item,
+ const handle_t& itf,
+ bool is_ext,
+ epg_id_t epg_id);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const create_cmd& i) const;
+
+private:
+ const handle_t m_itf;
+ bool m_is_ext;
+ const epg_id_t m_epg_id;
+};
+
+/**
+ * A cmd class that deletes a GBP recirc
+ */
+class delete_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_recirc_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<bool>& item, const handle_t& itf);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const delete_cmd& i) const;
+
+private:
+ const handle_t m_itf;
+};
+
+/**
+ * A cmd class that Dumps all the GBP recircs
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::Gbp_recirc_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_cmd();
+ dump_cmd(const dump_cmd& d);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const dump_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+}; // namespace gbp_enpoint_cms
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/src/vpp-api/vom/gbp_subnet.cpp b/src/vpp-api/vom/gbp_subnet.cpp
new file mode 100644
index 0000000..84dbd22
--- /dev/null
+++ b/src/vpp-api/vom/gbp_subnet.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "vom/gbp_subnet.hpp"
+#include "vom/gbp_subnet_cmds.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+gbp_subnet::type_t::type_t(int v, const std::string s)
+ : enum_base<gbp_subnet::type_t>(v, s)
+{
+}
+
+const gbp_subnet::type_t gbp_subnet::type_t::INTERNAL(0, "internal");
+const gbp_subnet::type_t gbp_subnet::type_t::EXTERNAL(1, "external");
+
+singular_db<gbp_subnet::key_t, gbp_subnet> gbp_subnet::m_db;
+
+gbp_subnet::event_handler gbp_subnet::m_evh;
+
+gbp_subnet::gbp_subnet(const route_domain& rd, const route::prefix_t& prefix)
+ : m_hw(false)
+ , m_rd(rd.singular())
+ , m_prefix(prefix)
+ , m_type(type_t::INTERNAL)
+ , m_recirc(nullptr)
+ , m_epg(nullptr)
+{
+}
+
+gbp_subnet::gbp_subnet(const route_domain& rd,
+ const route::prefix_t& prefix,
+ const gbp_recirc& recirc,
+ const gbp_endpoint_group& epg)
+ : m_hw(false)
+ , m_rd(rd.singular())
+ , m_prefix(prefix)
+ , m_type(type_t::EXTERNAL)
+ , m_recirc(recirc.singular())
+ , m_epg(epg.singular())
+{
+}
+
+gbp_subnet::gbp_subnet(const gbp_subnet& o)
+ : m_hw(o.m_hw)
+ , m_rd(o.m_rd)
+ , m_prefix(o.m_prefix)
+ , m_type(o.m_type)
+ , m_recirc(o.m_recirc)
+ , m_epg(o.m_epg)
+{
+}
+
+gbp_subnet::~gbp_subnet()
+{
+ sweep();
+ m_db.release(key(), this);
+}
+
+const gbp_subnet::key_t
+gbp_subnet::key() const
+{
+ return (std::make_pair(m_rd->key(), m_prefix));
+}
+
+bool
+gbp_subnet::operator==(const gbp_subnet& gbpe) const
+{
+ return ((key() == gbpe.key()) && (m_recirc == gbpe.m_recirc) &&
+ (m_epg == gbpe.m_epg));
+}
+
+void
+gbp_subnet::sweep()
+{
+ if (m_hw) {
+ HW::enqueue(
+ new gbp_subnet_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix));
+ }
+ HW::write();
+}
+
+void
+gbp_subnet::replay()
+{
+ if (m_hw) {
+ HW::enqueue(new gbp_subnet_cmds::create_cmd(
+ m_hw, m_rd->table_id(), m_prefix, (m_type == type_t::INTERNAL),
+ (m_recirc ? m_recirc->handle() : handle_t::INVALID),
+ (m_epg ? m_epg->id() : ~0)));
+ }
+}
+
+std::string
+gbp_subnet::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-subnet:[" << m_type.to_string() << ", " << m_rd->to_string() << ":"
+ << m_prefix.to_string();
+ if (m_recirc)
+ s << ", " << m_recirc->to_string();
+ if (m_epg)
+ s << ", " << m_epg->to_string();
+
+ s << "]";
+
+ return (s.str());
+}
+
+void
+gbp_subnet::update(const gbp_subnet& r)
+{
+ if (rc_t::OK != m_hw.rc()) {
+ HW::enqueue(new gbp_subnet_cmds::create_cmd(
+ m_hw, m_rd->table_id(), m_prefix, (m_type == type_t::INTERNAL),
+ (m_recirc ? m_recirc->handle() : handle_t::INVALID),
+ (m_epg ? m_epg->id() : ~0)));
+ }
+}
+
+std::shared_ptr<gbp_subnet>
+gbp_subnet::find_or_add(const gbp_subnet& temp)
+{
+ return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<gbp_subnet>
+gbp_subnet::find(const key_t& k)
+{
+ return (m_db.find(k));
+}
+
+std::shared_ptr<gbp_subnet>
+gbp_subnet::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_subnet::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+gbp_subnet::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "gbp-subnet" }, "GBP Subnets", this);
+}
+
+void
+gbp_subnet::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+void
+gbp_subnet::event_handler::handle_populate(const client_db::key_t& key)
+{
+ std::shared_ptr<gbp_subnet_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_subnet_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ route::prefix_t pfx(payload.subnet.is_ip6, payload.subnet.address,
+ payload.subnet.address_length);
+ std::shared_ptr<route_domain> rd =
+ route_domain::find(payload.subnet.table_id);
+
+ if (rd) {
+ if (payload.subnet.is_internal) {
+ gbp_subnet gs(*rd, pfx);
+ OM::commit(key, gs);
+ VOM_LOG(log_level_t::DEBUG) << "read: " << gs.to_string();
+ } else {
+ std::shared_ptr<interface> itf =
+ interface::find(payload.subnet.sw_if_index);
+ std::shared_ptr<gbp_endpoint_group> epg =
+ gbp_endpoint_group::find(payload.subnet.epg_id);
+
+ if (itf && epg) {
+ std::shared_ptr<gbp_recirc> recirc = gbp_recirc::find(itf->key());
+
+ if (recirc) {
+ gbp_subnet gs(*rd, pfx, *recirc, *epg);
+ OM::commit(key, gs);
+ VOM_LOG(log_level_t::DEBUG) << "read: " << gs.to_string();
+ }
+ }
+ }
+ }
+ }
+}
+
+dependency_t
+gbp_subnet::event_handler::order() const
+{
+ return (dependency_t::ENTRY);
+}
+
+void
+gbp_subnet::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+} // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/src/vpp-api/vom/gbp_subnet.hpp b/src/vpp-api/vom/gbp_subnet.hpp
new file mode 100644
index 0000000..9c9166e
--- /dev/null
+++ b/src/vpp-api/vom/gbp_subnet.hpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VOM_GBP_SUBNET_H__
+#define __VOM_GBP_SUBNET_H__
+
+#include "vom/gbp_endpoint_group.hpp"
+#include "vom/gbp_recirc.hpp"
+#include "vom/route.hpp"
+#include "vom/singular_db.hpp"
+
+namespace VOM {
+/**
+ * A GBP Enpoint (i.e. a VM)
+ */
+class gbp_subnet : public object_base
+{
+public:
+ /**
+ * The key for a GBP subnet; table and prefix
+ */
+ typedef std::pair<route_domain::key_t, route::prefix_t> key_t;
+
+ /**
+ * Construct an internal GBP subnet
+ */
+ gbp_subnet(const route_domain& rd, const route::prefix_t& prefix);
+
+ /**
+ * Construct an external GBP subnet
+ */
+ gbp_subnet(const route_domain& rd,
+ const route::prefix_t& prefix,
+ const gbp_recirc& recirc,
+ const gbp_endpoint_group& epg);
+
+ /**
+ * Copy Construct
+ */
+ gbp_subnet(const gbp_subnet& r);
+
+ /**
+ * Destructor
+ */
+ ~gbp_subnet();
+
+ /**
+ * Return the object's key
+ */
+ const key_t key() const;
+
+ /**
+ * comparison operator
+ */
+ bool operator==(const gbp_subnet& bdae) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<gbp_subnet> singular() const;
+
+ /**
+ * Find the instnace of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_subnet> find(const key_t& k);
+
+ /**
+ * Dump all bridge_domain-doamin into the stream provided
+ */
+ static void dump(std::ostream& os);
+
+ /**
+ * replay the object to create it in hardware
+ */
+ void replay(void);
+
+ /**
+ * Convert to string for debugging
+ */
+ std::string to_string() const;
+
+private:
+ struct type_t : public enum_base<type_t>
+ {
+ /**
+ * Internal subnet is reachable through the source EPG's
+ * uplink interface.
+ */
+ const static type_t INTERNAL;
+
+ /**
+ * External subnet requires NAT translation before egress.
+ */
+ const static type_t EXTERNAL;
+
+ private:
+ type_t(int v, const std::string s);
+ };
+
+ /**
+ * Class definition for listeners to OM events
+ */
+ class event_handler : public OM::listener, public inspect::command_handler
+ {
+ public:
+ event_handler();
+ virtual ~event_handler() = default;
+
+ /**
+ * Handle a populate event
+ */
+ void handle_populate(const client_db::key_t& key);
+
+ /**
+ * Handle a replay event
+ */
+ void handle_replay();
+
+ /**
+ * Show the object in the Singular DB
+ */
+ void show(std::ostream& os);
+
+ /**
+ * Get the sortable Id of the listener
+ */
+ dependency_t order() const;
+ };
+
+ /**
+ * event_handler to register with OM
+ */
+ static event_handler m_evh;
+
+ /**
+ * Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
+ */
+ void update(const gbp_subnet& obj);
+
+ /**
+ * Find or add the instnace of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_subnet> find_or_add(const gbp_subnet& temp);
+
+ /*
+ * It's the VPPHW class that updates the objects in HW
+ */
+ friend class OM;
+
+ /**
+ * It's the singular_db class that calls replay()
+ */
+ friend class singular_db<key_t, gbp_subnet>;
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * HW configuration for the result of creating the subnet
+ */
+ HW::item<bool> m_hw;
+
+ /**
+ * the route domain the prefix is in
+ */
+ std::shared_ptr<route_domain> m_rd;
+
+ /**
+ * prefix to match
+ */
+ const route::prefix_t m_prefix;
+
+ /*
+ * Subnet type
+ */
+ const type_t m_type;
+
+ /**
+ * The interface the prefix is reachable through
+ */
+ std::shared_ptr<gbp_recirc> m_recirc;
+
+ /**
+ * The EPG the subnet is in
+ */
+ std::shared_ptr<gbp_endpoint_group> m_epg;
+
+ /**
+ * A map of all bridge_domains
+ */
+ static singular_db<key_t, gbp_subnet> m_db;
+};
+
+}; // namespace
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/src/vpp-api/vom/gbp_subnet_cmds.cpp b/src/vpp-api/vom/gbp_subnet_cmds.cpp
new file mode 100644
index 0000000..d087e5c
--- /dev/null
+++ b/src/vpp-api/vom/gbp_subnet_cmds.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "vom/gbp_subnet_cmds.hpp"
+
+namespace VOM {
+namespace gbp_subnet_cmds {
+
+create_cmd::create_cmd(HW::item<bool>& item,
+ route::table_id_t rd,
+ const route::prefix_t& prefix,
+ bool internal,
+ const handle_t& itf,
+ epg_id_t epg_id)
+ : rpc_cmd(item)
+ , m_rd(rd)
+ , m_prefix(prefix)
+ , m_internal(internal)
+ , m_itf(itf)
+ , m_epg_id(epg_id)
+{
+}
+
+bool
+create_cmd::operator==(const create_cmd& other) const
+{
+ return ((m_itf == other.m_itf) && (m_rd == other.m_rd) &&
+ (m_prefix == other.m_prefix) && (m_itf == other.m_itf) &&
+ (m_epg_id == other.m_epg_id));
+}
+
+rc_t
+create_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.is_add = 1;
+ payload.subnet.is_internal = m_internal;
+ 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);
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return rc_t::OK;
+}
+
+std::string
+create_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-subnet-create: " << m_hw_item.to_string()
+ << "internal:" << m_internal << ", " << m_rd << ":" << m_prefix.to_string()
+ << " itf:" << m_itf << " epg-id:" << m_epg_id;
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<bool>& item,
+ route::table_id_t rd,
+ const route::prefix_t& prefix)
+ : rpc_cmd(item)
+ , m_rd(rd)
+ , m_prefix(prefix)
+{
+}
+
+bool
+delete_cmd::operator==(const delete_cmd& other) const
+{
+ return ((m_rd == other.m_rd) && (m_prefix == other.m_prefix));
+}
+
+rc_t
+delete_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ 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.is_internal = 0;
+ payload.subnet.sw_if_index = ~0;
+ payload.subnet.epg_id = ~0;
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return rc_t::OK;
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-subnet-delete: " << m_hw_item.to_string() << ", " << m_rd << ":"
+ << m_prefix.to_string();
+
+ return (s.str());
+}
+
+dump_cmd::dump_cmd()
+{
+}
+
+bool
+dump_cmd::operator==(const dump_cmd& other) const
+{
+ return (true);
+}
+
+rc_t
+dump_cmd::issue(connection& con)
+{
+ m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
+
+ VAPI_CALL(m_dump->execute());
+
+ wait();
+
+ return rc_t::OK;
+}
+
+std::string
+dump_cmd::to_string() const
+{
+ return ("gbp-subnet-dump");
+}
+
+}; // namespace gbp_subnet_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/src/vpp-api/vom/gbp_subnet_cmds.hpp b/src/vpp-api/vom/gbp_subnet_cmds.hpp
new file mode 100644
index 0000000..3dbc8db
--- /dev/null
+++ b/src/vpp-api/vom/gbp_subnet_cmds.hpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VOM_GBP_SUBNET_CMDS_H__
+#define __VOM_GBP_SUBNET_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/gbp_subnet.hpp"
+
+#include <vapi/gbp.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_subnet_cmds {
+
+/**
+* A command class that creates or updates the GBP subnet
+*/
+class create_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_subnet_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_cmd(HW::item<bool>& item,
+ route::table_id_t rd,
+ const route::prefix_t& prefix,
+ bool internal,
+ const handle_t& itf,
+ epg_id_t epg_id);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const create_cmd& i) const;
+
+private:
+ const route::table_id_t m_rd;
+ const route::prefix_t m_prefix;
+ const bool m_internal;
+ const handle_t m_itf;
+ const epg_id_t m_epg_id;
+};
+
+/**
+ * A cmd class that deletes a GBP subnet
+ */
+class delete_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_subnet_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<bool>& item,
+ route::table_id_t rd,
+ const route::prefix_t& prefix);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const delete_cmd& i) const;
+
+private:
+ const route::table_id_t m_rd;
+ const route::prefix_t m_prefix;
+};
+
+/**
+ * A cmd class that Dumps all the GBP subnets
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::Gbp_subnet_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_cmd();
+ dump_cmd(const dump_cmd& d);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const dump_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+}; // namespace gbp_enpoint_cms
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/src/vpp-api/vom/interface.cpp b/src/vpp-api/vom/interface.cpp
index e9b7a1a..6faf349 100644
--- a/src/vpp-api/vom/interface.cpp
+++ b/src/vpp-api/vom/interface.cpp
@@ -275,9 +275,7 @@
std::queue<cmd*>&
interface::mk_create_cmd(std::queue<cmd*>& q)
{
- if (type_t::LOOPBACK == m_type) {
- q.push(new interface_cmds::loopback_create_cmd(m_hdl, m_name));
- } else if (type_t::BVI == m_type) {
+ if ((type_t::LOOPBACK == m_type) || (type_t::BVI == m_type)) {
q.push(new interface_cmds::loopback_create_cmd(m_hdl, m_name));
q.push(new interface_cmds::set_tag(m_hdl, m_name));
/*
@@ -516,8 +514,12 @@
HW::write();
for (auto& itf_record : *cmd) {
- std::shared_ptr<interface> itf =
- interface_factory::new_interface(itf_record.get_payload());
+ auto payload = itf_record.get_payload();
+ VOM_LOG(log_level_t::DEBUG) << "dump: [" << payload.sw_if_index
+ << " name:" << (char*)payload.interface_name
+ << " tag:" << (char*)payload.tag << "]";
+
+ std::shared_ptr<interface> itf = interface_factory::new_interface(payload);
if (itf && interface::type_t::LOCAL != itf->type()) {
VOM_LOG(log_level_t::DEBUG) << "dump: " << itf->to_string();
diff --git a/src/vpp-api/vom/interface_types.cpp b/src/vpp-api/vom/interface_types.cpp
index 911282d..139bdd5 100644
--- a/src/vpp-api/vom/interface_types.cpp
+++ b/src/vpp-api/vom/interface_types.cpp
@@ -51,7 +51,8 @@
return interface::type_t::ETHERNET;
} else if (str.find("vxlan") != std::string::npos) {
return interface::type_t::VXLAN;
- } else if (str.find("loop") != std::string::npos) {
+ } else if ((str.find("loop") != std::string::npos) ||
+ (str.find("recirc") != std::string::npos)) {
return interface::type_t::LOOPBACK;
} else if (str.find("host-") != std::string::npos) {
return interface::type_t::AFPACKET;
diff --git a/src/vpp-api/vom/nat_binding_cmds.hpp b/src/vpp-api/vom/nat_binding_cmds.hpp
index bb94048..1b51192 100644
--- a/src/vpp-api/vom/nat_binding_cmds.hpp
+++ b/src/vpp-api/vom/nat_binding_cmds.hpp
@@ -255,6 +255,238 @@
HW::item<bool> item;
};
+/////
+/**
+* A functor class that binds a NAT configuration to an input interface
+*/
+class bind_66_input_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Nat66_add_del_interface>
+{
+public:
+ /**
+ * Constructor
+ */
+ bind_66_input_cmd(HW::item<bool>& item,
+ const handle_t& itf,
+ const nat_binding::zone_t& zone);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const bind_66_input_cmd& i) const;
+
+private:
+ /**
+ * The interface to bind
+ */
+ const handle_t m_itf;
+
+ /**
+ * The zone the interface is in
+ */
+ const nat_binding::zone_t m_zone;
+};
+
+/**
+ * A cmd class that unbinds a NAT configuration from an input interface
+ */
+class unbind_66_input_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Nat66_add_del_interface>
+{
+public:
+ /**
+ * Constructor
+ */
+ unbind_66_input_cmd(HW::item<bool>& item,
+ const handle_t& itf,
+ const nat_binding::zone_t& zone);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const unbind_66_input_cmd& i) const;
+
+private:
+ /**
+ * The interface to bind
+ */
+ const handle_t m_itf;
+
+ /**
+ * The zone the interface is in
+ */
+ const nat_binding::zone_t m_zone;
+};
+
+/**
+ * A functor class that binds a NAT configuration to an output interface
+ */
+/* class bind_66_output_cmd */
+/* : public rpc_cmd<HW::item<bool>, */
+/* rc_t, */
+/* vapi::Nat66_interface_add_del_output_feature> */
+/* { */
+/* public: */
+/* /\** */
+/* * Constructor */
+/* *\/ */
+/* bind_66_output_cmd(HW::item<bool>& item, */
+/* const handle_t& itf, */
+/* const nat_binding::zone_t& zone); */
+
+/* /\** */
+/* * Issue the command to VPP/HW */
+/* *\/ */
+/* rc_t issue(connection& con); */
+/* /\** */
+/* * convert to string format for debug purposes */
+/* *\/ */
+/* std::string to_string() const; */
+
+/* /\** */
+/* * Comparison operator - only used for UT */
+/* *\/ */
+/* bool operator==(const bind_66_output_cmd& i) const; */
+
+/* private: */
+/* /\** */
+/* * The interface to bind */
+/* *\/ */
+/* const handle_t m_itf; */
+
+/* /\** */
+/* * The zone the interface is in */
+/* *\/ */
+/* const nat_binding::zone_t m_zone; */
+/* }; */
+
+/* /\** */
+/* * A cmd class that unbinds a NAT configuration from an output interface */
+/* *\/ */
+/* class unbind_66_output_cmd */
+/* : public rpc_cmd<HW::item<bool>, */
+/* rc_t, */
+/* vapi::Nat66_interface_add_del_output_feature> */
+/* { */
+/* public: */
+/* /\** */
+/* * Constructor */
+/* *\/ */
+/* unbind_66_output_cmd(HW::item<bool>& item, */
+/* const handle_t& itf, */
+/* const nat_binding::zone_t& zone); */
+
+/* /\** */
+/* * Issue the command to VPP/HW */
+/* *\/ */
+/* rc_t issue(connection& con); */
+/* /\** */
+/* * convert to string format for debug purposes */
+/* *\/ */
+/* std::string to_string() const; */
+
+/* /\** */
+/* * Comparison operator - only used for UT */
+/* *\/ */
+/* bool operator==(const unbind_66_output_cmd& i) const; */
+
+/* private: */
+/* /\** */
+/* * The interface to bind */
+/* *\/ */
+/* const handle_t m_itf; */
+
+/* /\** */
+/* * The zone the interface is in */
+/* *\/ */
+/* const nat_binding::zone_t m_zone; */
+/* }; */
+
+/**
+ * A cmd class that Dumps all the nat_statics
+ */
+class dump_input_66_cmd : public dump_cmd<vapi::Nat66_interface_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_input_66_cmd();
+ dump_input_66_cmd(const dump_input_66_cmd& d);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const dump_input_66_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+
+/**
+ * A cmd class that Dumps all the nat_statics
+ */
+/* class dump_output_66_cmd */
+/* : public dump_cmd<vapi::Nat66_interface_output_feature_dump> */
+/* { */
+/* public: */
+/* /\** */
+/* * Constructor */
+/* *\/ */
+/* dump_output_66_cmd(); */
+/* dump_output_66_cmd(const dump_output_66_cmd& d); */
+
+/* /\** */
+/* * Issue the command to VPP/HW */
+/* *\/ */
+/* rc_t issue(connection& con); */
+/* /\** */
+/* * convert to string format for debug purposes */
+/* *\/ */
+/* std::string to_string() const; */
+
+/* /\** */
+/* * Comparison operator - only used for UT */
+/* *\/ */
+/* bool operator==(const dump_output_66_cmd& i) const; */
+
+/* private: */
+/* /\** */
+/* * HW reutrn code */
+/* *\/ */
+/* HW::item<bool> item; */
+/* }; */
+
}; // namespace nat_binding_cmds
}; // namespace VOM
diff --git a/src/vpp-api/vom/nat_static.cpp b/src/vpp-api/vom/nat_static.cpp
index 3185b56..bf8573d 100644
--- a/src/vpp-api/vom/nat_static.cpp
+++ b/src/vpp-api/vom/nat_static.cpp
@@ -22,7 +22,7 @@
nat_static::event_handler nat_static::m_evh;
nat_static::nat_static(const boost::asio::ip::address& inside,
- const boost::asio::ip::address_v4& outside)
+ const boost::asio::ip::address& outside)
: m_hw(false)
, m_rd(route_domain::get_default())
, m_inside(inside)
@@ -32,7 +32,7 @@
nat_static::nat_static(const route_domain& rd,
const boost::asio::ip::address& inside,
- const boost::asio::ip::address_v4& outside)
+ const boost::asio::ip::address& outside)
: m_hw(false)
, m_rd(rd.singular())
, m_inside(inside)
@@ -74,7 +74,10 @@
if (m_hw) {
if (m_inside.is_v4()) {
HW::enqueue(new nat_static_cmds::delete_44_cmd(
- m_hw, m_rd->table_id(), m_inside.to_v4(), m_outside));
+ m_hw, m_rd->table_id(), m_inside.to_v4(), m_outside.to_v4()));
+ } else {
+ HW::enqueue(new nat_static_cmds::delete_66_cmd(
+ m_hw, m_rd->table_id(), m_inside.to_v6(), m_outside.to_v6()));
}
}
HW::write();
@@ -86,7 +89,10 @@
if (m_hw) {
if (m_inside.is_v4()) {
HW::enqueue(new nat_static_cmds::create_44_cmd(
- m_hw, m_rd->table_id(), m_inside.to_v4(), m_outside));
+ m_hw, m_rd->table_id(), m_inside.to_v4(), m_outside.to_v4()));
+ } else {
+ HW::enqueue(new nat_static_cmds::create_66_cmd(
+ m_hw, m_rd->table_id(), m_inside.to_v6(), m_outside.to_v6()));
}
}
}
@@ -100,7 +106,10 @@
if (rc_t::OK != m_hw.rc()) {
if (m_inside.is_v4()) {
HW::enqueue(new nat_static_cmds::create_44_cmd(
- m_hw, m_rd->table_id(), m_inside.to_v4(), m_outside));
+ m_hw, m_rd->table_id(), m_inside.to_v4(), m_outside.to_v4()));
+ } else {
+ HW::enqueue(new nat_static_cmds::create_66_cmd(
+ m_hw, m_rd->table_id(), m_inside.to_v6(), m_outside.to_v6()));
}
}
}
@@ -158,20 +167,43 @@
/*
* dump VPP current states
*/
- std::shared_ptr<nat_static_cmds::dump_44_cmd> cmd =
+ std::shared_ptr<nat_static_cmds::dump_44_cmd> cmd44 =
std::make_shared<nat_static_cmds::dump_44_cmd>();
- HW::enqueue(cmd);
+ HW::enqueue(cmd44);
HW::write();
- for (auto& record : *cmd) {
+ for (auto& record : *cmd44) {
auto& payload = record.get_payload();
boost::asio::ip::address inside = from_bytes(0, payload.local_ip_address);
boost::asio::ip::address outside =
from_bytes(0, payload.external_ip_address);
- nat_static n(route_domain(payload.vrf_id), inside, outside.to_v4());
+ nat_static n(route_domain(payload.vrf_id), inside, outside);
+
+ /*
+ * Write each of the discovered mappings into the OM,
+ * but disable the HW Command q whilst we do, so that no
+ * commands are sent to VPP
+ */
+ OM::commit(key, n);
+ }
+
+ std::shared_ptr<nat_static_cmds::dump_66_cmd> cmd66 =
+ std::make_shared<nat_static_cmds::dump_66_cmd>();
+
+ HW::enqueue(cmd66);
+ HW::write();
+
+ for (auto& record : *cmd66) {
+
+ auto& payload = record.get_payload();
+
+ boost::asio::ip::address inside = from_bytes(1, payload.local_ip_address);
+ boost::asio::ip::address outside =
+ from_bytes(1, payload.external_ip_address);
+ nat_static n(route_domain(payload.vrf_id), inside, outside);
/*
* Write each of the discovered mappings into the OM,
diff --git a/src/vpp-api/vom/nat_static.hpp b/src/vpp-api/vom/nat_static.hpp
index 3b0d2d0..2dcadb3 100644
--- a/src/vpp-api/vom/nat_static.hpp
+++ b/src/vpp-api/vom/nat_static.hpp
@@ -39,7 +39,7 @@
* table
*/
nat_static(const boost::asio::ip::address& inside,
- const boost::asio::ip::address_v4& outside);
+ const boost::asio::ip::address& outside);
/**
* Construct an NAT Static binding with the outside address in
@@ -47,7 +47,7 @@
*/
nat_static(const route_domain& rd,
const boost::asio::ip::address& inside,
- const boost::asio::ip::address_v4& outside);
+ const boost::asio::ip::address& outside);
/**
* Copy Construct
@@ -171,9 +171,9 @@
const boost::asio::ip::address m_inside;
/**
- * The 'outside' IP address - always v4
+ * The 'outside' IP address
*/
- const boost::asio::ip::address_v4 m_outside;
+ const boost::asio::ip::address m_outside;
/**
* A map of all NAT statics
diff --git a/src/vpp-api/vom/nat_static_cmds.cpp b/src/vpp-api/vom/nat_static_cmds.cpp
index facc7c6..a80e474 100644
--- a/src/vpp-api/vom/nat_static_cmds.cpp
+++ b/src/vpp-api/vom/nat_static_cmds.cpp
@@ -144,6 +144,125 @@
std::string
dump_44_cmd::to_string() const
{
+ return ("nat-44-static-dump");
+}
+
+create_66_cmd::create_66_cmd(HW::item<bool>& item,
+ route::table_id_t id,
+ const boost::asio::ip::address_v6& inside,
+ const boost::asio::ip::address_v6& outside)
+ : rpc_cmd(item)
+ , m_id(id)
+ , m_inside(inside)
+ , m_outside(outside)
+{
+}
+
+bool
+create_66_cmd::operator==(const create_66_cmd& other) const
+{
+ return ((m_id == other.m_id) && (m_inside == other.m_inside) &&
+ (m_outside == other.m_outside));
+}
+
+rc_t
+create_66_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.is_add = 1;
+ payload.vrf_id = m_id;
+ to_bytes(m_inside, payload.local_ip_address);
+ to_bytes(m_outside, payload.external_ip_address);
+
+ VAPI_CALL(req.execute());
+
+ m_hw_item.set(wait());
+
+ return rc_t::OK;
+}
+
+std::string
+create_66_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "nat-66-static-create: " << m_hw_item.to_string() << " table:" << m_id
+ << " inside:" << m_inside.to_string()
+ << " outside:" << m_outside.to_string();
+
+ return (s.str());
+}
+
+delete_66_cmd::delete_66_cmd(HW::item<bool>& item,
+ route::table_id_t id,
+ const boost::asio::ip::address_v6& inside,
+ const boost::asio::ip::address_v6& outside)
+ : rpc_cmd(item)
+ , m_id(id)
+ , m_inside(inside)
+ , m_outside(outside)
+{
+}
+
+bool
+delete_66_cmd::operator==(const delete_66_cmd& other) const
+{
+ return ((m_id == other.m_id) && (m_inside == other.m_inside) &&
+ (m_outside == other.m_outside));
+}
+
+rc_t
+delete_66_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.is_add = 0;
+ payload.vrf_id = m_id;
+ to_bytes(m_inside, payload.local_ip_address);
+ to_bytes(m_outside, payload.external_ip_address);
+
+ VAPI_CALL(req.execute());
+
+ wait();
+ m_hw_item.set(rc_t::NOOP);
+
+ return rc_t::OK;
+}
+
+std::string
+delete_66_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "nat-66-static-delete: " << m_hw_item.to_string() << " table:" << m_id
+ << " inside:" << m_inside.to_string()
+ << " outside:" << m_outside.to_string();
+
+ return (s.str());
+}
+
+bool
+dump_66_cmd::operator==(const dump_66_cmd& other) const
+{
+ return (true);
+}
+
+rc_t
+dump_66_cmd::issue(connection& con)
+{
+ m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
+
+ VAPI_CALL(m_dump->execute());
+
+ wait();
+
+ return rc_t::OK;
+}
+
+std::string
+dump_66_cmd::to_string() const
+{
return ("nat-static-dump");
}
diff --git a/src/vpp-api/vom/nat_static_cmds.hpp b/src/vpp-api/vom/nat_static_cmds.hpp
index a4adcef..95061ca 100644
--- a/src/vpp-api/vom/nat_static_cmds.hpp
+++ b/src/vpp-api/vom/nat_static_cmds.hpp
@@ -129,6 +129,111 @@
HW::item<bool> item;
};
+/**
+ * A command class that creates NAT 66 static mapping
+ */
+class create_66_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Nat66_add_del_static_mapping>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_66_cmd(HW::item<bool>& item,
+ route::table_id_t id,
+ const boost::asio::ip::address_v6& inside,
+ const boost::asio::ip::address_v6& outside);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const create_66_cmd& i) const;
+
+private:
+ route::table_id_t m_id;
+ const boost::asio::ip::address_v6 m_inside;
+ const boost::asio::ip::address_v6 m_outside;
+};
+
+/**
+ * A cmd class that deletes a NAT 66 static mapping
+ */
+class delete_66_cmd
+ : public rpc_cmd<HW::item<bool>, rc_t, vapi::Nat66_add_del_static_mapping>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_66_cmd(HW::item<bool>& item,
+ route::table_id_t id,
+ const boost::asio::ip::address_v6& inside,
+ const boost::asio::ip::address_v6& outside);
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const delete_66_cmd& i) const;
+
+private:
+ route::table_id_t m_id;
+ const boost::asio::ip::address_v6 m_inside;
+ const boost::asio::ip::address_v6 m_outside;
+};
+
+/**
+ * A cmd class that Dumps all the nat_statics
+ */
+class dump_66_cmd : public dump_cmd<vapi::Nat66_static_mapping_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_66_cmd() = default;
+ ~dump_66_cmd() = default;
+
+ /**
+ * Issue the command to VPP/HW
+ */
+ rc_t issue(connection& con);
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator - only used for UT
+ */
+ bool operator==(const dump_66_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+
}; // namespace nat_static_cmds
}; // namespace vom
diff --git a/src/vpp-api/vom/route.cpp b/src/vpp-api/vom/route.cpp
index 247afa0..ec56c44 100644
--- a/src/vpp-api/vom/route.cpp
+++ b/src/vpp-api/vom/route.cpp
@@ -508,7 +508,7 @@
dependency_t
ip_route::event_handler::order() const
{
- return (dependency_t::ENTRY);
+ return (dependency_t::TABLE);
}
void
diff --git a/src/vpp-api/vom/types.cpp b/src/vpp-api/vom/types.cpp
index 44e0dd0..c6093eb 100644
--- a/src/vpp-api/vom/types.cpp
+++ b/src/vpp-api/vom/types.cpp
@@ -28,9 +28,6 @@
: enum_base<rc_t>(v, s)
{
}
-rc_t::~rc_t()
-{
-}
const rc_t&
rc_t::from_vpp_retval(int32_t rv)
diff --git a/src/vpp-api/vom/types.hpp b/src/vpp-api/vom/types.hpp
index 302e5ee..53654c5 100644
--- a/src/vpp-api/vom/types.hpp
+++ b/src/vpp-api/vom/types.hpp
@@ -94,7 +94,7 @@
/**
* Destructor
*/
- ~rc_t();
+ ~rc_t() = default;
/**
* The value un-set