diff options
author | Neale Ranns <neale.ranns@cisco.com> | 2018-02-20 08:10:44 -0800 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2018-02-22 19:57:08 +0000 |
commit | 4ef4226282685a049aad439080ca5478da09ac06 (patch) | |
tree | d9cefcdd79d9d5195b3862e56924ce8abb9218e8 | |
parent | de0203edd2177f627cc655b52ffdf921d94d5d26 (diff) |
VOM: vhost-use interfaces
Change-Id: Iee1574d1f0f081ccc4a90fd9825a0b5e254aa642
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
-rw-r--r-- | src/vpp-api/vom/interface.cpp | 55 | ||||
-rw-r--r-- | src/vpp-api/vom/interface.hpp | 28 | ||||
-rw-r--r-- | src/vpp-api/vom/interface_cmds.cpp | 110 | ||||
-rw-r--r-- | src/vpp-api/vom/interface_cmds.hpp | 70 | ||||
-rw-r--r-- | src/vpp-api/vom/interface_factory.cpp | 45 | ||||
-rw-r--r-- | src/vpp-api/vom/interface_factory.hpp | 4 | ||||
-rw-r--r-- | src/vpp-api/vom/interface_types.cpp | 6 | ||||
-rw-r--r-- | test/ext/vom_test.cpp | 30 |
8 files changed, 332 insertions, 16 deletions
diff --git a/src/vpp-api/vom/interface.cpp b/src/vpp-api/vom/interface.cpp index 9fa96af2d97..f943bf4a616 100644 --- a/src/vpp-api/vom/interface.cpp +++ b/src/vpp-api/vom/interface.cpp @@ -38,7 +38,8 @@ interface::event_handler interface::m_evh; */ interface::interface(const std::string& name, interface::type_t itf_type, - interface::admin_state_t itf_state) + interface::admin_state_t itf_state, + const std::string& tag) : m_hdl(handle_t::INVALID) , m_name(name) , m_type(itf_type) @@ -46,13 +47,15 @@ interface::interface(const std::string& name, , m_table_id(route::DEFAULT_TABLE) , m_l2_address(l2_address_t::ZERO, rc_t::UNSET) , m_oper(oper_state_t::DOWN) + , m_tag(tag) { } interface::interface(const std::string& name, interface::type_t itf_type, interface::admin_state_t itf_state, - const route_domain& rd) + const route_domain& rd, + const std::string& tag) : m_hdl(handle_t::INVALID) , m_name(name) , m_type(itf_type) @@ -61,6 +64,7 @@ interface::interface(const std::string& name, , m_table_id(m_rd->table_id()) , m_l2_address(l2_address_t::ZERO, rc_t::UNSET) , m_oper(oper_state_t::DOWN) + , m_tag(tag) { } @@ -73,6 +77,7 @@ interface::interface(const interface& o) , m_table_id(o.m_table_id) , m_l2_address(o.m_l2_address) , m_oper(o.m_oper) + , m_tag(o.m_tag) { } @@ -221,7 +226,13 @@ interface::to_string() const } s << " admin-state:" << m_state.to_string() - << " oper-state:" << m_oper.to_string() << "]"; + << " oper-state:" << m_oper.to_string(); + + if (!m_tag.empty()) { + s << " tag:[" << m_tag << "]"; + } + + s << "]"; return (s.str()); } @@ -246,10 +257,20 @@ interface::mk_create_cmd(std::queue<cmd*>& q) } else if (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)); + /* + * set the m_tag for pretty-print + */ + m_tag = m_name; } else if (type_t::AFPACKET == m_type) { q.push(new interface_cmds::af_packet_create_cmd(m_hdl, m_name)); + if (!m_tag.empty()) + q.push(new interface_cmds::set_tag(m_hdl, m_tag)); } else if (type_t::TAP == m_type) { q.push(new interface_cmds::tap_create_cmd(m_hdl, m_name)); + if (!m_tag.empty()) + q.push(new interface_cmds::set_tag(m_hdl, m_tag)); + } else if (type_t::VHOST == m_type) { + q.push(new interface_cmds::vhost_create_cmd(m_hdl, m_name, m_tag)); } else { m_hdl.set(rc_t::OK); } @@ -266,6 +287,8 @@ interface::mk_delete_cmd(std::queue<cmd*>& q) q.push(new interface_cmds::af_packet_delete_cmd(m_hdl, m_name)); } else if (type_t::TAP == m_type) { q.push(new interface_cmds::tap_delete_cmd(m_hdl)); + } else if (type_t::VHOST == m_type) { + q.push(new interface_cmds::vhost_delete_cmd(m_hdl, m_name)); } return (q); @@ -345,6 +368,12 @@ interface::update(const interface& desired) } void +interface::set(const admin_state_t& state) +{ + m_state = state; +} + +void interface::set(const l2_address_t& addr) { assert(rc_t::UNSET == m_l2_address.rc()); @@ -365,6 +394,12 @@ interface::set(const oper_state_t& state) } void +interface::set(const std::string& tag) +{ + m_tag = tag; +} + +void interface::enable_stats_i(interface::stat_listener& el) { if (!m_stats) { @@ -429,6 +464,20 @@ interface::dump(std::ostream& os) void interface::event_handler::handle_populate(const client_db::key_t& key) { + std::shared_ptr<interface_cmds::vhost_dump_cmd> vcmd = + std::make_shared<interface_cmds::vhost_dump_cmd>(); + + HW::enqueue(vcmd); + HW::write(); + + for (auto& vhost_itf_record : *vcmd) { + std::shared_ptr<interface> vitf = + interface_factory::new_vhost_user_interface( + vhost_itf_record.get_payload()); + VOM_LOG(log_level_t::DEBUG) << "dump: " << vitf->to_string(); + OM::commit(key, *vitf); + } + /* * dump VPP current states */ diff --git a/src/vpp-api/vom/interface.hpp b/src/vpp-api/vom/interface.hpp index da0db409e62..5d2951007a2 100644 --- a/src/vpp-api/vom/interface.hpp +++ b/src/vpp-api/vom/interface.hpp @@ -91,6 +91,11 @@ public: const static type_t TAP; /** + * vhost-user interface type + */ + const static type_t VHOST; + + /** * Convert VPP's name of the interface to a type */ static type_t from_string(const std::string& str); @@ -157,7 +162,10 @@ public: /** * Construct a new object matching the desried state */ - interface(const std::string& name, type_t type, admin_state_t state); + interface(const std::string& name, + type_t type, + admin_state_t state, + const std::string& tag = ""); /** * Construct a new object matching the desried state mapped * to a specific route_domain @@ -165,7 +173,8 @@ public: interface(const std::string& name, type_t type, admin_state_t state, - const route_domain& rd); + const route_domain& rd, + const std::string& tag = ""); /** * Destructor */ @@ -215,6 +224,11 @@ public: const l2_address_t& l2_address() const; /** + * Set the admin state of the interface + */ + void set(const admin_state_t& state); + + /** * Set the L2 Address */ void set(const l2_address_t& addr); @@ -225,6 +239,11 @@ public: void set(const oper_state_t& state); /** + * Set the tag to the interface + */ + void set(const std::string& tag); + + /** * Comparison operator - only used for UT */ virtual bool operator==(const interface& i) const; @@ -581,6 +600,11 @@ private: oper_state_t m_oper; /** + * tag of the interface + */ + std::string m_tag; + + /** * A map of all interfaces keyed against VPP's handle */ static std::map<handle_t, std::weak_ptr<interface>> m_hdl_db; diff --git a/src/vpp-api/vom/interface_cmds.cpp b/src/vpp-api/vom/interface_cmds.cpp index 031aaea7288..df3415408d9 100644 --- a/src/vpp-api/vom/interface_cmds.cpp +++ b/src/vpp-api/vom/interface_cmds.cpp @@ -20,6 +20,7 @@ DEFINE_VAPI_MSG_IDS_VPE_API_JSON; DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON; DEFINE_VAPI_MSG_IDS_AF_PACKET_API_JSON; DEFINE_VAPI_MSG_IDS_TAP_API_JSON; +DEFINE_VAPI_MSG_IDS_VHOST_USER_API_JSON; DEFINE_VAPI_MSG_IDS_STATS_API_JSON; namespace VOM { @@ -129,6 +130,50 @@ tap_create_cmd::to_string() const return (s.str()); } +vhost_create_cmd::vhost_create_cmd(HW::item<handle_t>& item, + const std::string& name, + const std::string& tag) + : create_cmd(item, name) + , m_tag(tag) +{ +} + +rc_t +vhost_create_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + memset(payload.sock_filename, 0, sizeof(payload.sock_filename)); + memcpy(payload.sock_filename, m_name.c_str(), + std::min(m_name.length(), sizeof(payload.sock_filename))); + memset(payload.tag, 0, sizeof(payload.tag)); + + if (!m_tag.empty()) + memcpy(payload.tag, m_tag.c_str(), + std::min(m_tag.length(), sizeof(payload.tag))); + + payload.is_server = 1; + payload.use_custom_mac = 0; + payload.renumber = 0; + + VAPI_CALL(req.execute()); + + m_hw_item = wait(); + + return rc_t::OK; +} + +std::string +vhost_create_cmd::to_string() const +{ + std::ostringstream s; + s << "vhost-intf-create: " << m_hw_item.to_string() << " name:" << m_name + << " tag:" << m_tag; + + return (s.str()); +} + loopback_delete_cmd::loopback_delete_cmd(HW::item<handle_t>& item) : delete_cmd(item) { @@ -215,6 +260,35 @@ tap_delete_cmd::to_string() const return (s.str()); } +vhost_delete_cmd::vhost_delete_cmd(HW::item<handle_t>& item, + const std::string& name) + : delete_cmd(item, name) +{ +} + +rc_t +vhost_delete_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.sw_if_index = m_hw_item.data().value(); + + VAPI_CALL(req.execute()); + + wait(); + + return rc_t::OK; +} +std::string +vhost_delete_cmd::to_string() const +{ + std::ostringstream s; + s << "vhost-itf-delete: " << m_hw_item.to_string() << " name:" << m_name; + + return (s.str()); +} + state_change_cmd::state_change_cmd(HW::item<interface::admin_state_t>& state, const HW::item<handle_t>& hdl) : rpc_cmd(state) @@ -475,10 +549,6 @@ stats_enable_cmd::to_string() const return (s.str()); } -dump_cmd::dump_cmd() -{ -} - stats_disable_cmd::stats_disable_cmd(const handle_t& handle) : rpc_cmd(m_res) , m_swifindex(handle) @@ -521,6 +591,10 @@ stats_disable_cmd::to_string() const return (s.str()); } +dump_cmd::dump_cmd() +{ +} + bool dump_cmd::operator==(const dump_cmd& other) const { @@ -548,6 +622,34 @@ dump_cmd::to_string() const return ("itf-dump"); } +vhost_dump_cmd::vhost_dump_cmd() +{ +} + +bool +vhost_dump_cmd::operator==(const vhost_dump_cmd& other) const +{ + return (true); +} + +rc_t +vhost_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 +vhost_dump_cmd::to_string() const +{ + return ("vhost-itf-dump"); +} + set_tag::set_tag(HW::item<handle_t>& item, const std::string& name) : rpc_cmd(item) , m_name(name) diff --git a/src/vpp-api/vom/interface_cmds.hpp b/src/vpp-api/vom/interface_cmds.hpp index f21a7f3b21c..62762ef7c41 100644 --- a/src/vpp-api/vom/interface_cmds.hpp +++ b/src/vpp-api/vom/interface_cmds.hpp @@ -27,6 +27,7 @@ #include <vapi/interface.api.vapi.hpp> #include <vapi/stats.api.vapi.hpp> #include <vapi/tap.api.vapi.hpp> +#include <vapi/vhost_user.api.vapi.hpp> #include <vapi/vpe.api.vapi.hpp> namespace VOM { @@ -110,6 +111,30 @@ public: }; /** + * A functor class that creates an interface + */ +class vhost_create_cmd + : public interface::create_cmd<vapi::Create_vhost_user_if> +{ +public: + vhost_create_cmd(HW::item<handle_t>& item, + const std::string& name, + const std::string& tag); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + +private: + const std::string m_tag; +}; + +/** * A command class to delete loopback interfaces in VPP */ class loopback_delete_cmd : public interface::delete_cmd<vapi::Delete_loopback> @@ -175,6 +200,25 @@ public: }; /** + * A functor class that deletes a Vhost interface + */ +class vhost_delete_cmd + : public interface::delete_cmd<vapi::Delete_vhost_user_if> +{ +public: + vhost_delete_cmd(HW::item<handle_t>& item, const std::string& name); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; +}; + +/** * A command class to set tag on interfaces */ class set_tag @@ -479,6 +523,32 @@ public: */ bool operator==(const dump_cmd& i) const; }; + +/** + * A cmd class that Dumps all the Vpp Interfaces + */ +class vhost_dump_cmd : public VOM::dump_cmd<vapi::Sw_interface_vhost_user_dump> +{ +public: + /** + * Default Constructor + */ + vhost_dump_cmd(); + + /** + * 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 vhost_dump_cmd& i) const; +}; }; }; /* diff --git a/src/vpp-api/vom/interface_factory.cpp b/src/vpp-api/vom/interface_factory.cpp index b8815ed7ac9..ef26c3293d3 100644 --- a/src/vpp-api/vom/interface_factory.cpp +++ b/src/vpp-api/vom/interface_factory.cpp @@ -34,6 +34,7 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd) interface::admin_state_t::from_int(vd.link_up_down); handle_t hdl(vd.sw_if_index); l2_address_t l2_address(vd.l2_address, vd.l2_address_length); + std::string tag = ""; if (interface::type_t::AFPACKET == type) { /* @@ -46,7 +47,11 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd) * the interface type more specific */ if (vd.tag[0] != 0) { - name = std::string(reinterpret_cast<const char*>(vd.tag)); + tag = std::string(reinterpret_cast<const char*>(vd.tag)); + } + + if (!tag.empty() && interface::type_t::LOOPBACK == type) { + name = tag; type = interface::type_t::from_string(name); } @@ -58,6 +63,8 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd) * TAP interface */ sp = tap_interface(name, state, route::prefix_t()).singular(); + if (sp && !tag.empty()) + sp->set(tag); } else if ((name.find(".") != std::string::npos) && (0 != vd.sub_id)) { /* * Sub-interface @@ -66,15 +73,28 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd) std::vector<std::string> parts; boost::split(parts, name, boost::is_any_of(".")); - interface parent(parts[0], type, state); + interface parent(parts[0], type, state, tag); sp = sub_interface(parent, state, vd.sub_id).singular(); } else if (interface::type_t::VXLAN == type) { /* * there's not enough information in a SW interface record to - * construct a VXLAN tunnel. so skip it. + * construct a VXLAN tunnel. so skip it. They have + * their own dump routines + */ + } else if (interface::type_t::VHOST == type) { + /* + * vhost interfaces already exist in db, look for it using + * sw_if_index */ + sp = interface::find(hdl); + if (sp) { + sp->set(state); + sp->set(l2_address); + if (!tag.empty()) + sp->set(tag); + } } else { - sp = interface(name, type, state).singular(); + sp = interface(name, type, state, tag).singular(); sp->set(l2_address); } @@ -82,8 +102,23 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd) * set the handle on the intterface - N.B. this is the sigluar instance * not a stack local. */ - sp->set(hdl); + if (sp) + sp->set(hdl); + + return (sp); +} +std::shared_ptr<interface> +interface_factory::new_vhost_user_interface( + const vapi_payload_sw_interface_vhost_user_details& vd) +{ + std::shared_ptr<interface> sp; + std::string name = reinterpret_cast<const char*>(vd.sock_filename); + interface::type_t type = interface::type_t::from_string(name); + handle_t hdl(vd.sw_if_index); + + sp = interface(name, type, interface::admin_state_t::DOWN).singular(); + sp->set(hdl); return (sp); } }; // namespace VOM diff --git a/src/vpp-api/vom/interface_factory.hpp b/src/vpp-api/vom/interface_factory.hpp index e1cbb38fd83..a2c81993550 100644 --- a/src/vpp-api/vom/interface_factory.hpp +++ b/src/vpp-api/vom/interface_factory.hpp @@ -21,6 +21,7 @@ #include "vom/interface.hpp" #include <vapi/interface.api.vapi.hpp> +#include <vapi/vhost_user.api.vapi.hpp> namespace VOM { @@ -32,6 +33,9 @@ public: */ static std::shared_ptr<interface> new_interface( const vapi_payload_sw_interface_details& vd); + + static std::shared_ptr<interface> new_vhost_user_interface( + const vapi_payload_sw_interface_vhost_user_details& vd); }; }; diff --git a/src/vpp-api/vom/interface_types.cpp b/src/vpp-api/vom/interface_types.cpp index a089f589f33..6d3dcae57f2 100644 --- a/src/vpp-api/vom/interface_types.cpp +++ b/src/vpp-api/vom/interface_types.cpp @@ -27,6 +27,7 @@ const interface::type_t interface::type_t::AFPACKET(4, "AFPACKET"); const interface::type_t interface::type_t::LOOPBACK(5, "LOOPBACK"); const interface::type_t interface::type_t::LOCAL(6, "LOCAL"); const interface::type_t interface::type_t::TAP(7, "TAP"); +const interface::type_t interface::type_t::VHOST(8, "VHOST"); const interface::oper_state_t interface::oper_state_t::DOWN(0, "down"); const interface::oper_state_t interface::oper_state_t::UP(1, "up"); @@ -37,7 +38,10 @@ const interface::admin_state_t interface::admin_state_t::UP(1, "up"); interface::type_t interface::type_t::from_string(const std::string& str) { - if (str.find("Ethernet") != std::string::npos) { + if ((str.find("Virtual") != std::string::npos) || + (str.find("vhost") != std::string::npos)) { + return interface::type_t::VHOST; + } else if (str.find("Ethernet") != std::string::npos) { return interface::type_t::ETHERNET; } else if (str.find("vxlan") != std::string::npos) { return interface::type_t::VXLAN; diff --git a/test/ext/vom_test.cpp b/test/ext/vom_test.cpp index 4c09ab4439c..9f7cfd6f208 100644 --- a/test/ext/vom_test.cpp +++ b/test/ext/vom_test.cpp @@ -174,6 +174,10 @@ public: { rc = handle_derived<interface_cmds::loopback_create_cmd>(f_exp, f_act); } + else if (typeid(*f_exp) == typeid(interface_cmds::vhost_create_cmd)) + { + rc = handle_derived<interface_cmds::vhost_create_cmd>(f_exp, f_act); + } else if (typeid(*f_exp) == typeid(interface_cmds::loopback_delete_cmd)) { rc = handle_derived<interface_cmds::loopback_delete_cmd>(f_exp, f_act); @@ -182,6 +186,10 @@ public: { rc = handle_derived<interface_cmds::af_packet_delete_cmd>(f_exp, f_act); } + else if (typeid(*f_exp) == typeid(interface_cmds::vhost_delete_cmd)) + { + rc = handle_derived<interface_cmds::vhost_delete_cmd>(f_exp, f_act); + } else if (typeid(*f_exp) == typeid(interface_cmds::state_change_cmd)) { rc = handle_derived<interface_cmds::state_change_cmd>(f_exp, f_act); @@ -605,12 +613,15 @@ BOOST_AUTO_TEST_CASE(test_interface) { TRY_CHECK(OM::mark(go)); std::string itf2_name = "afpacket2"; + std::string itf2_tag = "uuid-of-afpacket2-interface"; interface itf2(itf2_name, interface::type_t::AFPACKET, - interface::admin_state_t::UP); + interface::admin_state_t::UP, + itf2_tag); HW::item<handle_t> hw_ifh2(3, rc_t::OK); ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name)); + ADD_EXPECT(interface_cmds::set_tag(hw_ifh2, itf2_tag)); ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh2)); TRY_CHECK_RC(OM::write(go, itf2)); @@ -623,6 +634,23 @@ BOOST_AUTO_TEST_CASE(test_interface) { ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh2)); ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name)); TRY_CHECK(OM::sweep(go)); + + + std::string itf3_name = "/PATH/TO/vhost_user1.sock"; + std::string itf3_tag = "uuid-of-vhost_user1-interface"; + interface itf3(itf3_name, + interface::type_t::VHOST, + interface::admin_state_t::UP, + itf3_tag); + HW::item<handle_t> hw_ifh3(4, rc_t::OK); + + ADD_EXPECT(interface_cmds::vhost_create_cmd(hw_ifh3, itf3_name, itf3_tag)); + ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh3)); + TRY_CHECK_RC(OM::write(go, itf3)); + + ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh3)); + ADD_EXPECT(interface_cmds::vhost_delete_cmd(hw_ifh3, itf3_name)); + TRY_CHECK(OM::remove(go)); } BOOST_AUTO_TEST_CASE(test_bvi) { |