aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extras/vom/CMakeLists.txt1
-rw-r--r--extras/vom/vom/CMakeLists.txt28
-rw-r--r--extras/vom/vom/hw.cpp27
-rw-r--r--extras/vom/vom/hw.hpp17
-rw-r--r--extras/vom/vom/interface.cpp111
-rw-r--r--extras/vom/vom/interface.hpp78
-rw-r--r--extras/vom/vom/interface_cmds.cpp132
-rw-r--r--extras/vom/vom/interface_cmds.hpp96
-rw-r--r--extras/vom/vom/stat_client.cpp233
-rw-r--r--extras/vom/vom/stat_client.hpp221
-rw-r--r--extras/vom/vom/stat_reader.cpp117
-rw-r--r--extras/vom/vom/stat_reader.hpp103
-rw-r--r--extras/vom/vom/test_stats.cpp92
-rw-r--r--test/ext/vom_test.cpp2
14 files changed, 991 insertions, 267 deletions
diff --git a/extras/vom/CMakeLists.txt b/extras/vom/CMakeLists.txt
index 6ed14cd75a2..a04df5d52ab 100644
--- a/extras/vom/CMakeLists.txt
+++ b/extras/vom/CMakeLists.txt
@@ -24,6 +24,7 @@ set(CMAKE_INSTALL_MESSAGE NEVER)
find_package(VPP)
find_package(Threads REQUIRED)
+find_package(Boost OPTIONAL_COMPONENTS system filesystem)
add_subdirectory(vom)
diff --git a/extras/vom/vom/CMakeLists.txt b/extras/vom/vom/CMakeLists.txt
index 47e73b6e7a0..bd8986a4864 100644
--- a/extras/vom/vom/CMakeLists.txt
+++ b/extras/vom/vom/CMakeLists.txt
@@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+unset (VPPAPICLIENT_LIB)
unset (VAPICLIENT_LIB)
unset (ACL_FILE)
unset (NAT_FILE)
@@ -20,13 +21,20 @@ unset (IGMP_FILE)
unset (VOM_SOURCES)
unset (VOM_HEADERS)
+find_library(VPPAPICLIENT_LIB NAMES vppapiclient REQUIRED)
+find_path(VPPAPICLIENT_INCLUDE_DIR NAMES vpp-api/client/vppapiclient.h)
find_library(VAPICLIENT_LIB NAMES vapiclient REQUIRED)
find_path(VAPICLIENT_INCLUDE_DIR NAMES vapi/vapi.hpp)
+
+if(NOT VPPAPICLIENT_INCLUDE_DIR OR NOT VPPAPICLIENT_LIB)
+ message(FATAL_ERROR "Cannot find vppapiclient library and/or headers")
+endif()
if(NOT VAPICLIENT_INCLUDE_DIR OR NOT VAPICLIENT_LIB)
message(FATAL_ERROR "Cannot find vapiclient library and/or headers")
endif()
+include_directories(${VPPAPICLIENT_INCLUDE_DIR})
include_directories(${VAPICLIENT_INCLUDE_DIR})
include_directories(${CMAKE_SOURCE_DIR})
@@ -160,6 +168,8 @@ list(APPEND VOM_SOURCES
route_cmds.cpp
route_domain.cpp
route_domain_cmds.cpp
+ stat_client.cpp
+ stat_reader.cpp
sub_interface_cmds.cpp
sub_interface.cpp
tap_interface.cpp
@@ -257,6 +267,8 @@ list(APPEND VOM_HEADERS
rpc_cmd.hpp
singular_db.hpp
singular_db_funcs.hpp
+ stat_client.hpp
+ stat_reader.hpp
sub_interface.hpp
tap_interface.hpp
types.hpp
@@ -271,8 +283,20 @@ add_vpp_library(vom
INSTALL_HEADERS ${VOM_HEADERS}
- LINK_LIBRARIES ${VAPICLIENT_LIB} Threads::Threads boost_thread
- ${BOOST_SYSTEM_LIB} ${BOOST_FILESYSTEM_LIB} ${BOOST_ASIO_LIB} m rt
+ LINK_LIBRARIES ${VPPAPICLIENT_LIB} ${VAPICLIENT_LIB} Threads::Threads
+ ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} m rt
COMPONENT libvom
)
+
+if (Boost_FOUND)
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ add_definitions(-stdlib=libstdc++)
+ endif()
+ add_executable(vom_stats_test test_stats.cpp)
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ target_link_libraries(vom_stats_test vom stdc++)
+ else()
+ target_link_libraries(vom_stats_test vom)
+ endif()
+endif()
diff --git a/extras/vom/vom/hw.cpp b/extras/vom/vom/hw.cpp
index 0952b60f9d9..54f0aa2c02f 100644
--- a/extras/vom/vom/hw.cpp
+++ b/extras/vom/vom/hw.cpp
@@ -16,6 +16,7 @@
#include "vom/hw.hpp"
#include "vom/hw_cmds.hpp"
#include "vom/logger.hpp"
+#include "vom/stat_reader.hpp"
namespace VOM {
HW::cmd_q::cmd_q()
@@ -170,6 +171,11 @@ HW::cmd_q::write()
* The single Command Queue
*/
HW::cmd_q* HW::m_cmdQ;
+
+/*
+ * single stat reader
+ */
+stat_reader* HW::m_statReader;
HW::item<bool> HW::m_poll_state;
/**
@@ -179,6 +185,17 @@ void
HW::init(HW::cmd_q* f)
{
m_cmdQ = f;
+ m_statReader = new stat_reader();
+}
+
+/**
+ * Initialse the connection to VPP
+ */
+void
+HW::init(HW::cmd_q* f, stat_reader* s)
+{
+ m_cmdQ = f;
+ m_statReader = s;
}
/**
@@ -188,6 +205,7 @@ void
HW::init()
{
m_cmdQ = new cmd_q();
+ m_statReader = new stat_reader();
}
void
@@ -211,12 +229,13 @@ HW::enqueue(std::queue<cmd*>& cmds)
bool
HW::connect()
{
- return m_cmdQ->connect();
+ return (m_cmdQ->connect() && m_statReader->connect());
}
void
HW::disconnect()
{
+ m_statReader->disconnect();
m_cmdQ->disconnect();
}
@@ -249,6 +268,12 @@ HW::poll()
return (m_poll_state);
}
+void
+HW::read_stats()
+{
+ m_statReader->read();
+}
+
template <>
std::string
HW::item<bool>::to_string() const
diff --git a/extras/vom/vom/hw.hpp b/extras/vom/vom/hw.hpp
index 9ba47505619..d10a93aa59b 100644
--- a/extras/vom/vom/hw.hpp
+++ b/extras/vom/vom/hw.hpp
@@ -29,6 +29,7 @@
namespace VOM {
+class stat_reader;
class cmd;
class HW
{
@@ -287,6 +288,12 @@ public:
static void init(cmd_q* f);
/**
+ * Initialise the HW connection to VPP - the UT version passing
+ * a mock Q.
+ */
+ static void init(cmd_q* f, stat_reader* s);
+
+ /**
* Initialise the HW
*/
static void init();
@@ -326,6 +333,11 @@ public:
*/
static bool poll();
+ /**
+ * read stats from stat segment
+ */
+ static void read_stats();
+
private:
/**
* The command Q toward HW
@@ -333,6 +345,11 @@ private:
static cmd_q* m_cmdQ;
/**
+ * The stat reader toward HW
+ */
+ static stat_reader* m_statReader;
+
+ /**
* HW::item representing the connection state as determined by polling
*/
static HW::item<bool> m_poll_state;
diff --git a/extras/vom/vom/interface.cpp b/extras/vom/vom/interface.cpp
index c1894c2fbdf..bbbc187747c 100644
--- a/extras/vom/vom/interface.cpp
+++ b/extras/vom/vom/interface.cpp
@@ -23,6 +23,7 @@
#include "vom/logger.hpp"
#include "vom/prefix.hpp"
#include "vom/singular_db_funcs.hpp"
+#include "vom/stat_reader.hpp"
#include "vom/tap_interface_cmds.hpp"
namespace VOM {
@@ -175,13 +176,8 @@ interface::sweep()
new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
}
- if (m_stats) {
- if (stats_type_t::DETAILED == m_stats_type) {
- HW::enqueue(new interface_cmds::collect_detail_stats_change_cmd(
- m_stats_type, handle_i(), false));
- }
- HW::enqueue(new interface_cmds::stats_disable_cmd(m_hdl.data()));
- m_stats.reset();
+ if (m_listener) {
+ disable_stats();
}
// If the interface is up, bring it down
@@ -209,16 +205,8 @@ interface::replay()
HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl));
}
- if (m_stats) {
- if (stats_type_t::DETAILED == m_stats_type) {
- m_stats_type.set(rc_t::NOOP);
- HW::enqueue(new interface_cmds::collect_detail_stats_change_cmd(
- m_stats_type, handle_i(), true));
- }
- stat_listener& listener = m_stats->listener();
- listener.status().set(rc_t::NOOP);
- m_stats.reset(new interface_cmds::stats_enable_cmd(listener, handle_i()));
- HW::enqueue(m_stats);
+ if (m_listener) {
+ enable_stats(m_listener, m_stats_type.data());
}
if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) {
@@ -424,26 +412,101 @@ interface::set(const std::string& tag)
}
void
-interface::enable_stats_i(interface::stat_listener& el, const stats_type_t& st)
+interface::set(counter_t count, const std::string& stat_type)
+{
+ if ("rx" == stat_type)
+ m_stats.m_rx = count;
+ else if ("tx" == stat_type)
+ m_stats.m_tx = count;
+ else if ("rx-unicast" == stat_type)
+ m_stats.m_rx_unicast = count;
+ else if ("tx-unicast" == stat_type)
+ m_stats.m_tx_unicast = count;
+ else if ("rx-multicast" == stat_type)
+ m_stats.m_rx_multicast = count;
+ else if ("tx-multicast" == stat_type)
+ m_stats.m_tx_multicast = count;
+ else if ("rx-broadcast" == stat_type)
+ m_stats.m_rx_broadcast = count;
+ else if ("tx-broadcast" == stat_type)
+ m_stats.m_rx_broadcast = count;
+}
+
+const interface::stats_t&
+interface::get_stats(void) const
+{
+ return m_stats;
+}
+
+void
+interface::publish_stats()
{
- if (!m_stats) {
+ m_listener->handle_interface_stat(*this);
+}
+
+std::ostream&
+operator<<(std::ostream& os, const interface::stats_t& stats)
+{
+ os << "["
+ << "rx [packets " << stats.m_rx.packets << ", bytes " << stats.m_rx.bytes
+ << "]"
+ << " rx-unicast [packets " << stats.m_rx_unicast.packets << ", bytes "
+ << stats.m_rx_unicast.bytes << "]"
+ << " rx-multicast [packets " << stats.m_rx_multicast.packets << ", bytes "
+ << stats.m_rx_multicast.bytes << "]"
+ << " rx-broadcast [packets " << stats.m_rx_broadcast.packets << ", bytes "
+ << stats.m_rx_broadcast.bytes << "]"
+ << " tx [packets " << stats.m_tx.packets << ", bytes " << stats.m_tx.bytes
+ << "]"
+ << " tx-unicast [packets " << stats.m_tx_unicast.packets << ", bytes "
+ << stats.m_tx_unicast.bytes << "]"
+ << " tx-multicast [packets " << stats.m_tx_multicast.packets << ", bytes "
+ << stats.m_tx_multicast.bytes << "]"
+ << " tx-broadcast [packets " << stats.m_tx_broadcast.packets << ", bytes "
+ << stats.m_tx_broadcast.bytes << "]]" << std::endl;
+
+ return (os);
+}
+
+void
+interface::enable_stats_i(interface::stat_listener* el, const stats_type_t& st)
+{
+ if (el != NULL) {
if (stats_type_t::DETAILED == st) {
- m_stats_type = st;
+ m_stats_type.set(rc_t::NOOP);
HW::enqueue(new interface_cmds::collect_detail_stats_change_cmd(
m_stats_type, handle_i(), true));
}
- m_stats.reset(new interface_cmds::stats_enable_cmd(el, handle_i()));
- HW::enqueue(m_stats);
- HW::write();
+ stat_reader::registers(*this);
+ m_listener = el;
}
}
void
-interface::enable_stats(interface::stat_listener& el, const stats_type_t& st)
+interface::enable_stats(interface::stat_listener* el, const stats_type_t& st)
{
singular()->enable_stats_i(el, st);
}
+void
+interface::disable_stats_i()
+{
+ if (m_listener != NULL) {
+ if (stats_type_t::DETAILED == m_stats_type) {
+ HW::enqueue(new interface_cmds::collect_detail_stats_change_cmd(
+ m_stats_type, handle_i(), false));
+ }
+ stat_reader::unregisters(*this);
+ m_listener = NULL;
+ }
+}
+
+void
+interface::disable_stats()
+{
+ singular()->disable_stats_i();
+}
+
std::shared_ptr<interface>
interface::singular_i() const
{
diff --git a/extras/vom/vom/interface.hpp b/extras/vom/vom/interface.hpp
index 42dfa67e03d..100c3caf4bc 100644
--- a/extras/vom/vom/interface.hpp
+++ b/extras/vom/vom/interface.hpp
@@ -25,15 +25,16 @@
#include "vom/route_domain.hpp"
#include "vom/rpc_cmd.hpp"
#include "vom/singular_db.hpp"
+#include "vom/stat_client.hpp"
namespace VOM {
/**
* Forward declaration of the stats and events command
*/
namespace interface_cmds {
-class stats_enable_cmd;
class events_cmd;
};
+class stat_reader;
/**
* A representation of an interface in VPP
@@ -185,6 +186,21 @@ public:
};
/**
+ * stats_t:
+ */
+ struct stats_t
+ {
+ counter_t m_rx;
+ counter_t m_tx;
+ counter_t m_rx_unicast;
+ counter_t m_tx_unicast;
+ counter_t m_rx_multicast;
+ counter_t m_tx_multicast;
+ counter_t m_rx_broadcast;
+ counter_t m_tx_broadcast;
+ };
+
+ /**
* Construct a new object matching the desried state
*/
interface(const std::string& name,
@@ -269,6 +285,11 @@ public:
void set(const std::string& tag);
/**
+ * Get the interface stats
+ */
+ const stats_t& get_stats(void) const;
+
+ /**
* Comparison operator - only used for UT
*/
virtual bool operator==(const interface& i) const;
@@ -441,12 +462,13 @@ public:
*/
stat_listener();
+ virtual ~stat_listener() = default;
+
/**
* Virtual function called on the listener when the command has data
* ready to process
*/
- virtual void handle_interface_stat(
- interface_cmds::stats_enable_cmd* cmd) = 0;
+ virtual void handle_interface_stat(const interface&) = 0;
/**
* Return the HW::item representing the status
@@ -478,10 +500,15 @@ public:
/**
* Enable stats for this interface
*/
- void enable_stats(stat_listener& el,
+ void enable_stats(stat_listener* el,
const stats_type_t& st = stats_type_t::NORMAL);
/**
+ * Disable stats for this interface
+ */
+ void disable_stats();
+
+ /**
* Enable the reception of events of all interfaces
*/
static void enable_events(interface::event_listener& el);
@@ -499,7 +526,6 @@ protected:
void set(const handle_t& handle);
friend class interface_factory;
friend class pipe;
-
/**
* The SW interface handle VPP has asigned to the interface
*/
@@ -581,9 +607,29 @@ private:
static event_handler m_evh;
/**
+ * friend with stat_reader
+ */
+ friend stat_reader;
+
+ /**
+ * publish stats
+ */
+ void publish_stats();
+
+ /**
+ * Set the interface stat
+ */
+ void set(counter_t count, const std::string& stat_type);
+
+ /**
* enable the interface stats in the singular instance
*/
- void enable_stats_i(stat_listener& el, const stats_type_t& st);
+ void enable_stats_i(stat_listener* el, const stats_type_t& st);
+
+ /**
+ * disable the interface stats in the singular instance
+ */
+ void disable_stats_i();
/**
* Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
@@ -623,11 +669,6 @@ private:
std::shared_ptr<route_domain> m_rd;
/**
- * shared pointer to the stats object for this interface.
- */
- std::shared_ptr<interface_cmds::stats_enable_cmd> m_stats;
-
- /**
* The state of the interface
*/
HW::item<admin_state_t> m_state;
@@ -648,6 +689,16 @@ private:
HW::item<stats_type_t> m_stats_type;
/**
+ * Interface stats
+ */
+ stats_t m_stats;
+
+ /**
+ * reference to stat listener
+ */
+ stat_listener* m_listener;
+
+ /**
* Operational state of the interface
*/
oper_state_t m_oper;
@@ -683,6 +734,11 @@ private:
static std::shared_ptr<interface_cmds::events_cmd> m_events_cmd;
};
+
+/**
+ * stream insertion operator for interface stats
+ */
+std::ostream& operator<<(std::ostream& os, const interface::stats_t& stats);
};
/*
* fd.io coding-style-patch-verification: ON
diff --git a/extras/vom/vom/interface_cmds.cpp b/extras/vom/vom/interface_cmds.cpp
index c4fd6613a0e..3a7fb50f64b 100644
--- a/extras/vom/vom/interface_cmds.cpp
+++ b/extras/vom/vom/interface_cmds.cpp
@@ -20,7 +20,6 @@ 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_VHOST_USER_API_JSON;
-DEFINE_VAPI_MSG_IDS_STATS_API_JSON;
namespace VOM {
namespace interface_cmds {
@@ -473,137 +472,6 @@ events_cmd::to_string() const
return ("itf-events");
}
-/**
- * Interface statistics
- */
-stats_enable_cmd::stats_enable_cmd(interface::stat_listener& el,
- const handle_t& handle)
- : event_cmd(el.status())
- , m_listener(el)
- , m_swifindex(handle)
-{
-}
-
-bool
-stats_enable_cmd::operator==(const stats_enable_cmd& other) const
-{
- return (true);
-}
-
-rc_t
-stats_enable_cmd::issue(connection& con)
-{
- /*
- * First set the call back to handle the interface stats
- */
- m_reg.reset(new reg_t(con.ctx(), std::ref(*(static_cast<event_cmd*>(this)))));
-
- /*
- * then send the request to enable them
- */
- msg_t req(con.ctx(), 1, std::ref(*(static_cast<rpc_cmd*>(this))));
-
- auto& payload = req.get_request().get_payload();
- payload.enable_disable = 1;
- payload.pid = getpid();
- payload.num = 1;
-
- payload.sw_ifs[0] = m_swifindex.value();
-
- VAPI_CALL(req.execute());
-
- wait();
-
- return (rc_t::OK);
-}
-
-void
-stats_enable_cmd::retire(connection& con)
-{
- /*
- * disable interface stats.
- */
- msg_t req(con.ctx(), 1, std::ref(*(static_cast<rpc_cmd*>(this))));
-
- auto& payload = req.get_request().get_payload();
- payload.enable_disable = 0;
- payload.pid = getpid();
- payload.num = 1;
- payload.sw_ifs[0] = m_swifindex.value();
-
- VAPI_CALL(req.execute());
-
- wait();
-}
-
-interface::stat_listener&
-stats_enable_cmd::listener() const
-{
- return m_listener;
-}
-
-void
-stats_enable_cmd::set(const rc_t& rc)
-{
- m_listener.status().set(rc);
-}
-
-void
-stats_enable_cmd::notify()
-{
- m_listener.handle_interface_stat(this);
-}
-
-std::string
-stats_enable_cmd::to_string() const
-{
- std::ostringstream s;
- s << "itf-stats-enable itf:" << m_swifindex.to_string();
- return (s.str());
-}
-
-stats_disable_cmd::stats_disable_cmd(const handle_t& handle)
- : rpc_cmd(m_res)
- , m_swifindex(handle)
-{
-}
-
-bool
-stats_disable_cmd::operator==(const stats_disable_cmd& other) const
-{
- return (true);
-}
-
-rc_t
-stats_disable_cmd::issue(connection& con)
-{
- /*
- * then send the request to enable them
- */
- msg_t req(con.ctx(), 1, std::ref(*this));
-
- auto& payload = req.get_request().get_payload();
- payload.enable_disable = 0;
- payload.pid = getpid();
- payload.num = 1;
-
- payload.sw_ifs[0] = m_swifindex.value();
-
- VAPI_CALL(req.execute());
-
- wait();
-
- return (rc_t::OK);
-}
-
-std::string
-stats_disable_cmd::to_string() const
-{
- std::ostringstream s;
- s << "itf-stats-disable itf:" << m_swifindex.to_string();
- return (s.str());
-}
-
dump_cmd::dump_cmd()
{
}
diff --git a/extras/vom/vom/interface_cmds.hpp b/extras/vom/vom/interface_cmds.hpp
index b646e4ec9b8..13a47e6a6d7 100644
--- a/extras/vom/vom/interface_cmds.hpp
+++ b/extras/vom/vom/interface_cmds.hpp
@@ -25,7 +25,6 @@
#include <vapi/af_packet.api.vapi.hpp>
#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>
@@ -407,101 +406,6 @@ private:
};
/**
- * A command class represents our desire to recieve interface stats
- */
-class stats_enable_cmd
- : public event_cmd<vapi::Want_per_interface_combined_stats,
- vapi::Vnet_per_interface_combined_counters>
-{
-public:
- /**
- * Constructor taking the listner to notify
- */
- stats_enable_cmd(interface::stat_listener& el, const handle_t& handle);
-
- /**
- * Issue the command to VPP/HW
- */
- rc_t issue(connection& con);
-
- /**
- * Retires the command - unsubscribe from the stats.
- */
- void retire(connection& con);
-
- /**
- * convert to string format for debug purposes
- */
- std::string to_string() const;
-
- /**
- * (re)set status
- */
- void set(const rc_t& rc);
-
- /**
- * get listener
- */
- interface::stat_listener& listener() const;
-
- /**
- * Comparison operator - only used for UT
- */
- bool operator==(const stats_enable_cmd& i) const;
-
- /**
- * Called when it's time to poke the listeners
- */
- void notify();
-
-private:
- /**
- * The listeners to notify when data/stats arrive
- */
- interface::stat_listener& m_listener;
-
- /**
- * The interface on which we are enabling states
- */
- const handle_t& m_swifindex;
-};
-
-/**
- * A command class represents our desire to recieve interface stats
- */
-class stats_disable_cmd
- : public rpc_cmd<HW::item<bool>, vapi::Want_per_interface_combined_stats>
-{
-public:
- /**
- * Constructor taking the listner to notify
- */
- stats_disable_cmd(const handle_t& handle);
-
- /**
- * 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 stats_disable_cmd& i) const;
-
-private:
- HW::item<bool> m_res;
- /**
- * The interface on which we are disabling states
- */
- handle_t m_swifindex;
-};
-
-/**
* A cmd class that Dumps all the Vpp interfaces
*/
class dump_cmd : public VOM::dump_cmd<vapi::Sw_interface_dump>
diff --git a/extras/vom/vom/stat_client.cpp b/extras/vom/vom/stat_client.cpp
new file mode 100644
index 00000000000..b348c6c24eb
--- /dev/null
+++ b/extras/vom/vom/stat_client.cpp
@@ -0,0 +1,233 @@
+/*
+ * 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/stat_client.hpp"
+
+namespace VOM {
+
+stat_client::stat_data_t::stat_data_t()
+ : m_name("")
+ , m_type(STAT_DIR_TYPE_ILLEGAL)
+{
+}
+
+stat_client::stat_data_t::stat_data_t(stat_segment_data_t* stat_seg_data)
+ : m_name(stat_seg_data->name)
+ , m_type(stat_seg_data->type)
+{
+ switch (m_type) {
+ case STAT_DIR_TYPE_SCALAR_INDEX:
+ m_scalar_value = stat_seg_data->scalar_value;
+ break;
+ case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
+ m_simple_counter_vec = stat_seg_data->simple_counter_vec;
+ break;
+ case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
+ m_combined_counter_vec =
+ reinterpret_cast<counter_t**>(stat_seg_data->combined_counter_vec);
+ break;
+ case STAT_DIR_TYPE_ERROR_INDEX:
+ m_error_Value = stat_seg_data->error_value;
+ break;
+ case STAT_DIR_TYPE_ILLEGAL:
+ break;
+ }
+}
+
+const std::string&
+stat_client::stat_data_t::name() const
+{
+ return m_name;
+}
+
+const stat_directory_type_t&
+stat_client::stat_data_t::type() const
+{
+ return m_type;
+}
+
+double
+stat_client::stat_data_t::get_stat_segment_scalar_data()
+{
+ return m_scalar_value;
+}
+uint64_t
+stat_client::stat_data_t::get_stat_segment_error_data()
+{
+ return m_error_Value;
+}
+uint64_t**
+stat_client::stat_data_t::get_stat_segment_simple_counter_data()
+{
+ return m_simple_counter_vec;
+}
+counter_t**
+stat_client::stat_data_t::get_stat_segment_combined_counter_data()
+{
+ return m_combined_counter_vec;
+}
+
+stat_client::stat_client(std::string& socket_name)
+ : m_socket_name(socket_name)
+ , m_patterns()
+ , m_stat_connect(0)
+{
+ m_patterns.push_back("/if");
+}
+
+stat_client::stat_client(std::vector<std::string>& pattern)
+ : m_socket_name("/run/vpp/stats.sock")
+ , m_patterns(pattern)
+ , m_stat_connect(0)
+{
+}
+
+stat_client::stat_client(std::string socket_name,
+ std::vector<std::string> patterns)
+ : m_socket_name(socket_name)
+ , m_patterns(patterns)
+ , m_stat_connect(0)
+{
+}
+
+stat_client::stat_client()
+ : m_socket_name("/run/vpp/stats.sock")
+ , m_patterns()
+ , m_stat_connect(0)
+{
+ m_patterns.push_back("/if");
+}
+
+stat_client::~stat_client()
+{
+ stat_segment_vec_free(m_counter_vec);
+ data_free();
+ if (m_stat_connect)
+ stat_segment_disconnect();
+}
+
+stat_client::stat_client(const stat_client& o)
+ : m_socket_name(o.m_socket_name)
+ , m_patterns(o.m_patterns)
+{
+}
+
+int
+stat_client::connect()
+{
+ if (stat_segment_connect(m_socket_name.c_str()) == 0)
+ m_stat_connect = 1;
+ return m_stat_connect;
+}
+
+void
+stat_client::disconnect()
+{
+ if (m_stat_connect)
+ stat_segment_disconnect();
+}
+
+int
+stat_client::vec_len(void* vec)
+{
+ return stat_segment_vec_len(vec);
+}
+
+void
+stat_client::vec_free(void* vec)
+{
+ stat_segment_vec_free(vec);
+}
+
+void
+stat_client::ls()
+{
+ uint8_t** string_vec = { 0 };
+ for (auto& pattern : m_patterns) {
+ string_vec = stat_segment_string_vector(string_vec, pattern.c_str());
+ }
+ m_counter_vec = stat_segment_ls(string_vec);
+ stat_segment_vec_free(string_vec);
+}
+
+const stat_client::stat_data_vec_t&
+stat_client::dump()
+{
+ stat_segment_data_t* ssd;
+ stat_segment_data_free(m_stat_seg_data);
+ if (m_stat_data.size()) {
+ m_stat_data.clear();
+ }
+ ssd = stat_segment_dump(m_counter_vec);
+ if (!ssd) {
+ ls();
+ return m_stat_data;
+ }
+ m_stat_seg_data = ssd;
+ for (int i = 0; i < stat_segment_vec_len(ssd); i++) {
+ stat_data_t sd(&ssd[i]);
+ m_stat_data.push_back(sd);
+ }
+ return m_stat_data;
+}
+
+const stat_client::stat_data_vec_t&
+stat_client::dump_entry(uint32_t index)
+{
+ stat_segment_data_t* ssd;
+ stat_segment_data_free(m_stat_seg_data);
+ if (m_stat_data.size()) {
+ m_stat_data.clear();
+ }
+ ssd = stat_segment_dump_entry(index);
+ if (!ssd) {
+ ls();
+ return m_stat_data;
+ }
+ m_stat_seg_data = ssd;
+ for (int i = 0; i < stat_segment_vec_len(ssd); i++) {
+ stat_data_t sd(&ssd[i]);
+ m_stat_data.push_back(sd);
+ }
+ return m_stat_data;
+}
+
+void
+stat_client::data_free()
+{
+ stat_segment_data_free(m_stat_seg_data);
+}
+
+double
+stat_client::heartbeat()
+{
+ return stat_segment_heartbeat();
+}
+
+std::string
+stat_client::index_to_name(uint32_t index)
+{
+ return stat_segment_index_to_name(index);
+}
+
+} // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/stat_client.hpp b/extras/vom/vom/stat_client.hpp
new file mode 100644
index 00000000000..4da968a8204
--- /dev/null
+++ b/extras/vom/vom/stat_client.hpp
@@ -0,0 +1,221 @@
+/*
+ * 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_STAT_CLIENT_H__
+#define __VOM_STAT_CLIENT_H__
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+extern "C" {
+#include <vpp-api/client/stat_client.h>
+}
+
+namespace VOM {
+
+typedef struct
+{
+ uint64_t packets;
+ uint64_t bytes;
+} counter_t;
+
+typedef uint64_t stat_counter_t;
+/**
+ * A representation of a stat client in VPP
+ */
+class stat_client
+{
+public:
+ /**
+ * stat data representation
+ */
+ struct stat_data_t
+ {
+ /**
+ * stat data constructor
+ */
+ stat_data_t();
+
+ /**
+ * stat data custom constructor
+ */
+ stat_data_t(stat_segment_data_t* stat_seg_data);
+
+ /**
+ * get name of stat
+ */
+ const std::string& name() const;
+
+ /**
+ * get type of stat
+ */
+ const stat_directory_type_t& type() const;
+
+ /**
+ * Get pointer to actual data
+ */
+ double get_stat_segment_scalar_data();
+ uint64_t get_stat_segment_error_data();
+ uint64_t** get_stat_segment_simple_counter_data();
+ counter_t** get_stat_segment_combined_counter_data();
+
+ private:
+ /**
+ * name of stat data
+ */
+ const std::string m_name;
+
+ /**
+ * type of stat data
+ */
+ const stat_directory_type_t m_type;
+
+ /**
+ * union of pointers to actual stat data
+ */
+ union
+ {
+ double m_scalar_value;
+ uint64_t m_error_Value;
+ uint64_t** m_simple_counter_vec;
+ counter_t** m_combined_counter_vec;
+ };
+ };
+
+ /**
+ * vector of stat_data_t
+ */
+ typedef std::vector<stat_data_t> stat_data_vec_t;
+
+ /**
+ * Stat Client constructor with custom socket name
+ */
+ stat_client(std::string& socket_name);
+
+ /**
+ * Stat Client constructor with custom vector of patterns
+ */
+ stat_client(std::vector<std::string>& pattern);
+
+ /**
+ * Stat Client constructor with custom socket name and vector of patterns
+ */
+ stat_client(std::string socket_name, std::vector<std::string> patterns);
+
+ /**
+ * Stat Client constructor
+ */
+ stat_client();
+
+ /**
+ * Stat Client destructor
+ */
+ ~stat_client();
+
+ /**
+ * Stat Client copy constructor
+ */
+ stat_client(const stat_client& o);
+
+ /**
+ * Connect to stat segment
+ */
+ int connect();
+
+ /**
+ * Disconnect to stat segment
+ */
+ void disconnect();
+
+ /**
+ * Get vector length of VPP style vector
+ */
+ int vec_len(void* vec);
+
+ /**
+ * Free VPP style vector
+ */
+ void vec_free(void* vec);
+
+ /**
+ * ls on the stat directory using given pattern
+ */
+ void ls();
+
+ /**
+ * dump all the stats for given pattern
+ */
+ const stat_data_vec_t& dump();
+
+ /**
+ * dump stats for given index in stat directory
+ */
+ const stat_data_vec_t& dump_entry(uint32_t index);
+
+ /**
+ * Free stat segment data
+ */
+ void data_free();
+
+ double heartbeat();
+
+ /**
+ * get index to name of stat
+ */
+ std::string index_to_name(uint32_t index);
+
+private:
+ /**
+ * socket name
+ */
+ std::string m_socket_name;
+
+ /**
+ * vector of patterns for stats
+ */
+ std::vector<std::string> m_patterns;
+
+ /**
+ * connection bit
+ */
+ int m_stat_connect;
+
+ /**
+ * Pointer to VPP style vector of stat indexes
+ */
+ uint32_t* m_counter_vec;
+
+ /**
+ * Pointer to stat segment
+ */
+ stat_segment_data_t* m_stat_seg_data;
+
+ /**
+ * Vector of stat data
+ */
+ stat_data_vec_t m_stat_data;
+};
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/stat_reader.cpp b/extras/vom/vom/stat_reader.cpp
new file mode 100644
index 00000000000..4b054aba5af
--- /dev/null
+++ b/extras/vom/vom/stat_reader.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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/stat_reader.hpp"
+#include "vom/interface.hpp"
+
+namespace VOM {
+
+stat_reader::stat_indexes_t stat_reader::m_stat_itf_indexes;
+
+stat_reader::stat_reader()
+ : m_client()
+{
+}
+
+stat_reader::stat_reader(stat_client sc)
+ : m_client(sc)
+{
+}
+
+stat_reader::~stat_reader()
+{
+}
+
+int
+stat_reader::connect()
+{
+ return m_client.connect();
+}
+
+void
+stat_reader::disconnect()
+{
+ m_client.disconnect();
+}
+
+void
+stat_reader::registers(const interface& intf)
+{
+ m_stat_itf_indexes.insert(intf.handle().value());
+}
+
+void
+stat_reader::unregisters(const interface& intf)
+{
+ m_stat_itf_indexes.erase(intf.handle().value());
+}
+
+void
+stat_reader::read()
+{
+ stat_client::stat_data_vec_t sd = m_client.dump();
+ for (auto& sde : sd) {
+ std::string name;
+
+ if (sde.name().empty())
+ continue;
+
+ name = sde.name();
+
+ switch (sde.type()) {
+ case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
+ case STAT_DIR_TYPE_ERROR_INDEX:
+ case STAT_DIR_TYPE_SCALAR_INDEX:
+ break;
+
+ case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
+ if (name.find("/if") != std::string::npos)
+ name.erase(0, 4);
+ for (auto& i : m_stat_itf_indexes) {
+ counter_t count = {.packets = 0, .bytes = 0 };
+ for (int k = 0; k < m_client.vec_len(
+ sde.get_stat_segment_combined_counter_data());
+ k++) {
+ count.packets +=
+ sde.get_stat_segment_combined_counter_data()[k][i].packets;
+ count.bytes +=
+ sde.get_stat_segment_combined_counter_data()[k][i].bytes;
+ }
+ std::shared_ptr<interface> itf = interface::find(i);
+ if (itf)
+ itf->set(count, name);
+ }
+ break;
+
+ default:;
+ }
+ }
+
+ for (auto& i : m_stat_itf_indexes) {
+ std::shared_ptr<interface> itf = interface::find(i);
+ if (itf)
+ itf->publish_stats();
+ }
+}
+
+} // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/stat_reader.hpp b/extras/vom/vom/stat_reader.hpp
new file mode 100644
index 00000000000..f90b2561602
--- /dev/null
+++ b/extras/vom/vom/stat_reader.hpp
@@ -0,0 +1,103 @@
+/*
+ * 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_STAT_READER_H__
+#define __VOM_STAT_READER_H__
+
+#include "vom/stat_client.hpp"
+#include <set>
+
+namespace VOM {
+
+class interface;
+
+/**
+ * Stat reader: single interface to get stats
+ */
+class stat_reader
+{
+public:
+ /**
+ * Default Constructor
+ */
+ stat_reader();
+
+ /**
+ * Constructor
+ */
+ stat_reader(stat_client sc);
+
+ /**
+ * Destructor
+ */
+ ~stat_reader();
+
+ /**
+ * connection to stat object
+ */
+ virtual int connect();
+
+ /**
+ * disconnect to stat object
+ */
+ virtual void disconnect();
+
+ /**
+ * read stats for registered objects from stat_segment
+ * and set those stats to respective objects
+ */
+ virtual void read();
+
+private:
+ /**
+ * friend to interface class to call stat_register and
+ * stat_unregister methods
+ */
+ friend class interface;
+
+ /**
+ * Register objects to get stats for
+ */
+ static void registers(const interface& itf);
+
+ /**
+ * Unregister objects
+ */
+ static void unregisters(const interface& itf);
+
+ /**
+ * typedef of stat_indexes
+ */
+ typedef std::set<uint32_t> stat_indexes_t;
+
+ /**
+ * stat_client object
+ */
+ stat_client m_client;
+
+ /**
+ * static pointer to set of registered interfaces
+ */
+ static stat_indexes_t m_stat_itf_indexes;
+};
+};
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+#endif
diff --git a/extras/vom/vom/test_stats.cpp b/extras/vom/vom/test_stats.cpp
new file mode 100644
index 00000000000..6235dd44e3f
--- /dev/null
+++ b/extras/vom/vom/test_stats.cpp
@@ -0,0 +1,92 @@
+#include <vom/om.hpp>
+#include <vom/hw.hpp>
+#include <vom/types.hpp>
+#include <vom/prefix.hpp>
+#include <vom/tap_interface.hpp>
+
+class listener : public VOM::interface::stat_listener
+{
+public:
+ listener() {}
+ ~listener() {}
+ void handle_interface_stat(const VOM::interface& itf)
+ {
+ std::cout << itf.name() << " " << itf.get_stats();
+ }
+};
+
+/**
+ * Run VPP on another terminal before running vom_stats_test
+ */
+int main()
+{
+ uint8_t i = 5;
+ listener *listen = new listener();
+
+ VOM::HW::init(new VOM::HW::cmd_q());
+ VOM::OM::init();
+
+ while (VOM::HW::connect() != true)
+ ;
+
+ VOM::tap_interface itf("tap0", VOM::interface::admin_state_t::UP, VOM::route::prefix_t::ZERO);
+ VOM::OM::write("__TAP__", itf);
+
+ std::shared_ptr<VOM::tap_interface> intf = itf.singular();
+
+
+ VOM::tap_interface itf1("tap1", VOM::interface::admin_state_t::UP, VOM::route::prefix_t::ZERO);
+ VOM::OM::write("__TAP__", itf1);
+
+ std::shared_ptr<VOM::tap_interface> intf1 = itf1.singular();
+
+ VOM::tap_interface itf2("tap2", VOM::interface::admin_state_t::UP, VOM::route::prefix_t::ZERO);
+ VOM::OM::write("__TAP__", itf2);
+
+ std::shared_ptr<VOM::tap_interface> intf2 = itf2.singular();
+
+ if (VOM::handle_t::INVALID == intf->handle() || VOM::handle_t::INVALID == intf1->handle()
+ || VOM::handle_t::INVALID == intf2->handle())
+ {
+ std::cout << "Interface index is INVALID" << std::endl;
+ VOM::HW::disconnect();
+
+ return 0;
+ }
+ else
+ {
+ std::cout << "Interface #1 index is " << intf->handle().value() << std::endl;
+ std::cout << "Interface #2 index is " << intf1->handle().value() << std::endl;
+ std::cout << "Interface #3 index is " << intf2->handle().value() << std::endl;
+ }
+
+ intf->enable_stats(listen);
+ intf1->enable_stats(listen);
+ intf2->enable_stats(listen);
+
+ while (i--)
+ {
+ sleep(3);
+ std::cout << "stats # " << std::to_string(i) << std::endl;
+ VOM::HW::read_stats();
+
+ if (i == 2)
+ intf->disable_stats();
+
+ }
+
+ intf1->disable_stats();
+ intf2->disable_stats();
+
+ intf.reset();
+ intf1.reset();
+ intf2.reset();
+
+ VOM::OM::remove("__TAP__");
+
+ delete listen;
+ sleep(2);
+ VOM::HW::disconnect();
+
+ return 0;
+}
diff --git a/test/ext/vom_test.cpp b/test/ext/vom_test.cpp
index fa51c38215d..6aacea9803b 100644
--- a/test/ext/vom_test.cpp
+++ b/test/ext/vom_test.cpp
@@ -95,7 +95,7 @@ public:
class MockListener : public interface::event_listener,
public interface::stat_listener
{
- void handle_interface_stat(interface_cmds::stats_enable_cmd *cmd)
+ void handle_interface_stat(const interface& itf)
{
}
void handle_interface_event(std::vector<VOM::interface::event> events)