From 93cc3ee3b3a9c9224a1446625882205f3282a949 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 10 Oct 2018 07:22:51 -0700 Subject: GBP Endpoint Learning Learning GBP endpoints over vxlan-gbp tunnels Change-Id: I1db9fda5a16802d9ad8b4efd4e475614f3b21502 Signed-off-by: Neale Ranns --- extras/vom/vom/CMakeLists.txt | 18 ++- extras/vom/vom/gbp_bridge_domain.cpp | 232 +++++++++++++++++++++++++++++ extras/vom/vom/gbp_bridge_domain.hpp | 183 +++++++++++++++++++++++ extras/vom/vom/gbp_bridge_domain_cmds.cpp | 133 +++++++++++++++++ extras/vom/vom/gbp_bridge_domain_cmds.hpp | 131 ++++++++++++++++ extras/vom/vom/gbp_contract_cmds.hpp | 2 +- extras/vom/vom/gbp_endpoint_group.cpp | 23 +-- extras/vom/vom/gbp_endpoint_group.hpp | 15 +- extras/vom/vom/gbp_endpoint_group_cmds.cpp | 7 +- extras/vom/vom/gbp_endpoint_group_cmds.hpp | 6 +- extras/vom/vom/gbp_route_domain.cpp | 232 +++++++++++++++++++++++++++++ extras/vom/vom/gbp_route_domain.hpp | 183 +++++++++++++++++++++++ extras/vom/vom/gbp_route_domain_cmds.cpp | 135 +++++++++++++++++ extras/vom/vom/gbp_route_domain_cmds.hpp | 131 ++++++++++++++++ extras/vom/vom/gbp_subnet.cpp | 85 +++++++---- extras/vom/vom/gbp_subnet.hpp | 59 +++++--- extras/vom/vom/gbp_subnet_cmds.cpp | 37 +++-- extras/vom/vom/gbp_subnet_cmds.hpp | 4 +- extras/vom/vom/gbp_vxlan.cpp | 231 ++++++++++++++++++++++++++++ extras/vom/vom/gbp_vxlan.hpp | 186 +++++++++++++++++++++++ extras/vom/vom/gbp_vxlan_cmds.cpp | 137 +++++++++++++++++ extras/vom/vom/gbp_vxlan_cmds.hpp | 135 +++++++++++++++++ extras/vom/vom/gbp_vxlan_tunnel.cpp | 186 +++++++++++++++++++++++ extras/vom/vom/interface_factory.cpp | 4 + 24 files changed, 2392 insertions(+), 103 deletions(-) create mode 100644 extras/vom/vom/gbp_bridge_domain.cpp create mode 100644 extras/vom/vom/gbp_bridge_domain.hpp create mode 100644 extras/vom/vom/gbp_bridge_domain_cmds.cpp create mode 100644 extras/vom/vom/gbp_bridge_domain_cmds.hpp create mode 100644 extras/vom/vom/gbp_route_domain.cpp create mode 100644 extras/vom/vom/gbp_route_domain.hpp create mode 100644 extras/vom/vom/gbp_route_domain_cmds.cpp create mode 100644 extras/vom/vom/gbp_route_domain_cmds.hpp create mode 100644 extras/vom/vom/gbp_vxlan.cpp create mode 100644 extras/vom/vom/gbp_vxlan.hpp create mode 100644 extras/vom/vom/gbp_vxlan_cmds.cpp create mode 100644 extras/vom/vom/gbp_vxlan_cmds.hpp create mode 100644 extras/vom/vom/gbp_vxlan_tunnel.cpp (limited to 'extras/vom') 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 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::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::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::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 cmd = + std::make_shared(); + + HW::enqueue(cmd); + HW::write(); + + for (auto& record : *cmd) { + auto& payload = record.get_payload(); + + std::shared_ptr uu_fwd = + interface::find(payload.bd.uu_fwd_sw_if_index); + std::shared_ptr 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 singular() const; + + /** + * Find the instnace of the bridge_domain domain in the OM + */ + static std::shared_ptr 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 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; + + /** + * Sweep/reap the object if still stale + */ + void sweep(void); + + /** + * HW configuration for the result of creating the endpoint + */ + HW::item m_id; + + std::shared_ptr m_bd; + std::shared_ptr m_bvi; + std::shared_ptr m_uu_fwd; + + /** + * A map of all bridge_domains + */ + static singular_db 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& 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& 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 + +namespace VOM { +namespace gbp_bridge_domain_cmds { +/** + * A command class that creates an Bridge-Domain + */ +class create_cmd + : public rpc_cmd, vapi::Gbp_bridge_domain_add> +{ +public: + /** + * Constructor + */ + create_cmd(HW::item& 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, vapi::Gbp_bridge_domain_del> +{ +public: + /** + * Constructor + */ + delete_cmd(HW::item& 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 +{ +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 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 { 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 itf = interface::find(payload.epg.uplink_sw_if_index); - std::shared_ptr rd = - route_domain::find(payload.epg.ip4_table_id); - std::shared_ptr bd = bridge_domain::find(payload.epg.bd_id); + std::shared_ptr rd = + gbp_route_domain::find(payload.epg.rd_id); + std::shared_ptr 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 m_rd; + std::shared_ptr m_rd; /** * The bridge-domain the EPG uses */ - std::shared_ptr m_bd; + std::shared_ptr 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, vapi::Gbp_endpoint_group_add_del> +class create_cmd : public rpc_cmd, 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, vapi::Gbp_endpoint_group_add_del> +class delete_cmd : public rpc_cmd, 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 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::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::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::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 cmd = + std::make_shared(); + + HW::enqueue(cmd); + HW::write(); + + for (auto& record : *cmd) { + auto& payload = record.get_payload(); + + std::shared_ptr ip6_uu_fwd = + interface::find(payload.rd.ip6_uu_sw_if_index); + std::shared_ptr 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 singular() const; + + /** + * Find the instnace of the route_domain domain in the OM + */ + static std::shared_ptr 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 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; + + /** + * Sweep/reap the object if still stale + */ + void sweep(void); + + /** + * HW configuration for the result of creating the endpoint + */ + HW::item m_id; + + std::shared_ptr m_rd; + std::shared_ptr m_ip4_uu_fwd; + std::shared_ptr m_ip6_uu_fwd; + + /** + * A map of all route_domains + */ + static singular_db 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& 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& 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 + +namespace VOM { +namespace gbp_route_domain_cmds { +/** + * A command class that creates an Route-Domain + */ +class create_cmd + : public rpc_cmd, vapi::Gbp_route_domain_add> +{ +public: + /** + * Constructor + */ + create_cmd(HW::item& 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, vapi::Gbp_route_domain_del> +{ +public: + /** + * Constructor + */ + delete_cmd(HW::item& 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 +{ +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 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::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 rd = - route_domain::find(payload.subnet.table_id); + std::shared_ptr 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 itf = - interface::find(payload.subnet.sw_if_index); - std::shared_ptr epg = - gbp_endpoint_group::find(payload.subnet.epg_id); - - if (itf && epg) { - std::shared_ptr 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 itf = + interface::find(payload.subnet.sw_if_index); + std::shared_ptr epg = + gbp_endpoint_group::find(payload.subnet.epg_id); + + if (itf && epg) { + std::shared_ptr 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 + #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 key_t; + typedef std::pair key_t; + + struct type_t : public enum_base + { + /** + * 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 - { - /** - * 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 m_rd; + const std::shared_ptr m_rd; /** * prefix to match @@ -205,6 +214,8 @@ private: static singular_db 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& 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& 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::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::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::find_or_add(const gbp_vxlan& temp) +{ + return (m_db.find_or_add(temp.key(), temp)); +} + +std::shared_ptr +gbp_vxlan::singular() const +{ + return find_or_add(*this); +} + +std::shared_ptr +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 cmd = + std::make_shared(); + + 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 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 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 singular_i() const; + + /** + * Find the GBP_VXLAN tunnel in the OM + */ + static std::shared_ptr 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; + + /** + * 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 m_gbd; + std::shared_ptr m_grd; + + /** + * A map of all VLAN tunnela against thier key + */ + static singular_db 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 + +namespace VOM { +namespace gbp_vxlan_cmds { +create_cmd::create_cmd(HW::item& item, + const std::string& name, + uint32_t vni, + bool is_l2, + uint32_t bd_rd) + : interface::create_cmd(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& item, uint32_t vni) + : interface::delete_cmd(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 + +namespace VOM { +namespace gbp_vxlan_cmds { +/** + * A command class that creates an Bridge-Domain + */ +class create_cmd : public interface::create_cmd +{ +public: + /** + * Constructor + */ + create_cmd(HW::item& 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 +{ +public: + /** + * Constructor + */ + delete_cmd(HW::item& 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 +{ +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 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 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::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::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::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 cmd = + std::make_shared(); + + 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); -- cgit 1.2.3-korg