VOM: vhost-use interfaces
Change-Id: Iee1574d1f0f081ccc4a90fd9825a0b5e254aa642
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
diff --git a/src/vpp-api/vom/interface.cpp b/src/vpp-api/vom/interface.cpp
index 9fa96af..f943bf4 100644
--- a/src/vpp-api/vom/interface.cpp
+++ b/src/vpp-api/vom/interface.cpp
@@ -38,7 +38,8 @@
*/
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 @@
, 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 @@
, 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 @@
, 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 @@
}
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 @@
} 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 @@
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 @@
}
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 @@
}
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 @@
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 da0db40..5d29510 100644
--- a/src/vpp-api/vom/interface.hpp
+++ b/src/vpp-api/vom/interface.hpp
@@ -91,6 +91,11 @@
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 @@
/**
* 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 @@
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 @@
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 @@
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 @@
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 031aaea..df34154 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_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 @@
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 @@
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 @@
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 @@
return (s.str());
}
+dump_cmd::dump_cmd()
+{
+}
+
bool
dump_cmd::operator==(const dump_cmd& other) const
{
@@ -548,6 +622,34 @@
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 f21a7f3..62762ef 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 @@
};
/**
+ * 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 @@
};
/**
+ * 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 @@
*/
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 b8815ed..ef26c32 100644
--- a/src/vpp-api/vom/interface_factory.cpp
+++ b/src/vpp-api/vom/interface_factory.cpp
@@ -34,6 +34,7 @@
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 @@
* 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 @@
* 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 @@
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,10 +102,25 @@
* 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 e1cbb38..a2c8199 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 @@
*/
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 a089f58..6d3dcae 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::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 @@
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;