*/
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)
, 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)
, 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)
{
}
, m_table_id(o.m_table_id)
, m_l2_address(o.m_l2_address)
, m_oper(o.m_oper)
+ , m_tag(o.m_tag)
{
}
}
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());
}
} 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);
}
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);
}
}
+void
+interface::set(const admin_state_t& state)
+{
+ m_state = state;
+}
+
void
interface::set(const l2_address_t& addr)
{
m_oper = state;
}
+void
+interface::set(const std::string& tag)
+{
+ m_tag = tag;
+}
+
void
interface::enable_stats_i(interface::stat_listener& el)
{
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
*/
*/
const static type_t TAP;
+ /**
+ * vhost-user interface type
+ */
+ const static type_t VHOST;
+
/**
* Convert VPP's name of the interface to a type
*/
/**
* 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
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
*/
*/
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 oper_state_t& state);
+ /**
+ * Set the tag to the interface
+ */
+ void set(const std::string& tag);
+
/**
* Comparison operator - only used for UT
*/
*/
oper_state_t m_oper;
+ /**
+ * tag of the interface
+ */
+ std::string m_tag;
+
/**
* A map of all interfaces keyed against VPP's handle
*/
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 {
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)
{
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)
return (s.str());
}
-dump_cmd::dump_cmd()
-{
-}
-
stats_disable_cmd::stats_disable_cmd(const handle_t& handle)
: rpc_cmd(m_res)
, m_swifindex(handle)
return (s.str());
}
+dump_cmd::dump_cmd()
+{
+}
+
bool
dump_cmd::operator==(const dump_cmd& other) 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)
#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 {
std::string to_string() const;
};
+/**
+ * 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
*/
std::string to_string() const;
};
+/**
+ * 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
*/
*/
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;
+};
};
};
/*
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) {
/*
* 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);
}
* 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
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);
}
* 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
#include "vom/interface.hpp"
#include <vapi/interface.api.vapi.hpp>
+#include <vapi/vhost_user.api.vapi.hpp>
namespace VOM {
*/
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);
};
};
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");
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;
{
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);
{
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);
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));
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) {