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