diff options
author | Neale Ranns <neale.ranns@cisco.com> | 2018-02-05 01:13:38 -0800 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2018-02-09 13:17:54 +0000 |
commit | bc27d1be24815e1371dcce3bff2d3075a532acba (patch) | |
tree | c17db02fefb19ce593de5ddb2444f4c97e074492 /src/vpp-api | |
parent | ef56fae51a8683ec6ceeb01e1374cde2ba30c1e5 (diff) |
GBP plugin
Group Base Policy (GBP) defines:
- endpoints: typically a VM or container that is connected to the
virtual switch/router (i.e. to VPP)
- endpoint-group: (EPG) a collection of endpoints
- policy: rules determining which traffic can pass between EPGs a.k.a
a 'contract'
Here, policy is implemented via an ACL.
EPG classification for transit packets is determined by:
- source EPG: from the packet's input interface
- destination EPG: from the packet's destination IP address.
Change-Id: I7b983844826b5fc3d49e21353ebda9df9b224e25
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
Diffstat (limited to 'src/vpp-api')
-rw-r--r-- | src/vpp-api/vom/Makefile.am | 6 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_contract.cpp | 193 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_contract.hpp | 188 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_contract_cmds.cpp | 145 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_contract_cmds.hpp | 137 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_endpoint.cpp | 187 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_endpoint.hpp | 191 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_endpoint_cmds.cpp | 149 | ||||
-rw-r--r-- | src/vpp-api/vom/gbp_endpoint_cmds.hpp | 140 | ||||
-rw-r--r-- | src/vpp-api/vom/l2_emulation.cpp | 2 | ||||
-rw-r--r-- | src/vpp-api/vom/l2_emulation_cmds.cpp | 4 |
11 files changed, 1339 insertions, 3 deletions
diff --git a/src/vpp-api/vom/Makefile.am b/src/vpp-api/vom/Makefile.am index e7e003968b0..2cb7f837571 100644 --- a/src/vpp-api/vom/Makefile.am +++ b/src/vpp-api/vom/Makefile.am @@ -57,6 +57,10 @@ libvom_la_SOURCES = \ connection.cpp \ dhcp_config_cmds.cpp \ dhcp_config.cpp \ + gbp_endpoint_cmds.cpp \ + gbp_endpoint.cpp \ + gbp_contract_cmds.cpp \ + gbp_contract.cpp \ hw_cmds.cpp \ hw.cpp \ inspect.cpp \ @@ -123,6 +127,8 @@ vominclude_HEADERS = \ dump_cmd.hpp \ enum_base.hpp \ event_cmd.hpp \ + gbp_endpoint.hpp \ + gbp_contract.hpp \ hw.hpp \ inspect.hpp \ interface.hpp \ diff --git a/src/vpp-api/vom/gbp_contract.cpp b/src/vpp-api/vom/gbp_contract.cpp new file mode 100644 index 00000000000..d648fb3aeaa --- /dev/null +++ b/src/vpp-api/vom/gbp_contract.cpp @@ -0,0 +1,193 @@ +/* + * 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_contract.hpp" +#include "vom/gbp_contract_cmds.hpp" + +namespace VOM { + +singular_db<gbp_contract::key_t, gbp_contract> gbp_contract::m_db; + +gbp_contract::event_handler gbp_contract::m_evh; + +gbp_contract::gbp_contract(epg_id_t src_epg_id, + epg_id_t dst_epg_id, + const ACL::l3_list& acl) + : m_hw(false) + , m_src_epg_id(src_epg_id) + , m_dst_epg_id(dst_epg_id) + , m_acl(acl.singular()) +{ +} + +gbp_contract::gbp_contract(const gbp_contract& gbpc) + : m_hw(gbpc.m_hw) + , m_src_epg_id(gbpc.m_src_epg_id) + , m_dst_epg_id(gbpc.m_dst_epg_id) + , m_acl(gbpc.m_acl) +{ +} + +gbp_contract::~gbp_contract() +{ + sweep(); + + // not in the DB anymore. + m_db.release(key(), this); +} + +const gbp_contract::key_t +gbp_contract::key() const +{ + return (std::make_pair(m_src_epg_id, m_dst_epg_id)); +} + +bool +gbp_contract::operator==(const gbp_contract& gbpc) const +{ + return ((key() == gbpc.key()) && (m_acl->handle() == gbpc.m_acl->handle())); +} + +void +gbp_contract::sweep() +{ + if (m_hw) { + HW::enqueue( + new gbp_contract_cmds::delete_cmd(m_hw, m_src_epg_id, m_dst_epg_id)); + } + HW::write(); +} + +void +gbp_contract::replay() +{ + if (m_hw) { + HW::enqueue(new gbp_contract_cmds::create_cmd( + m_hw, m_src_epg_id, m_dst_epg_id, m_acl->handle())); + } +} + +std::string +gbp_contract::to_string() const +{ + std::ostringstream s; + s << "gbp-contract:[{" << m_src_epg_id << ", " << m_dst_epg_id << "}, " + << m_acl->to_string() << "]"; + + return (s.str()); +} + +void +gbp_contract::update(const gbp_contract& r) +{ + /* + * create the table if it is not yet created + */ + if (rc_t::OK != m_hw.rc()) { + HW::enqueue(new gbp_contract_cmds::create_cmd( + m_hw, m_src_epg_id, m_dst_epg_id, m_acl->handle())); + } +} + +std::shared_ptr<gbp_contract> +gbp_contract::find_or_add(const gbp_contract& temp) +{ + return (m_db.find_or_add(temp.key(), temp)); +} + +std::shared_ptr<gbp_contract> +gbp_contract::find(const key_t& k) +{ + return (m_db.find(k)); +} + +std::shared_ptr<gbp_contract> +gbp_contract::singular() const +{ + return find_or_add(*this); +} + +void +gbp_contract::dump(std::ostream& os) +{ + m_db.dump(os); +} + +gbp_contract::event_handler::event_handler() +{ + OM::register_listener(this); + inspect::register_handler({ "gbp-contract" }, "GBP Contract", this); +} + +void +gbp_contract::event_handler::handle_replay() +{ + m_db.replay(); +} + +void +gbp_contract::event_handler::handle_populate(const client_db::key_t& key) +{ + std::shared_ptr<gbp_contract_cmds::dump_cmd> cmd = + std::make_shared<gbp_contract_cmds::dump_cmd>(); + + HW::enqueue(cmd); + HW::write(); + + for (auto& record : *cmd) { + auto& payload = record.get_payload(); + + std::shared_ptr<ACL::l3_list> acl = + ACL::l3_list::find(payload.contract.acl_index); + + if (acl) { + gbp_contract gbpc(payload.contract.src_epg, payload.contract.dst_epg, + *acl); + OM::commit(key, gbpc); + + VOM_LOG(log_level_t::DEBUG) << "read: " << gbpc.to_string(); + } + } +} + +dependency_t +gbp_contract::event_handler::order() const +{ + return (dependency_t::ENTRY); +} + +void +gbp_contract::event_handler::show(std::ostream& os) +{ + m_db.dump(os); +} + +std::ostream& +operator<<(std::ostream& os, const gbp_contract::key_t& key) +{ + os << "{ " << key.first << "," << key.second << "}"; + + return (os); +} + +} // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ diff --git a/src/vpp-api/vom/gbp_contract.hpp b/src/vpp-api/vom/gbp_contract.hpp new file mode 100644 index 00000000000..7a0696de7b3 --- /dev/null +++ b/src/vpp-api/vom/gbp_contract.hpp @@ -0,0 +1,188 @@ +/* + * 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_CONTRACT_H__ +#define __VOM_GBP_CONTRACT_H__ + +#include "vom/acl_list.hpp" +#include "vom/gbp_endpoint.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_contract : public object_base +{ +public: + /** + * The key for a contract is the pari of EPG-IDs + */ + typedef std::pair<epg_id_t, epg_id_t> key_t; + + /** + * Construct a GBP contract + */ + gbp_contract(epg_id_t src_epg_id, + epg_id_t dst_epg_id, + const ACL::l3_list& acl); + + /** + * Copy Construct + */ + gbp_contract(const gbp_contract& r); + + /** + * Destructor + */ + ~gbp_contract(); + + /** + * Return the object's key + */ + const key_t key() const; + + /** + * comparison operator + */ + bool operator==(const gbp_contract& bdae) const; + + /** + * Return the matching 'singular instance' + */ + std::shared_ptr<gbp_contract> singular() const; + + /** + * Find the instnace of the bridge_domain domain in the OM + */ + static std::shared_ptr<gbp_contract> 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_contract& obj); + + /** + * Find or add the instance of the contract domain in the OM + */ + static std::shared_ptr<gbp_contract> find_or_add(const gbp_contract& 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_contract>; + + /** + * Sweep/reap the object if still stale + */ + void sweep(void); + + /** + * HW configuration for the result of creating the endpoint + */ + HW::item<bool> m_hw; + + /** + * The source EPG ID + */ + epg_id_t m_src_epg_id; + + /** + * The destination EPG ID + */ + epg_id_t m_dst_epg_id; + + /** + * The ACL applied to traffic between the gourps + */ + std::shared_ptr<ACL::l3_list> m_acl; + + /** + * A map of all bridge_domains + */ + static singular_db<key_t, gbp_contract> m_db; +}; + +std::ostream& operator<<(std::ostream& os, const gbp_contract::key_t& key); +}; // namespace + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ + +#endif diff --git a/src/vpp-api/vom/gbp_contract_cmds.cpp b/src/vpp-api/vom/gbp_contract_cmds.cpp new file mode 100644 index 00000000000..a98dc62bc59 --- /dev/null +++ b/src/vpp-api/vom/gbp_contract_cmds.cpp @@ -0,0 +1,145 @@ +/* + * 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_contract_cmds.hpp" + +namespace VOM { +namespace gbp_contract_cmds { + +create_cmd::create_cmd(HW::item<bool>& item, + epg_id_t src_epg_id, + epg_id_t dst_epg_id, + const handle_t& acl) + : rpc_cmd(item) + , m_src_epg_id(src_epg_id) + , m_dst_epg_id(dst_epg_id) + , m_acl(acl) +{ +} + +bool +create_cmd::operator==(const create_cmd& other) const +{ + return ((m_acl == other.m_acl) && (m_src_epg_id == other.m_src_epg_id) && + (m_dst_epg_id == other.m_dst_epg_id)); +} + +rc_t +create_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 1; + payload.contract.acl_index = m_acl.value(); + payload.contract.src_epg = m_src_epg_id; + payload.contract.dst_epg = m_dst_epg_id; + + VAPI_CALL(req.execute()); + + m_hw_item.set(wait()); + + return rc_t::OK; +} + +std::string +create_cmd::to_string() const +{ + std::ostringstream s; + s << "gbp-contract-create: " << m_hw_item.to_string() + << " src-epg-id:" << m_src_epg_id << " dst-epg-id:" << m_dst_epg_id + << " acl:" << m_acl; + + return (s.str()); +} + +delete_cmd::delete_cmd(HW::item<bool>& item, + epg_id_t src_epg_id, + epg_id_t dst_epg_id) + : rpc_cmd(item) + , m_src_epg_id(src_epg_id) + , m_dst_epg_id(dst_epg_id) +{ +} + +bool +delete_cmd::operator==(const delete_cmd& other) const +{ + return ((m_src_epg_id == other.m_src_epg_id) && + (m_dst_epg_id == other.m_dst_epg_id)); +} + +rc_t +delete_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 0; + payload.contract.acl_index = ~0; + payload.contract.src_epg = m_src_epg_id; + payload.contract.dst_epg = m_dst_epg_id; + + VAPI_CALL(req.execute()); + + m_hw_item.set(wait()); + + return rc_t::OK; +} + +std::string +delete_cmd::to_string() const +{ + std::ostringstream s; + s << "gbp-contract-delete: " << m_hw_item.to_string() + << " src-epg-id:" << m_src_epg_id << " dst-epg-id:" << m_dst_epg_id; + + 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-contract-dump"); +} + +}; // namespace gbp_contract_cmds +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ diff --git a/src/vpp-api/vom/gbp_contract_cmds.hpp b/src/vpp-api/vom/gbp_contract_cmds.hpp new file mode 100644 index 00000000000..705c1a0a3db --- /dev/null +++ b/src/vpp-api/vom/gbp_contract_cmds.hpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __VOM_GBP_CONTRACT_CMDS_H__ +#define __VOM_GBP_CONTRACT_CMDS_H__ + +#include "vom/dump_cmd.hpp" +#include "vom/gbp_contract.hpp" + +#include <vapi/gbp.api.vapi.hpp> + +namespace VOM { +namespace gbp_contract_cmds { + +/** +* A command class that creates or updates the GBP contract +*/ +class create_cmd + : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_contract_add_del> +{ +public: + /** + * Constructor + */ + create_cmd(HW::item<bool>& item, + epg_id_t src_epg_id, + epg_id_t dst_epg_id, + const handle_t& acl); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const create_cmd& i) const; + +private: + const epg_id_t m_src_epg_id; + const epg_id_t m_dst_epg_id; + const handle_t m_acl; +}; + +/** + * A cmd class that deletes a GBP contract + */ +class delete_cmd + : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_contract_add_del> +{ +public: + /** + * Constructor + */ + delete_cmd(HW::item<bool>& item, epg_id_t src_epg_id, epg_id_t dst_epg_id); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const delete_cmd& i) const; + +private: + const epg_id_t m_src_epg_id; + const epg_id_t m_dst_epg_id; +}; + +/** + * A cmd class that Dumps all the GBP endpoints + */ +class dump_cmd : public VOM::dump_cmd<vapi::Gbp_contract_dump> +{ +public: + /** + * Constructor + */ + dump_cmd() = default; + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const dump_cmd& i) const; + +private: + /** + * HW reutrn code + */ + HW::item<bool> item; +}; +}; // namespace gbp_contract_cmds +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ + +#endif diff --git a/src/vpp-api/vom/gbp_endpoint.cpp b/src/vpp-api/vom/gbp_endpoint.cpp new file mode 100644 index 00000000000..429183bd210 --- /dev/null +++ b/src/vpp-api/vom/gbp_endpoint.cpp @@ -0,0 +1,187 @@ +/* + * 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_endpoint.hpp" +#include "vom/gbp_endpoint_cmds.hpp" + +namespace VOM { + +singular_db<gbp_endpoint::key_t, gbp_endpoint> gbp_endpoint::m_db; + +gbp_endpoint::event_handler gbp_endpoint::m_evh; + +gbp_endpoint::gbp_endpoint(const interface& itf, + const boost::asio::ip::address& ip_addr, + epg_id_t epg_id) + : m_hw(false) + , m_itf(itf.singular()) + , m_ip_addr(ip_addr) + , m_epg_id(epg_id) +{ +} + +gbp_endpoint::gbp_endpoint(const gbp_endpoint& gbpe) + : m_hw(gbpe.m_hw) + , m_itf(gbpe.m_itf) + , m_ip_addr(gbpe.m_ip_addr) + , m_epg_id(gbpe.m_epg_id) +{ +} + +gbp_endpoint::~gbp_endpoint() +{ + sweep(); + + // not in the DB anymore. + m_db.release(key(), this); +} + +const gbp_endpoint::key_t +gbp_endpoint::key() const +{ + return (std::make_pair(m_itf->key(), m_ip_addr)); +} + +bool +gbp_endpoint::operator==(const gbp_endpoint& gbpe) const +{ + return ((key() == gbpe.key()) && (m_epg_id == gbpe.m_epg_id)); +} + +void +gbp_endpoint::sweep() +{ + if (m_hw) { + HW::enqueue( + new gbp_endpoint_cmds::delete_cmd(m_hw, m_itf->handle(), m_ip_addr)); + } + HW::write(); +} + +void +gbp_endpoint::replay() +{ + if (m_hw) { + HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(), + m_ip_addr, m_epg_id)); + } +} + +std::string +gbp_endpoint::to_string() const +{ + std::ostringstream s; + s << "gbp-endpoint:[" << m_itf->to_string() << ", " << m_ip_addr.to_string() + << ", epg-id:" << m_epg_id << "]"; + + return (s.str()); +} + +void +gbp_endpoint::update(const gbp_endpoint& r) +{ + /* + * create the table if it is not yet created + */ + if (rc_t::OK != m_hw.rc()) { + HW::enqueue(new gbp_endpoint_cmds::create_cmd(m_hw, m_itf->handle(), + m_ip_addr, m_epg_id)); + } +} + +std::shared_ptr<gbp_endpoint> +gbp_endpoint::find_or_add(const gbp_endpoint& temp) +{ + return (m_db.find_or_add(temp.key(), temp)); +} + +std::shared_ptr<gbp_endpoint> +gbp_endpoint::find(const key_t& k) +{ + return (m_db.find(k)); +} + +std::shared_ptr<gbp_endpoint> +gbp_endpoint::singular() const +{ + return find_or_add(*this); +} + +void +gbp_endpoint::dump(std::ostream& os) +{ + m_db.dump(os); +} + +gbp_endpoint::event_handler::event_handler() +{ + OM::register_listener(this); + inspect::register_handler({ "gbp-endpoint" }, "GBP Endpoints", this); +} + +void +gbp_endpoint::event_handler::handle_replay() +{ + m_db.replay(); +} + +void +gbp_endpoint::event_handler::handle_populate(const client_db::key_t& key) +{ + std::shared_ptr<gbp_endpoint_cmds::dump_cmd> cmd = + std::make_shared<gbp_endpoint_cmds::dump_cmd>(); + + HW::enqueue(cmd); + HW::write(); + + for (auto& record : *cmd) { + auto& payload = record.get_payload(); + + boost::asio::ip::address address = + from_bytes(payload.endpoint.is_ip6, payload.endpoint.address); + std::shared_ptr<interface> itf = + interface::find(payload.endpoint.sw_if_index); + + VOM_LOG(log_level_t::DEBUG) << "data: " << payload.endpoint.sw_if_index; + + if (itf) { + gbp_endpoint gbpe(*itf, address, payload.endpoint.epg_id); + OM::commit(key, gbpe); + + VOM_LOG(log_level_t::DEBUG) << "read: " << gbpe.to_string(); + } + } +} + +dependency_t +gbp_endpoint::event_handler::order() const +{ + return (dependency_t::ENTRY); +} + +void +gbp_endpoint::event_handler::show(std::ostream& os) +{ + m_db.dump(os); +} +} // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ diff --git a/src/vpp-api/vom/gbp_endpoint.hpp b/src/vpp-api/vom/gbp_endpoint.hpp new file mode 100644 index 00000000000..9118cb80eb1 --- /dev/null +++ b/src/vpp-api/vom/gbp_endpoint.hpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __VOM_GBP_ENDPOINT_H__ +#define __VOM_GBP_ENDPOINT_H__ + +#include "vom/interface.hpp" +#include "vom/singular_db.hpp" +#include "vom/types.hpp" + +namespace VOM { + +/** + * EPG IDs are 32 bit integers + */ +typedef uint32_t epg_id_t; + +/** + * A entry in the ARP termination table of a Bridge Domain + */ +class gbp_endpoint : public object_base +{ +public: + /** + * The key for a GBP endpoint; interface and IP + */ + typedef std::pair<interface::key_t, boost::asio::ip::address> key_t; + + /** + * Construct a GBP endpoint + */ + gbp_endpoint(const interface& itf, + const boost::asio::ip::address& ip_addr, + epg_id_t epg_id); + + /** + * Copy Construct + */ + gbp_endpoint(const gbp_endpoint& r); + + /** + * Destructor + */ + ~gbp_endpoint(); + + /** + * Return the object's key + */ + const key_t key() const; + + /** + * comparison operator + */ + bool operator==(const gbp_endpoint& bdae) const; + + /** + * Return the matching 'singular instance' + */ + std::shared_ptr<gbp_endpoint> singular() const; + + /** + * Find the instnace of the bridge_domain domain in the OM + */ + static std::shared_ptr<gbp_endpoint> 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_endpoint& obj); + + /** + * Find or add the instnace of the bridge_domain domain in the OM + */ + static std::shared_ptr<gbp_endpoint> find_or_add(const gbp_endpoint& temp); + + /* + * It's the VPPHW class that updates the objects in HW + */ + friend class OM; + + /** + * It's the singular_db class that calls replay() + */ + friend class singular_db<key_t, gbp_endpoint>; + + /** + * Sweep/reap the object if still stale + */ + void sweep(void); + + /** + * HW configuration for the result of creating the endpoint + */ + HW::item<bool> m_hw; + + /** + * The interface the endpoint is attached to. + */ + std::shared_ptr<interface> m_itf; + + /** + * The IP address of the endpoint + */ + boost::asio::ip::address m_ip_addr; + + /** + * The EPG ID + */ + epg_id_t m_epg_id; + + /** + * A map of all bridge_domains + */ + static singular_db<key_t, gbp_endpoint> m_db; +}; + +std::ostream& operator<<(std::ostream& os, const gbp_endpoint::key_t& key); +}; // namespace + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ + +#endif diff --git a/src/vpp-api/vom/gbp_endpoint_cmds.cpp b/src/vpp-api/vom/gbp_endpoint_cmds.cpp new file mode 100644 index 00000000000..5a8247a4250 --- /dev/null +++ b/src/vpp-api/vom/gbp_endpoint_cmds.cpp @@ -0,0 +1,149 @@ +/* + * 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_endpoint_cmds.hpp" + +DEFINE_VAPI_MSG_IDS_GBP_API_JSON; + +namespace VOM { +namespace gbp_endpoint_cmds { + +create_cmd::create_cmd(HW::item<bool>& item, + const handle_t& itf, + const boost::asio::ip::address& ip_addr, + epg_id_t epg_id) + : rpc_cmd(item) + , m_itf(itf) + , m_ip_addr(ip_addr) + , m_epg_id(epg_id) +{ +} + +bool +create_cmd::operator==(const create_cmd& other) const +{ + return ((m_itf == other.m_itf) && (m_ip_addr == other.m_ip_addr) && + (m_epg_id == other.m_epg_id)); +} + +rc_t +create_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 1; + payload.endpoint.sw_if_index = m_itf.value(); + payload.endpoint.epg_id = m_epg_id; + to_bytes(m_ip_addr, &payload.endpoint.is_ip6, payload.endpoint.address); + + VAPI_CALL(req.execute()); + + m_hw_item.set(wait()); + + return rc_t::OK; +} + +std::string +create_cmd::to_string() const +{ + std::ostringstream s; + s << "gbp-endpoint-create: " << m_hw_item.to_string() << " itf:" << m_itf + << " ip:" << m_ip_addr.to_string() << " epg-id:" << m_epg_id; + + return (s.str()); +} + +delete_cmd::delete_cmd(HW::item<bool>& item, + const handle_t& itf, + const boost::asio::ip::address& ip_addr) + : rpc_cmd(item) + , m_itf(itf) + , m_ip_addr(ip_addr) +{ +} + +bool +delete_cmd::operator==(const delete_cmd& other) const +{ + return ((m_itf == other.m_itf) && (m_ip_addr == other.m_ip_addr)); +} + +rc_t +delete_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 0; + payload.endpoint.sw_if_index = m_itf.value(); + payload.endpoint.epg_id = ~0; + to_bytes(m_ip_addr, &payload.endpoint.is_ip6, payload.endpoint.address); + + VAPI_CALL(req.execute()); + + m_hw_item.set(wait()); + + return rc_t::OK; +} + +std::string +delete_cmd::to_string() const +{ + std::ostringstream s; + s << "gbp-endpoint-create: " << m_hw_item.to_string() << " itf:" << m_itf + << " ip:" << m_ip_addr.to_string(); + + return (s.str()); +} + +dump_cmd::dump_cmd() +{ +} + +bool +dump_cmd::operator==(const dump_cmd& other) const +{ + return (true); +} + +rc_t +dump_cmd::issue(connection& con) +{ + m_dump.reset(new msg_t(con.ctx(), std::ref(*this))); + + VAPI_CALL(m_dump->execute()); + + wait(); + + return rc_t::OK; +} + +std::string +dump_cmd::to_string() const +{ + return ("gbp-endpoint-dump"); +} + +}; // namespace gbp_endpoint_cmds +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ diff --git a/src/vpp-api/vom/gbp_endpoint_cmds.hpp b/src/vpp-api/vom/gbp_endpoint_cmds.hpp new file mode 100644 index 00000000000..cc7884979e8 --- /dev/null +++ b/src/vpp-api/vom/gbp_endpoint_cmds.hpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __VOM_GBP_ENDPOINT_CMDS_H__ +#define __VOM_GBP_ENDPOINT_CMDS_H__ + +#include "vom/dump_cmd.hpp" +#include "vom/gbp_endpoint.hpp" + +#include <vapi/gbp.api.vapi.hpp> + +namespace VOM { +namespace gbp_endpoint_cmds { + +/** +* A command class that creates or updates the GBP endpoint +*/ +class create_cmd + : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_endpoint_add_del> +{ +public: + /** + * Constructor + */ + create_cmd(HW::item<bool>& item, + const handle_t& itf, + const boost::asio::ip::address& ip_addr, + epg_id_t epg_id); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const create_cmd& i) const; + +private: + const handle_t m_itf; + const boost::asio::ip::address m_ip_addr; + const epg_id_t m_epg_id; +}; + +/** + * A cmd class that deletes a GBP endpoint + */ +class delete_cmd + : public rpc_cmd<HW::item<bool>, rc_t, vapi::Gbp_endpoint_add_del> +{ +public: + /** + * Constructor + */ + delete_cmd(HW::item<bool>& item, + const handle_t& itf, + const boost::asio::ip::address& ip_addr); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const delete_cmd& i) const; + +private: + const handle_t m_itf; + const boost::asio::ip::address m_ip_addr; +}; + +/** + * A cmd class that Dumps all the GBP endpoints + */ +class dump_cmd : public VOM::dump_cmd<vapi::Gbp_endpoint_dump> +{ +public: + /** + * Constructor + */ + dump_cmd(); + dump_cmd(const dump_cmd& d); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const dump_cmd& i) const; + +private: + /** + * HW reutrn code + */ + HW::item<bool> item; +}; +}; // namespace gbp_enpoint_cms +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ + +#endif diff --git a/src/vpp-api/vom/l2_emulation.cpp b/src/vpp-api/vom/l2_emulation.cpp index 2a2757616be..75e3bffb2ec 100644 --- a/src/vpp-api/vom/l2_emulation.cpp +++ b/src/vpp-api/vom/l2_emulation.cpp @@ -74,7 +74,7 @@ l2_emulation::replay() { if (m_emulation && handle_t::INVALID != m_itf->handle()) { HW::enqueue( - new l2_emulation_cmds::disable_cmd(m_emulation, m_itf->handle())); + new l2_emulation_cmds::enable_cmd(m_emulation, m_itf->handle())); } } diff --git a/src/vpp-api/vom/l2_emulation_cmds.cpp b/src/vpp-api/vom/l2_emulation_cmds.cpp index 07107d6ff58..27f84830191 100644 --- a/src/vpp-api/vom/l2_emulation_cmds.cpp +++ b/src/vpp-api/vom/l2_emulation_cmds.cpp @@ -51,7 +51,7 @@ std::string enable_cmd::to_string() const { std::ostringstream s; - s << "L2-emulation: " << m_hw_item.to_string() + s << "L2-emulation-enable: " << m_hw_item.to_string() << " itf:" << m_itf.to_string(); return (s.str()); @@ -89,7 +89,7 @@ std::string disable_cmd::to_string() const { std::ostringstream s; - s << "L2-emulation: " << m_hw_item.to_string() + s << "L2-emulation-disable: " << m_hw_item.to_string() << " itf:" << m_itf.to_string(); return (s.str()); |