aboutsummaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
authorNeale Ranns <neale.ranns@cisco.com>2018-10-10 07:22:51 -0700
committerDamjan Marion <dmarion@me.com>2018-11-07 12:00:10 +0000
commit93cc3ee3b3a9c9224a1446625882205f3282a949 (patch)
tree077421ee51238c22181a3b3f4871b648bb1299d3 /extras
parentc3df1e9a0ab79c1fe254394748ef441ffe224c43 (diff)
GBP Endpoint Learning
Learning GBP endpoints over vxlan-gbp tunnels Change-Id: I1db9fda5a16802d9ad8b4efd4e475614f3b21502 Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
Diffstat (limited to 'extras')
-rw-r--r--extras/vom/vom/CMakeLists.txt18
-rw-r--r--extras/vom/vom/gbp_bridge_domain.cpp232
-rw-r--r--extras/vom/vom/gbp_bridge_domain.hpp183
-rw-r--r--extras/vom/vom/gbp_bridge_domain_cmds.cpp133
-rw-r--r--extras/vom/vom/gbp_bridge_domain_cmds.hpp131
-rw-r--r--extras/vom/vom/gbp_contract_cmds.hpp2
-rw-r--r--extras/vom/vom/gbp_endpoint_group.cpp23
-rw-r--r--extras/vom/vom/gbp_endpoint_group.hpp15
-rw-r--r--extras/vom/vom/gbp_endpoint_group_cmds.cpp7
-rw-r--r--extras/vom/vom/gbp_endpoint_group_cmds.hpp6
-rw-r--r--extras/vom/vom/gbp_route_domain.cpp232
-rw-r--r--extras/vom/vom/gbp_route_domain.hpp183
-rw-r--r--extras/vom/vom/gbp_route_domain_cmds.cpp135
-rw-r--r--extras/vom/vom/gbp_route_domain_cmds.hpp131
-rw-r--r--extras/vom/vom/gbp_subnet.cpp85
-rw-r--r--extras/vom/vom/gbp_subnet.hpp59
-rw-r--r--extras/vom/vom/gbp_subnet_cmds.cpp37
-rw-r--r--extras/vom/vom/gbp_subnet_cmds.hpp4
-rw-r--r--extras/vom/vom/gbp_vxlan.cpp231
-rw-r--r--extras/vom/vom/gbp_vxlan.hpp186
-rw-r--r--extras/vom/vom/gbp_vxlan_cmds.cpp137
-rw-r--r--extras/vom/vom/gbp_vxlan_cmds.hpp135
-rw-r--r--extras/vom/vom/gbp_vxlan_tunnel.cpp186
-rw-r--r--extras/vom/vom/interface_factory.cpp4
24 files changed, 2392 insertions, 103 deletions
diff --git a/extras/vom/vom/CMakeLists.txt b/extras/vom/vom/CMakeLists.txt
index 5a5e5a7df0e..a2c35addb05 100644
--- a/extras/vom/vom/CMakeLists.txt
+++ b/extras/vom/vom/CMakeLists.txt
@@ -68,16 +68,22 @@ endif()
if(GBP_FILE)
list(APPEND VOM_SOURCES
- gbp_recirc_cmds.cpp
- gbp_recirc.cpp
- gbp_subnet_cmds.cpp
- gbp_subnet.cpp
+ gbp_contract_cmds.cpp
+ gbp_contract.cpp
+ gbp_bridge_domain_cmds.cpp
+ gbp_bridge_domain.cpp
gbp_endpoint_cmds.cpp
gbp_endpoint.cpp
gbp_endpoint_group_cmds.cpp
gbp_endpoint_group.cpp
- gbp_contract_cmds.cpp
- gbp_contract.cpp
+ gbp_recirc_cmds.cpp
+ gbp_recirc.cpp
+ gbp_route_domain_cmds.cpp
+ gbp_route_domain.cpp
+ gbp_subnet_cmds.cpp
+ gbp_subnet.cpp
+ gbp_vxlan.cpp
+ gbp_vxlan_cmds.cpp
)
endif()
diff --git a/extras/vom/vom/gbp_bridge_domain.cpp b/extras/vom/vom/gbp_bridge_domain.cpp
new file mode 100644
index 00000000000..6cad1954e5d
--- /dev/null
+++ b/extras/vom/vom/gbp_bridge_domain.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_bridge_domain.hpp"
+#include "vom/gbp_bridge_domain_cmds.hpp"
+#include "vom/interface.hpp"
+#include "vom/l2_binding.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+/**
+ * A DB of al the interfaces, key on the name
+ */
+singular_db<uint32_t, gbp_bridge_domain> gbp_bridge_domain::m_db;
+
+gbp_bridge_domain::event_handler gbp_bridge_domain::m_evh;
+
+/**
+ * Construct a new object matching the desried state
+ */
+gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd)
+ : m_id(bd.id())
+ , m_bd(bd.singular())
+{
+}
+
+gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
+ const interface& bvi,
+ const interface& uu_fwd)
+ : m_id(bd.id())
+ , m_bd(bd.singular())
+ , m_bvi(bvi.singular())
+ , m_uu_fwd(uu_fwd.singular())
+{
+}
+
+gbp_bridge_domain::gbp_bridge_domain(const gbp_bridge_domain& bd)
+ : m_id(bd.id())
+ , m_bd(bd.m_bd)
+{
+}
+
+const gbp_bridge_domain::key_t
+gbp_bridge_domain::key() const
+{
+ return (m_bd->key());
+}
+
+uint32_t
+gbp_bridge_domain::id() const
+{
+ return (m_bd->id());
+}
+
+bool
+gbp_bridge_domain::operator==(const gbp_bridge_domain& b) const
+{
+ bool equal = true;
+
+ if (m_bvi && b.m_bvi)
+ equal &= (m_bvi->key() == b.m_bvi->key());
+ else if (!m_bvi && !b.m_bvi)
+ ;
+ else
+ equal = false;
+
+ if (m_uu_fwd && b.m_uu_fwd)
+ equal &= (m_uu_fwd->key() == b.m_uu_fwd->key());
+ else if (!m_uu_fwd && !b.m_uu_fwd)
+ ;
+ else
+ equal = false;
+
+ return ((m_bd->key() == b.m_bd->key()) && equal);
+}
+
+void
+gbp_bridge_domain::sweep()
+{
+ if (rc_t::OK == m_id.rc()) {
+ HW::enqueue(new gbp_bridge_domain_cmds::delete_cmd(m_id));
+ }
+ HW::write();
+}
+
+void
+gbp_bridge_domain::replay()
+{
+ if (rc_t::OK == m_id.rc()) {
+ if (m_bvi && m_uu_fwd)
+ HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(m_id, m_bvi->handle(),
+ m_uu_fwd->handle()));
+ else
+ HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(
+ m_id, handle_t::INVALID, handle_t::INVALID));
+ }
+}
+
+gbp_bridge_domain::~gbp_bridge_domain()
+{
+ sweep();
+
+ // not in the DB anymore.
+ m_db.release(m_id.data(), this);
+}
+
+std::string
+gbp_bridge_domain::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-bridge-domain:[" << m_bd->to_string() << "]";
+
+ return (s.str());
+}
+
+std::shared_ptr<gbp_bridge_domain>
+gbp_bridge_domain::find(const key_t& key)
+{
+ return (m_db.find(key));
+}
+
+void
+gbp_bridge_domain::update(const gbp_bridge_domain& desired)
+{
+ /*
+ * the desired state is always that the interface should be created
+ */
+ if (rc_t::OK != m_id.rc()) {
+ if (m_bvi && m_uu_fwd)
+ HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(m_id, m_bvi->handle(),
+ m_uu_fwd->handle()));
+ else
+ HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(
+ m_id, handle_t::INVALID, handle_t::INVALID));
+ }
+}
+
+std::shared_ptr<gbp_bridge_domain>
+gbp_bridge_domain::find_or_add(const gbp_bridge_domain& temp)
+{
+ return (m_db.find_or_add(temp.m_id.data(), temp));
+}
+
+std::shared_ptr<gbp_bridge_domain>
+gbp_bridge_domain::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_bridge_domain::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+void
+gbp_bridge_domain::event_handler::handle_populate(const client_db::key_t& key)
+{
+ /*
+ * dump VPP Bridge domains
+ */
+ std::shared_ptr<gbp_bridge_domain_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_bridge_domain_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ std::shared_ptr<interface> uu_fwd =
+ interface::find(payload.bd.uu_fwd_sw_if_index);
+ std::shared_ptr<interface> bvi =
+ interface::find(payload.bd.bvi_sw_if_index);
+
+ if (uu_fwd && bvi) {
+ gbp_bridge_domain bd(payload.bd.bd_id, *bvi, *uu_fwd);
+ OM::commit(key, bd);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << bd.to_string();
+ } else {
+ gbp_bridge_domain bd(payload.bd.bd_id);
+ OM::commit(key, bd);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << bd.to_string();
+ }
+ }
+}
+
+gbp_bridge_domain::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "gbd", "gbridge" }, "GBP Bridge Domains", this);
+}
+
+void
+gbp_bridge_domain::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+dependency_t
+gbp_bridge_domain::event_handler::order() const
+{
+ return (dependency_t::TABLE);
+}
+
+void
+gbp_bridge_domain::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_bridge_domain.hpp b/extras/vom/vom/gbp_bridge_domain.hpp
new file mode 100644
index 00000000000..0d7d58ecc05
--- /dev/null
+++ b/extras/vom/vom/gbp_bridge_domain.hpp
@@ -0,0 +1,183 @@
+/*
+ * 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_BRIDGE_DOMAIN_H__
+#define __VOM_GBP_BRIDGE_DOMAIN_H__
+
+#include "vom/bridge_domain.hpp"
+#include "vom/interface.hpp"
+#include "vom/singular_db.hpp"
+#include "vom/types.hpp"
+
+namespace VOM {
+
+/**
+ * A entry in the ARP termination table of a Bridge Domain
+ */
+class gbp_bridge_domain : public object_base
+{
+public:
+ /**
+ * The key for a bridge_domain is the pari of EPG-IDs
+ */
+ typedef bridge_domain::key_t key_t;
+
+ /**
+ * Construct a GBP bridge_domain
+ */
+ gbp_bridge_domain(const bridge_domain& bd);
+
+ gbp_bridge_domain(const bridge_domain& bd,
+ const interface& bvi,
+ const interface& uu_fwd);
+
+ /**
+ * Copy Construct
+ */
+ gbp_bridge_domain(const gbp_bridge_domain& r);
+
+ /**
+ * Destructor
+ */
+ ~gbp_bridge_domain();
+
+ /**
+ * Return the object's key
+ */
+ const key_t key() const;
+
+ /**
+ * Return the bridge domain's VPP ID
+ */
+ uint32_t id() const;
+
+ /**
+ * comparison operator
+ */
+ bool operator==(const gbp_bridge_domain& bdae) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<gbp_bridge_domain> singular() const;
+
+ /**
+ * Find the instnace of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_bridge_domain> 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:
+ /**
+ * 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_bridge_domain& obj);
+
+ /**
+ * Find or add the instance of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_bridge_domain> find_or_add(
+ const gbp_bridge_domain& 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_bridge_domain>;
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * HW configuration for the result of creating the endpoint
+ */
+ HW::item<uint32_t> m_id;
+
+ std::shared_ptr<bridge_domain> m_bd;
+ std::shared_ptr<interface> m_bvi;
+ std::shared_ptr<interface> m_uu_fwd;
+
+ /**
+ * A map of all bridge_domains
+ */
+ static singular_db<key_t, gbp_bridge_domain> m_db;
+};
+
+}; // namespace
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_bridge_domain_cmds.cpp b/extras/vom/vom/gbp_bridge_domain_cmds.cpp
new file mode 100644
index 00000000000..60f7cddd9f3
--- /dev/null
+++ b/extras/vom/vom/gbp_bridge_domain_cmds.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_bridge_domain_cmds.hpp"
+
+namespace VOM {
+namespace gbp_bridge_domain_cmds {
+
+create_cmd::create_cmd(HW::item<uint32_t>& item,
+ const handle_t bvi,
+ const handle_t uu_fwd)
+ : rpc_cmd(item)
+ , m_bvi(bvi)
+ , m_uu_fwd(uu_fwd)
+{
+}
+
+bool
+create_cmd::operator==(const create_cmd& other) const
+{
+ return ((m_hw_item.data() == other.m_hw_item.data()) &&
+ (m_bvi == other.m_bvi) && (m_uu_fwd == other.m_uu_fwd));
+}
+
+rc_t
+create_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+
+ payload.bd.bd_id = m_hw_item.data();
+ payload.bd.bvi_sw_if_index = m_bvi.value();
+ payload.bd.uu_fwd_sw_if_index = m_uu_fwd.value();
+
+ VAPI_CALL(req.execute());
+
+ return (wait());
+}
+
+std::string
+create_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-bridge-domain: " << m_hw_item.to_string()
+ << " bvi:" << m_bvi.to_string() << " uu-fwd:" << m_uu_fwd.to_string();
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<uint32_t>& item)
+ : rpc_cmd(item)
+{
+}
+
+bool
+delete_cmd::operator==(const delete_cmd& other) const
+{
+ return (m_hw_item.data() == other.m_hw_item.data());
+}
+
+rc_t
+delete_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+
+ payload.bd_id = m_hw_item.data();
+
+ VAPI_CALL(req.execute());
+
+ wait();
+ m_hw_item.set(rc_t::NOOP);
+
+ return rc_t::OK;
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-bridge-domain: " << m_hw_item.to_string();
+
+ return (s.str());
+}
+
+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-bridge-domain-dump");
+}
+
+}; // namespace gbp_bridge_domain_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_bridge_domain_cmds.hpp b/extras/vom/vom/gbp_bridge_domain_cmds.hpp
new file mode 100644
index 00000000000..e7c501fc598
--- /dev/null
+++ b/extras/vom/vom/gbp_bridge_domain_cmds.hpp
@@ -0,0 +1,131 @@
+/*
+ * 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_BRIDGE_DOMAIN_CMDS_H__
+#define __VOM_GBP_BRIDGE_DOMAIN_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/gbp_bridge_domain.hpp"
+#include "vom/rpc_cmd.hpp"
+
+#include <vapi/gbp.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_bridge_domain_cmds {
+/**
+ * A command class that creates an Bridge-Domain
+ */
+class create_cmd
+ : public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_bridge_domain_add>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_cmd(HW::item<uint32_t>& item,
+ const handle_t bvi,
+ const handle_t uu_fwd);
+
+ /**
+ * 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_bvi;
+ const handle_t m_uu_fwd;
+};
+
+/**
+ * A cmd class that Delete an Bridge-Domain
+ */
+class delete_cmd
+ : public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_bridge_domain_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<uint32_t>& item);
+
+ /**
+ * 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;
+};
+
+/**
+ * A cmd class that Dumps all the bridge domains
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::Gbp_bridge_domain_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_cmd() = default;
+ dump_cmd(const dump_cmd& d) = 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_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+
+}; // gbp_bridge_domain_cmds
+}; // VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_contract_cmds.hpp b/extras/vom/vom/gbp_contract_cmds.hpp
index 31b9a00ed14..7e4447663fd 100644
--- a/extras/vom/vom/gbp_contract_cmds.hpp
+++ b/extras/vom/vom/gbp_contract_cmds.hpp
@@ -91,7 +91,7 @@ private:
};
/**
- * A cmd class that Dumps all the GBP endpoints
+ * A cmd class that Dumps all the GBP contracts
*/
class dump_cmd : public VOM::dump_cmd<vapi::Gbp_contract_dump>
{
diff --git a/extras/vom/vom/gbp_endpoint_group.cpp b/extras/vom/vom/gbp_endpoint_group.cpp
index d9f0d38d594..bd68d77a064 100644
--- a/extras/vom/vom/gbp_endpoint_group.cpp
+++ b/extras/vom/vom/gbp_endpoint_group.cpp
@@ -26,8 +26,8 @@ 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)
+ const gbp_route_domain& rd,
+ const gbp_bridge_domain& bd)
: m_hw(false)
, m_epg_id(epg_id)
, m_itf(itf.singular())
@@ -64,10 +64,10 @@ gbp_endpoint_group::id() const
}
bool
-gbp_endpoint_group::operator==(const gbp_endpoint_group& gbpe) const
+gbp_endpoint_group::operator==(const gbp_endpoint_group& gg) const
{
- return (key() == gbpe.key() && (m_itf == gbpe.m_itf) && (m_rd == gbpe.m_rd) &&
- (m_bd == gbpe.m_bd));
+ return (key() == gg.key() && (m_itf == gg.m_itf) && (m_rd == gg.m_rd) &&
+ (m_bd == gg.m_bd));
}
void
@@ -84,7 +84,7 @@ gbp_endpoint_group::replay()
{
if (m_hw) {
HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
- m_hw, m_epg_id, m_bd->id(), m_rd->table_id(), m_itf->handle()));
+ m_hw, m_epg_id, m_bd->id(), m_rd->id(), m_itf->handle()));
}
}
@@ -104,7 +104,7 @@ gbp_endpoint_group::update(const gbp_endpoint_group& r)
{
if (rc_t::OK != m_hw.rc()) {
HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
- m_hw, m_epg_id, m_bd->id(), m_rd->table_id(), m_itf->handle()));
+ m_hw, m_epg_id, m_bd->id(), m_rd->id(), m_itf->handle()));
}
}
@@ -159,12 +159,13 @@ gbp_endpoint_group::event_handler::handle_populate(const client_db::key_t& key)
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);
+ std::shared_ptr<gbp_route_domain> rd =
+ gbp_route_domain::find(payload.epg.rd_id);
+ std::shared_ptr<gbp_bridge_domain> bd =
+ gbp_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.rd_id << ", "
<< payload.epg.bd_id << "]";
if (itf && bd && rd) {
diff --git a/extras/vom/vom/gbp_endpoint_group.hpp b/extras/vom/vom/gbp_endpoint_group.hpp
index f7c900f20be..d609b89fe2f 100644
--- a/extras/vom/vom/gbp_endpoint_group.hpp
+++ b/extras/vom/vom/gbp_endpoint_group.hpp
@@ -20,8 +20,8 @@
#include "vom/singular_db.hpp"
#include "vom/types.hpp"
-#include "vom/bridge_domain.hpp"
-#include "vom/route_domain.hpp"
+#include "vom/gbp_bridge_domain.hpp"
+#include "vom/gbp_route_domain.hpp"
namespace VOM {
@@ -46,8 +46,11 @@ public:
*/
gbp_endpoint_group(epg_id_t epg_id,
const interface& itf,
- const route_domain& rd,
- const bridge_domain& bd);
+ const gbp_route_domain& rd,
+ const gbp_bridge_domain& bd);
+ gbp_endpoint_group(epg_id_t epg_id,
+ const gbp_route_domain& rd,
+ const gbp_bridge_domain& bd);
/**
* Copy Construct
@@ -179,12 +182,12 @@ private:
/**
* The route-domain the EPG uses
*/
- std::shared_ptr<route_domain> m_rd;
+ std::shared_ptr<gbp_route_domain> m_rd;
/**
* The bridge-domain the EPG uses
*/
- std::shared_ptr<bridge_domain> m_bd;
+ std::shared_ptr<gbp_bridge_domain> m_bd;
/**
* A map of all bridge_domains
diff --git a/extras/vom/vom/gbp_endpoint_group_cmds.cpp b/extras/vom/vom/gbp_endpoint_group_cmds.cpp
index a7b46f8a80b..45523a6326e 100644
--- a/extras/vom/vom/gbp_endpoint_group_cmds.cpp
+++ b/extras/vom/vom/gbp_endpoint_group_cmds.cpp
@@ -44,12 +44,10 @@ 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;
+ payload.epg.rd_id = m_rd_id;
VAPI_CALL(req.execute());
@@ -85,8 +83,7 @@ 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;
+ payload.epg_id = m_epg_id;
VAPI_CALL(req.execute());
diff --git a/extras/vom/vom/gbp_endpoint_group_cmds.hpp b/extras/vom/vom/gbp_endpoint_group_cmds.hpp
index 4cf88cff116..39f69e081ef 100644
--- a/extras/vom/vom/gbp_endpoint_group_cmds.hpp
+++ b/extras/vom/vom/gbp_endpoint_group_cmds.hpp
@@ -27,8 +27,7 @@ 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>, vapi::Gbp_endpoint_group_add_del>
+class create_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_group_add>
{
public:
/**
@@ -65,8 +64,7 @@ private:
/**
* A cmd class that deletes a GBP endpoint_group
*/
-class delete_cmd
- : public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_group_add_del>
+class delete_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_group_del>
{
public:
/**
diff --git a/extras/vom/vom/gbp_route_domain.cpp b/extras/vom/vom/gbp_route_domain.cpp
new file mode 100644
index 00000000000..2786297b0c8
--- /dev/null
+++ b/extras/vom/vom/gbp_route_domain.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_route_domain.hpp"
+#include "vom/gbp_route_domain_cmds.hpp"
+#include "vom/interface.hpp"
+#include "vom/l2_binding.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+/**
+ * A DB of al the interfaces, key on the name
+ */
+singular_db<uint32_t, gbp_route_domain> gbp_route_domain::m_db;
+
+gbp_route_domain::event_handler gbp_route_domain::m_evh;
+
+/**
+ * Construct a new object matching the desried state
+ */
+gbp_route_domain::gbp_route_domain(const gbp_route_domain& rd)
+ : m_id(rd.id())
+ , m_rd(rd.m_rd)
+{
+}
+
+gbp_route_domain::gbp_route_domain(const route_domain& rd,
+ const interface& ip4_uu_fwd,
+ const interface& ip6_uu_fwd)
+ : m_id(rd.table_id())
+ , m_rd(rd.singular())
+ , m_ip4_uu_fwd(ip4_uu_fwd.singular())
+ , m_ip6_uu_fwd(ip6_uu_fwd.singular())
+{
+}
+
+gbp_route_domain::gbp_route_domain(const route_domain& rd)
+ : m_id(rd.table_id())
+ , m_rd(rd.singular())
+{
+}
+
+const gbp_route_domain::key_t
+gbp_route_domain::key() const
+{
+ return (m_rd->key());
+}
+
+uint32_t
+gbp_route_domain::id() const
+{
+ return (m_rd->table_id());
+}
+
+bool
+gbp_route_domain::operator==(const gbp_route_domain& b) const
+{
+ bool equal = true;
+
+ if (m_ip4_uu_fwd && b.m_ip4_uu_fwd)
+ equal &= (m_ip4_uu_fwd->key() == b.m_ip4_uu_fwd->key());
+ else if (!m_ip4_uu_fwd && !b.m_ip4_uu_fwd)
+ ;
+ else
+ equal = false;
+
+ if (m_ip6_uu_fwd && b.m_ip6_uu_fwd)
+ equal &= (m_ip6_uu_fwd->key() == b.m_ip6_uu_fwd->key());
+ else if (!m_ip6_uu_fwd && !b.m_ip6_uu_fwd)
+ ;
+ else
+ equal = false;
+
+ return ((m_rd->key() == b.m_rd->key()) && equal);
+}
+
+void
+gbp_route_domain::sweep()
+{
+ if (rc_t::OK == m_id.rc()) {
+ HW::enqueue(new gbp_route_domain_cmds::delete_cmd(m_id));
+ }
+ HW::write();
+}
+
+void
+gbp_route_domain::replay()
+{
+ if (rc_t::OK == m_id.rc()) {
+ if (m_ip4_uu_fwd && m_ip6_uu_fwd)
+ HW::enqueue(new gbp_route_domain_cmds::create_cmd(
+ m_id, m_ip4_uu_fwd->handle(), m_ip6_uu_fwd->handle()));
+ else
+ HW::enqueue(new gbp_route_domain_cmds::create_cmd(m_id, handle_t::INVALID,
+ handle_t::INVALID));
+ }
+}
+
+gbp_route_domain::~gbp_route_domain()
+{
+ sweep();
+
+ // not in the DB anymore.
+ m_db.release(m_id.data(), this);
+}
+
+std::string
+gbp_route_domain::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-route-domain:[" << m_rd->to_string() << "]";
+
+ return (s.str());
+}
+
+std::shared_ptr<gbp_route_domain>
+gbp_route_domain::find(const key_t& key)
+{
+ return (m_db.find(key));
+}
+
+void
+gbp_route_domain::update(const gbp_route_domain& desired)
+{
+ /*
+ * the desired state is always that the interface should be created
+ */
+ if (rc_t::OK != m_id.rc()) {
+ if (m_ip4_uu_fwd && m_ip6_uu_fwd)
+ HW::enqueue(new gbp_route_domain_cmds::create_cmd(
+ m_id, m_ip4_uu_fwd->handle(), m_ip6_uu_fwd->handle()));
+ else
+ HW::enqueue(new gbp_route_domain_cmds::create_cmd(m_id, handle_t::INVALID,
+ handle_t::INVALID));
+ }
+}
+
+std::shared_ptr<gbp_route_domain>
+gbp_route_domain::find_or_add(const gbp_route_domain& temp)
+{
+ return (m_db.find_or_add(temp.m_id.data(), temp));
+}
+
+std::shared_ptr<gbp_route_domain>
+gbp_route_domain::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_route_domain::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+void
+gbp_route_domain::event_handler::handle_populate(const client_db::key_t& key)
+{
+ /*
+ * dump VPP Route domains
+ */
+ std::shared_ptr<gbp_route_domain_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_route_domain_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ std::shared_ptr<interface> ip6_uu_fwd =
+ interface::find(payload.rd.ip6_uu_sw_if_index);
+ std::shared_ptr<interface> ip4_uu_fwd =
+ interface::find(payload.rd.ip4_uu_sw_if_index);
+
+ if (ip6_uu_fwd && ip4_uu_fwd) {
+ gbp_route_domain rd(payload.rd.rd_id, *ip4_uu_fwd, *ip6_uu_fwd);
+ OM::commit(key, rd);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << rd.to_string();
+ } else {
+ gbp_route_domain rd(payload.rd.rd_id);
+ OM::commit(key, rd);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << rd.to_string();
+ }
+ }
+}
+
+gbp_route_domain::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "grd", "groute" }, "GBP Route Domains", this);
+}
+
+void
+gbp_route_domain::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+dependency_t
+gbp_route_domain::event_handler::order() const
+{
+ return (dependency_t::TABLE);
+}
+
+void
+gbp_route_domain::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_route_domain.hpp b/extras/vom/vom/gbp_route_domain.hpp
new file mode 100644
index 00000000000..6dc37d1981e
--- /dev/null
+++ b/extras/vom/vom/gbp_route_domain.hpp
@@ -0,0 +1,183 @@
+/*
+ * 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_ROUTE_DOMAIN_H__
+#define __VOM_GBP_ROUTE_DOMAIN_H__
+
+#include "vom/interface.hpp"
+#include "vom/route_domain.hpp"
+#include "vom/singular_db.hpp"
+#include "vom/types.hpp"
+
+namespace VOM {
+
+/**
+ * A entry in the ARP termination table of a Route Domain
+ */
+class gbp_route_domain : public object_base
+{
+public:
+ /**
+ * The key for a route_domain is the pari of EPG-IDs
+ */
+ typedef route_domain::key_t key_t;
+
+ /**
+ * Construct a GBP route_domain
+ */
+ gbp_route_domain(const route_domain& rd);
+
+ gbp_route_domain(const route_domain& rd,
+ const interface& ip4_uu_fwd,
+ const interface& ip6_uu_fwd);
+
+ /**
+ * Copy Construct
+ */
+ gbp_route_domain(const gbp_route_domain& r);
+
+ /**
+ * Destructor
+ */
+ ~gbp_route_domain();
+
+ /**
+ * Return the object's key
+ */
+ const key_t key() const;
+
+ /**
+ * Return the route domain's VPP ID
+ */
+ uint32_t id() const;
+
+ /**
+ * comparison operator
+ */
+ bool operator==(const gbp_route_domain& rdae) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<gbp_route_domain> singular() const;
+
+ /**
+ * Find the instnace of the route_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_route_domain> find(const key_t& k);
+
+ /**
+ * Dump all route_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:
+ /**
+ * 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_route_domain& obj);
+
+ /**
+ * Find or add the instance of the route_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_route_domain> find_or_add(
+ const gbp_route_domain& 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_route_domain>;
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * HW configuration for the result of creating the endpoint
+ */
+ HW::item<uint32_t> m_id;
+
+ std::shared_ptr<route_domain> m_rd;
+ std::shared_ptr<interface> m_ip4_uu_fwd;
+ std::shared_ptr<interface> m_ip6_uu_fwd;
+
+ /**
+ * A map of all route_domains
+ */
+ static singular_db<key_t, gbp_route_domain> m_db;
+};
+
+}; // namespace
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_route_domain_cmds.cpp b/extras/vom/vom/gbp_route_domain_cmds.cpp
new file mode 100644
index 00000000000..0862d8a36f1
--- /dev/null
+++ b/extras/vom/vom/gbp_route_domain_cmds.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_route_domain_cmds.hpp"
+
+namespace VOM {
+namespace gbp_route_domain_cmds {
+
+create_cmd::create_cmd(HW::item<uint32_t>& item,
+ const handle_t ip4_uu_fwd,
+ const handle_t ip6_uu_fwd)
+ : rpc_cmd(item)
+ , m_ip4_uu_fwd(ip4_uu_fwd)
+ , m_ip6_uu_fwd(ip6_uu_fwd)
+{
+}
+
+bool
+create_cmd::operator==(const create_cmd& other) const
+{
+ return ((m_hw_item.data() == other.m_hw_item.data()) &&
+ (m_ip4_uu_fwd == other.m_ip4_uu_fwd) &&
+ (m_ip6_uu_fwd == other.m_ip6_uu_fwd));
+}
+
+rc_t
+create_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+
+ payload.rd.rd_id = m_hw_item.data();
+ payload.rd.ip4_uu_sw_if_index = m_ip4_uu_fwd.value();
+ payload.rd.ip6_uu_sw_if_index = m_ip6_uu_fwd.value();
+
+ VAPI_CALL(req.execute());
+
+ return (wait());
+}
+
+std::string
+create_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-route-domain: " << m_hw_item.to_string()
+ << " ip4-uu-fwd:" << m_ip4_uu_fwd.to_string()
+ << " ip6-uu-fwd:" << m_ip6_uu_fwd.to_string();
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<uint32_t>& item)
+ : rpc_cmd(item)
+{
+}
+
+bool
+delete_cmd::operator==(const delete_cmd& other) const
+{
+ return (m_hw_item.data() == other.m_hw_item.data());
+}
+
+rc_t
+delete_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+
+ payload.rd_id = m_hw_item.data();
+
+ VAPI_CALL(req.execute());
+
+ wait();
+ m_hw_item.set(rc_t::NOOP);
+
+ return rc_t::OK;
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-route-domain: " << m_hw_item.to_string();
+
+ return (s.str());
+}
+
+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-route-domain-dump");
+}
+
+}; // namespace gbp_route_domain_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_route_domain_cmds.hpp b/extras/vom/vom/gbp_route_domain_cmds.hpp
new file mode 100644
index 00000000000..249ba901329
--- /dev/null
+++ b/extras/vom/vom/gbp_route_domain_cmds.hpp
@@ -0,0 +1,131 @@
+/*
+ * 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_ROUTE_DOMAIN_CMDS_H__
+#define __VOM_GBP_ROUTE_DOMAIN_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/gbp_route_domain.hpp"
+#include "vom/rpc_cmd.hpp"
+
+#include <vapi/gbp.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_route_domain_cmds {
+/**
+ * A command class that creates an Route-Domain
+ */
+class create_cmd
+ : public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_route_domain_add>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_cmd(HW::item<uint32_t>& item,
+ const handle_t ip4_uu_fwd,
+ const handle_t ip6_uu_fwd);
+
+ /**
+ * 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_ip4_uu_fwd;
+ const handle_t m_ip6_uu_fwd;
+};
+
+/**
+ * A cmd class that Delete an Route-Domain
+ */
+class delete_cmd
+ : public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_route_domain_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<uint32_t>& item);
+
+ /**
+ * 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;
+};
+
+/**
+ * A cmd class that Dumps all the route domains
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::Gbp_route_domain_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_cmd() = default;
+ dump_cmd(const dump_cmd& d) = 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_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+
+}; // gbp_route_domain_cmds
+}; // VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_subnet.cpp b/extras/vom/vom/gbp_subnet.cpp
index 1bc024da854..2221c616dbb 100644
--- a/extras/vom/vom/gbp_subnet.cpp
+++ b/extras/vom/vom/gbp_subnet.cpp
@@ -25,31 +25,38 @@ gbp_subnet::type_t::type_t(int v, const std::string 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");
+const gbp_subnet::type_t gbp_subnet::type_t::STITCHED_INTERNAL(
+ 0,
+ "stitched-internal");
+const gbp_subnet::type_t gbp_subnet::type_t::STITCHED_EXTERNAL(
+ 1,
+ "stitched-external");
+const gbp_subnet::type_t gbp_subnet::type_t::TRANSPORT(1, "transport");
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)
+gbp_subnet::gbp_subnet(const gbp_route_domain& rd,
+ const route::prefix_t& prefix,
+ const type_t& type)
: m_hw(false)
, m_rd(rd.singular())
, m_prefix(prefix)
- , m_type(type_t::INTERNAL)
+ , m_type(type)
, m_recirc(nullptr)
, m_epg(nullptr)
{
}
-gbp_subnet::gbp_subnet(const route_domain& rd,
+gbp_subnet::gbp_subnet(const gbp_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_type(type_t::STITCHED_EXTERNAL)
, m_recirc(recirc.singular())
, m_epg(epg.singular())
{
@@ -88,8 +95,7 @@ void
gbp_subnet::sweep()
{
if (m_hw) {
- HW::enqueue(
- new gbp_subnet_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix));
+ HW::enqueue(new gbp_subnet_cmds::delete_cmd(m_hw, m_rd->id(), m_prefix));
}
HW::write();
}
@@ -99,7 +105,7 @@ 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_hw, m_rd->id(), m_prefix, m_type,
(m_recirc ? m_recirc->handle() : handle_t::INVALID),
(m_epg ? m_epg->id() : ~0)));
}
@@ -126,7 +132,7 @@ 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_hw, m_rd->id(), m_prefix, m_type,
(m_recirc ? m_recirc->handle() : handle_t::INVALID),
(m_epg ? m_epg->id() : ~0)));
} else {
@@ -136,7 +142,7 @@ gbp_subnet::update(const gbp_subnet& r)
m_type = r.m_type;
HW::enqueue(new gbp_subnet_cmds::create_cmd(
- m_hw, m_rd->table_id(), m_prefix, (m_type == type_t::INTERNAL),
+ m_hw, m_rd->id(), m_prefix, m_type,
(m_recirc ? m_recirc->handle() : handle_t::INVALID),
(m_epg ? m_epg->id() : ~0)));
}
@@ -192,27 +198,37 @@ gbp_subnet::event_handler::handle_populate(const client_db::key_t& key)
auto& payload = record.get_payload();
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<gbp_route_domain> rd =
+ gbp_route_domain::find(payload.subnet.rd_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();
+ switch (payload.subnet.type) {
+ case GBP_API_SUBNET_TRANSPORT: {
+ gbp_subnet gs(*rd, pfx, type_t::TRANSPORT);
+ OM::commit(key, gs);
+ VOM_LOG(log_level_t::DEBUG) << "read: " << gs.to_string();
+ break;
+ }
+ case GBP_API_SUBNET_STITCHED_INTERNAL: {
+ gbp_subnet gs(*rd, pfx, type_t::STITCHED_INTERNAL);
+ OM::commit(key, gs);
+ VOM_LOG(log_level_t::DEBUG) << "read: " << gs.to_string();
+ break;
+ }
+ case GBP_API_SUBNET_STITCHED_EXTERNAL: {
+ 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();
+ }
}
}
}
@@ -231,6 +247,15 @@ gbp_subnet::event_handler::show(std::ostream& os)
{
db_dump(m_db, os);
}
+
+std::ostream&
+operator<<(std::ostream& os, const gbp_subnet::key_t& key)
+{
+ os << "[" << key.first << ", " << key.second << "]";
+
+ return os;
+}
+
} // namespace VOM
/*
diff --git a/extras/vom/vom/gbp_subnet.hpp b/extras/vom/vom/gbp_subnet.hpp
index b4adb40ae45..e08f1a25e11 100644
--- a/extras/vom/vom/gbp_subnet.hpp
+++ b/extras/vom/vom/gbp_subnet.hpp
@@ -16,9 +16,11 @@
#ifndef __VOM_GBP_SUBNET_H__
#define __VOM_GBP_SUBNET_H__
+#include <ostream>
+
#include "vom/gbp_endpoint_group.hpp"
#include "vom/gbp_recirc.hpp"
-#include "vom/route.hpp"
+#include "vom/gbp_route_domain.hpp"
#include "vom/singular_db.hpp"
namespace VOM {
@@ -31,17 +33,41 @@ public:
/**
* The key for a GBP subnet; table and prefix
*/
- typedef std::pair<route_domain::key_t, route::prefix_t> key_t;
+ typedef std::pair<gbp_route_domain::key_t, route::prefix_t> key_t;
+
+ struct type_t : public enum_base<type_t>
+ {
+ /**
+ * Internal subnet is reachable through the source EPG's
+ * uplink interface.
+ */
+ const static type_t STITCHED_INTERNAL;
+
+ /**
+ * External subnet requires NAT translation before egress.
+ */
+ const static type_t STITCHED_EXTERNAL;
+
+ /**
+ * A transport subnet, sent via the RD's UU-fwd interface
+ */
+ const static type_t TRANSPORT;
+
+ private:
+ type_t(int v, const std::string s);
+ };
/**
- * Construct an internal GBP subnet
- */
- gbp_subnet(const route_domain& rd, const route::prefix_t& prefix);
+ * Construct an internal GBP subnet
+ */
+ gbp_subnet(const gbp_route_domain& rd,
+ const route::prefix_t& prefix,
+ const type_t& type);
/**
* Construct an external GBP subnet
*/
- gbp_subnet(const route_domain& rd,
+ gbp_subnet(const gbp_route_domain& rd,
const route::prefix_t& prefix,
const gbp_recirc& recirc,
const gbp_endpoint_group& epg);
@@ -92,23 +118,6 @@ public:
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
*/
@@ -177,7 +186,7 @@ private:
/**
* the route domain the prefix is in
*/
- const std::shared_ptr<route_domain> m_rd;
+ const std::shared_ptr<gbp_route_domain> m_rd;
/**
* prefix to match
@@ -205,6 +214,8 @@ private:
static singular_db<key_t, gbp_subnet> m_db;
};
+std::ostream& operator<<(std::ostream& os, const gbp_subnet::key_t& key);
+
}; // namespace
/*
diff --git a/extras/vom/vom/gbp_subnet_cmds.cpp b/extras/vom/vom/gbp_subnet_cmds.cpp
index 79fdf175ee1..3dcd652dd19 100644
--- a/extras/vom/vom/gbp_subnet_cmds.cpp
+++ b/extras/vom/vom/gbp_subnet_cmds.cpp
@@ -22,13 +22,13 @@ 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 gbp_subnet::type_t& type,
const handle_t& itf,
epg_id_t epg_id)
: rpc_cmd(item)
, m_rd(rd)
, m_prefix(prefix)
- , m_internal(internal)
+ , m_type(type)
, m_itf(itf)
, m_epg_id(epg_id)
{
@@ -38,8 +38,21 @@ 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));
+ (m_prefix == other.m_prefix) && (m_type == other.m_type) &&
+ (m_itf == other.m_itf) && (m_epg_id == other.m_epg_id));
+}
+
+static vapi_enum_gbp_subnet_type
+gbp_subnet_type_to_api(const gbp_subnet::type_t& type)
+{
+ if (gbp_subnet::type_t::STITCHED_INTERNAL == type)
+ return (GBP_API_SUBNET_STITCHED_INTERNAL);
+ if (gbp_subnet::type_t::STITCHED_EXTERNAL == type)
+ return (GBP_API_SUBNET_STITCHED_EXTERNAL);
+ if (gbp_subnet::type_t::TRANSPORT == type)
+ return (GBP_API_SUBNET_TRANSPORT);
+
+ return (GBP_API_SUBNET_STITCHED_INTERNAL);
}
rc_t
@@ -49,8 +62,8 @@ create_cmd::issue(connection& con)
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.type = gbp_subnet_type_to_api(m_type);
+ payload.subnet.rd_id = m_rd;
payload.subnet.sw_if_index = m_itf.value();
payload.subnet.epg_id = m_epg_id;
payload.subnet.prefix = to_api(m_prefix);
@@ -64,9 +77,9 @@ 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;
+ s << "gbp-subnet-create: " << m_hw_item.to_string() << "type:" << m_type
+ << ", " << m_rd << ":" << m_prefix.to_string() << " itf:" << m_itf
+ << " epg-id:" << m_epg_id;
return (s.str());
}
@@ -93,13 +106,9 @@ delete_cmd::issue(connection& con)
auto& payload = req.get_request().get_payload();
payload.is_add = 0;
- payload.subnet.table_id = m_rd;
+ payload.subnet.rd_id = m_rd;
payload.subnet.prefix = to_api(m_prefix);
- payload.subnet.is_internal = 0;
- payload.subnet.sw_if_index = ~0;
- payload.subnet.epg_id = ~0;
-
VAPI_CALL(req.execute());
return (wait());
diff --git a/extras/vom/vom/gbp_subnet_cmds.hpp b/extras/vom/vom/gbp_subnet_cmds.hpp
index 118303b7178..da2a4c509d1 100644
--- a/extras/vom/vom/gbp_subnet_cmds.hpp
+++ b/extras/vom/vom/gbp_subnet_cmds.hpp
@@ -36,7 +36,7 @@ public:
create_cmd(HW::item<bool>& item,
route::table_id_t rd,
const route::prefix_t& prefix,
- bool internal,
+ const gbp_subnet::type_t& type,
const handle_t& itf,
epg_id_t epg_id);
@@ -58,7 +58,7 @@ public:
private:
const route::table_id_t m_rd;
const route::prefix_t m_prefix;
- const bool m_internal;
+ const gbp_subnet::type_t& m_type;
const handle_t m_itf;
const epg_id_t m_epg_id;
};
diff --git a/extras/vom/vom/gbp_vxlan.cpp b/extras/vom/vom/gbp_vxlan.cpp
new file mode 100644
index 00000000000..af4467abfbb
--- /dev/null
+++ b/extras/vom/vom/gbp_vxlan.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_vxlan.hpp"
+#include "vom/gbp_vxlan_cmds.hpp"
+#include "vom/interface.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+const std::string GBP_VXLAN_NAME = "gbp-vxlan";
+
+/**
+ * A DB of al the interfaces, key on the name
+ */
+singular_db<gbp_vxlan::key_t, gbp_vxlan> gbp_vxlan::m_db;
+
+gbp_vxlan::event_handler gbp_vxlan::m_evh;
+
+gbp_vxlan::gbp_vxlan(uint32_t vni, const gbp_route_domain& grd)
+ : interface(mk_name(vni),
+ interface::type_t::UNKNOWN,
+ interface::admin_state_t::UP)
+ , m_vni(vni)
+ , m_gbd()
+ , m_grd(grd.singular())
+{
+}
+gbp_vxlan::gbp_vxlan(uint32_t vni, const gbp_bridge_domain& gbd)
+ : interface(mk_name(vni),
+ interface::type_t::UNKNOWN,
+ interface::admin_state_t::UP)
+ , m_vni(vni)
+ , m_gbd(gbd.singular())
+ , m_grd()
+{
+}
+
+gbp_vxlan::gbp_vxlan(const gbp_vxlan& vt)
+ : interface(vt)
+ , m_vni(vt.m_vni)
+ , m_gbd(vt.m_gbd)
+ , m_grd(vt.m_grd)
+{
+}
+
+std::string
+gbp_vxlan::mk_name(uint32_t vni)
+{
+ std::ostringstream s;
+
+ s << GBP_VXLAN_NAME << "-" << vni;
+
+ return (s.str());
+}
+
+const gbp_vxlan::key_t
+gbp_vxlan::key() const
+{
+ return (m_vni);
+}
+
+bool
+gbp_vxlan::operator==(const gbp_vxlan& vt) const
+{
+ return (m_vni == vt.m_vni);
+}
+
+void
+gbp_vxlan::sweep()
+{
+ if (rc_t::OK == m_hdl) {
+ HW::enqueue(new gbp_vxlan_cmds::delete_cmd(m_hdl, m_vni));
+ }
+ HW::write();
+}
+
+void
+gbp_vxlan::replay()
+{
+ if (rc_t::OK == m_hdl) {
+ if (m_grd)
+ HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, false,
+ m_grd->id()));
+ else if (m_gbd)
+ HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, true,
+ m_gbd->id()));
+ }
+}
+
+gbp_vxlan::~gbp_vxlan()
+{
+ sweep();
+ m_db.release(key(), this);
+}
+
+std::string
+gbp_vxlan::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-vxlan:[" << m_vni << "]";
+
+ return (s.str());
+}
+
+std::shared_ptr<gbp_vxlan>
+gbp_vxlan::find(const key_t key)
+{
+ return (m_db.find(key));
+}
+
+void
+gbp_vxlan::update(const gbp_vxlan& desired)
+{
+ /*
+ * the desired state is always that the interface should be created
+ */
+ if (rc_t::OK != m_hdl) {
+ if (m_grd)
+ HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, false,
+ m_grd->id()));
+ else if (m_gbd)
+ HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, true,
+ m_gbd->id()));
+ }
+}
+
+std::shared_ptr<gbp_vxlan>
+gbp_vxlan::find_or_add(const gbp_vxlan& temp)
+{
+ return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<gbp_vxlan>
+gbp_vxlan::singular() const
+{
+ return find_or_add(*this);
+}
+
+std::shared_ptr<interface>
+gbp_vxlan::singular_i() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_vxlan::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+void
+gbp_vxlan::event_handler::handle_populate(const client_db::key_t& key)
+{
+ /*
+ * dump VPP Bridge domains
+ */
+ std::shared_ptr<gbp_vxlan_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_vxlan_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ if (GBP_VXLAN_TUNNEL_MODE_L3 == payload.tunnel.mode) {
+ auto rd = gbp_route_domain::find(payload.tunnel.bd_rd_id);
+
+ if (rd) {
+ gbp_vxlan vt(payload.tunnel.vni, *rd);
+ OM::commit(key, vt);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
+ }
+ } else {
+ auto bd = gbp_bridge_domain::find(payload.tunnel.bd_rd_id);
+
+ if (bd) {
+ gbp_vxlan vt(payload.tunnel.vni, *bd);
+ OM::commit(key, vt);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
+ }
+ }
+ }
+}
+
+gbp_vxlan::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "gvt", "gbp-vxlan-tunnel" }, "GBP VXLAN Tunnels",
+ this);
+}
+
+void
+gbp_vxlan::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+dependency_t
+gbp_vxlan::event_handler::order() const
+{
+ return (dependency_t::BINDING);
+}
+
+void
+gbp_vxlan::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_vxlan.hpp b/extras/vom/vom/gbp_vxlan.hpp
new file mode 100644
index 00000000000..cae67d8ad17
--- /dev/null
+++ b/extras/vom/vom/gbp_vxlan.hpp
@@ -0,0 +1,186 @@
+/*
+ * 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_VXLAN_H__
+#define __VOM_GBP_VXLAN_H__
+
+#include "vom/gbp_bridge_domain.hpp"
+#include "vom/gbp_route_domain.hpp"
+#include "vom/hw.hpp"
+#include "vom/inspect.hpp"
+#include "vom/interface.hpp"
+#include "vom/singular_db.hpp"
+
+namespace VOM {
+/**
+ * A representation of a GBP_VXLAN Tunnel in VPP
+ */
+class gbp_vxlan : public interface
+{
+public:
+ /**
+ * The VNI is the key
+ */
+ typedef uint32_t key_t;
+
+ /**
+ * Construct a new object matching the desried state
+ */
+ gbp_vxlan(uint32_t vni, const gbp_bridge_domain& gbd);
+ gbp_vxlan(uint32_t vni, const gbp_route_domain& grd);
+
+ /*
+ * Destructor
+ */
+ ~gbp_vxlan();
+
+ /**
+ * Copy constructor
+ */
+ gbp_vxlan(const gbp_vxlan& o);
+
+ bool operator==(const gbp_vxlan& vt) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<gbp_vxlan> singular() const;
+
+ /**
+ * Return the object's key
+ */
+ const key_t key() const;
+
+ /**
+ * Debug rpint function
+ */
+ virtual std::string to_string() const;
+
+ /**
+ * Return VPP's handle to this object
+ */
+ const handle_t& handle() const;
+
+ /**
+ * Dump all L3Configs into the stream provided
+ */
+ static void dump(std::ostream& os);
+
+ /**
+ * Find the GBP_VXLAN tunnel in the OM
+ */
+ static std::shared_ptr<gbp_vxlan> find(const key_t k);
+
+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 handle 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_vxlan& obj);
+
+ /**
+ * Return the matching 'instance' of the sub-interface
+ * over-ride from the base class
+ */
+ std::shared_ptr<interface> singular_i() const;
+
+ /**
+ * Find the GBP_VXLAN tunnel in the OM
+ */
+ static std::shared_ptr<gbp_vxlan> find_or_add(const gbp_vxlan& 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_vxlan>;
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * replay the object to create it in hardware
+ */
+ void replay(void);
+
+ /**
+ * Tunnel VNI/key
+ */
+ uint32_t m_vni;
+ std::shared_ptr<gbp_bridge_domain> m_gbd;
+ std::shared_ptr<gbp_route_domain> m_grd;
+
+ /**
+ * A map of all VLAN tunnela against thier key
+ */
+ static singular_db<key_t, gbp_vxlan> m_db;
+
+ /**
+ * Construct a unique name for the tunnel
+ */
+ static std::string mk_name(uint32_t vni);
+};
+
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_vxlan_cmds.cpp b/extras/vom/vom/gbp_vxlan_cmds.cpp
new file mode 100644
index 00000000000..90a77fbb896
--- /dev/null
+++ b/extras/vom/vom/gbp_vxlan_cmds.cpp
@@ -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.
+ */
+
+#include "vom/gbp_vxlan_cmds.hpp"
+
+#include <vapi/tap.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_vxlan_cmds {
+create_cmd::create_cmd(HW::item<handle_t>& item,
+ const std::string& name,
+ uint32_t vni,
+ bool is_l2,
+ uint32_t bd_rd)
+ : interface::create_cmd<vapi::Gbp_vxlan_tunnel_add>(item, name)
+ , m_vni(vni)
+ , m_is_l2(is_l2)
+ , m_bd_rd(bd_rd)
+{
+}
+
+rc_t
+create_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+
+ payload.tunnel.vni = m_vni;
+ payload.tunnel.bd_rd_id = m_bd_rd;
+ if (m_is_l2)
+ payload.tunnel.mode = GBP_VXLAN_TUNNEL_MODE_L2;
+ else
+ payload.tunnel.mode = GBP_VXLAN_TUNNEL_MODE_L3;
+
+ VAPI_CALL(req.execute());
+
+ wait();
+ if (m_hw_item.rc() == rc_t::OK) {
+ insert_interface();
+ }
+
+ return (m_hw_item.rc());
+}
+
+std::string
+create_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-vxlan-create: " << m_hw_item.to_string() << " vni:" << m_vni
+ << " bd/rd:" << m_bd_rd;
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<handle_t>& item, uint32_t vni)
+ : interface::delete_cmd<vapi::Gbp_vxlan_tunnel_del>(item)
+ , m_vni(vni)
+{
+}
+
+rc_t
+delete_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.vni = m_vni;
+
+ VAPI_CALL(req.execute());
+
+ wait();
+ m_hw_item.set(rc_t::NOOP);
+
+ remove_interface();
+ return rc_t::OK;
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-vxlan-delete: " << m_hw_item.to_string() << " vni:" << m_vni;
+
+ 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-vxlan-dump");
+}
+
+} // namespace gbp_vxlan_cmds
+} // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_vxlan_cmds.hpp b/extras/vom/vom/gbp_vxlan_cmds.hpp
new file mode 100644
index 00000000000..a42a6531f20
--- /dev/null
+++ b/extras/vom/vom/gbp_vxlan_cmds.hpp
@@ -0,0 +1,135 @@
+/*
+ * 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_VXLAN_CMDS_H__
+#define __VOM_GBP_VXLAN_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/gbp_vxlan.hpp"
+#include "vom/interface.hpp"
+
+#include <vapi/gbp.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_vxlan_cmds {
+/**
+ * A command class that creates an Bridge-Domain
+ */
+class create_cmd : public interface::create_cmd<vapi::Gbp_vxlan_tunnel_add>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_cmd(HW::item<handle_t>& item,
+ const std::string& name,
+ uint32_t vni,
+ bool is_l2,
+ uint32_t bd_rd);
+
+ /**
+ * 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:
+ uint32_t m_vni;
+ bool m_is_l2;
+ uint32_t m_bd_rd;
+};
+
+/**
+ * A cmd class that Delete an Bridge-Domain
+ */
+class delete_cmd : public interface::delete_cmd<vapi::Gbp_vxlan_tunnel_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<handle_t>& item, uint32_t vni);
+
+ /**
+ * 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:
+ uint32_t m_vni;
+};
+
+/**
+ * A cmd class that Dumps all the bridge domains
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::Gbp_vxlan_tunnel_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;
+};
+
+}; // gbp_vxlan_cmds
+}; // VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_vxlan_tunnel.cpp b/extras/vom/vom/gbp_vxlan_tunnel.cpp
new file mode 100644
index 00000000000..2219c04b1c2
--- /dev/null
+++ b/extras/vom/vom/gbp_vxlan_tunnel.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_vxlan_tunnel.hpp"
+#include "vom/gbp_vxlan_tunnel_cmds.hpp"
+#include "vom/interface.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+/**
+ * A DB of al the interfaces, key on the name
+ */
+singular_db<uint32_t, gbp_vxlan_tunnel> gbp_vxlan_tunnel::m_db;
+
+gbp_vxlan_tunnel::event_handler gbp_vxlan_tunnel::m_evh;
+
+/**
+ * Construct a new object matching the desried state
+ */
+gbp_vxlan_tunnel::gbp_vxlan_tunnel(const vxlan_tunnel& vt)
+ : interface(vt)
+ , m_vni(vt.m_vni)
+{
+}
+
+gbp_vxlan_tunnel::gbp_vxlan_tunnel(uint32_t vni)
+ : interface(mk_name(vni),
+ interface::type_t::UNKNOWN,
+ interface::admin_state_t::UP)
+ , m_vni(vt.m_vni)
+{
+}
+
+const gbp_vxlan_tunnel::key_t
+gbp_vxlan_tunnel::key() const
+{
+ return (m_vni);
+}
+
+bool
+gbp_vxlan_tunnel::operator==(const gbp_vxlan_tunnel& vt) const
+{
+ return (m_vni == vt.m_vni);
+}
+
+void
+gbp_vxlan_tunnel::sweep()
+{
+ if (rc_t::OK == m_id.rc()) {
+ HW::enqueue(new gbp_vxlan_tunnel_cmds::delete_cmd(m_vni));
+ }
+ HW::write();
+}
+
+void
+gbp_vxlan_tunnel::replay()
+{
+ if (rc_t::OK == m_hdl) {
+ HW::enqueue(new gbp_vxlan_tunnel_cmds::create_cmd(m_vni));
+ }
+}
+
+gbp_vxlan_tunnel::~gbp_vxlan_tunnel()
+{
+ sweep();
+ m_db.release(m_id.data(), this);
+}
+
+std::string
+gbp_vxlan_tunnel::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-vxlan:[" << m_vni << "]";
+
+ return (s.str());
+}
+
+std::shared_ptr<gbp_vxlan_tunnel>
+gbp_vxlan_tunnel::find(const key_t& key)
+{
+ return (m_db.find(key));
+}
+
+void
+gbp_vxlan_tunnel::update(const gbp_vxlan_tunnel& desired)
+{
+ /*
+ * the desired state is always that the interface should be created
+ */
+ if (rc_t::OK != m_hdl) {
+ HW::enqueue(new gbp_vxlan_tunnel_cmds::create_cmd(m_vni));
+ }
+}
+
+std::shared_ptr<gbp_vxlan_tunnel>
+gbp_vxlan_tunnel::find_or_add(const gbp_vxlan_tunnel& temp)
+{
+ return (m_db.find_or_add(temp.m_id.data(), temp));
+}
+
+std::shared_ptr<gbp_vxlan_tunnel>
+gbp_vxlan_tunnel::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_vxlan_tunnel::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+void
+gbp_vxlan_tunnel::event_handler::handle_populate(const client_db::key_t& key)
+{
+ /*
+ * dump VPP Bridge domains
+ */
+ std::shared_ptr<gbp_vxlan_tunnel_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_vxlan_tunnel_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ gbp_vxlan_tunnel vt(payload.tunnel.vni, );
+ OM::commit(key, vt);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
+ }
+ else
+ {
+ gbp_vxlan_tunnel vt(payload.vt.vt_id);
+ OM::commit(key, vt);
+ VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
+ }
+}
+}
+
+gbp_vxlan_tunnel::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "gvt", "gbp-vxlan-tunnel" }, "GBP VXLAN Tunnels",
+ this);
+}
+
+void
+gbp_vxlan_tunnel::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+dependency_t
+gbp_vxlan_tunnel::event_handler::order() const
+{
+ return (dependency_t::INTERFACE);
+}
+
+void
+gbp_vxlan_tunnel::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/interface_factory.cpp b/extras/vom/vom/interface_factory.cpp
index f4425130a4e..fd135f5820e 100644
--- a/extras/vom/vom/interface_factory.cpp
+++ b/extras/vom/vom/interface_factory.cpp
@@ -38,6 +38,10 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd)
l2_address_t l2_address(vd.l2_address, vd.l2_address_length);
std::string tag = "";
+ if (interface::type_t::UNKNOWN == type) {
+ return sp;
+ }
+
sp = interface::find(hdl);
if (sp) {
sp->set(state);