vom: Add support for new stats

This patch deprecates old stats and adds support for
new stats.

This implements the PULL design where client will enable
stats on objects (i.e. interfaces, etc), register a call
back function which will run once stats will be ready for
enabled object and call HW::read_stats() periodically to
read stats for enabled objects from VPP.

Change-Id: I32525a417427be87408d01f8bc93a731602ff690
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
This commit is contained in:
Mohsin Kazmi
2018-11-21 19:00:46 +01:00
committed by Neale Ranns
parent eb6c799947
commit 51edc3ab01
14 changed files with 991 additions and 267 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -29,6 +29,7 @@
namespace VOM {
class stat_reader;
class cmd;
class HW
{
@ -286,6 +287,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
*/
@ -326,12 +333,22 @@ public:
*/
static bool poll();
/**
* read stats from stat segment
*/
static void read_stats();
private:
/**
* The command Q toward HW
*/
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
*/

View File

@ -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 (!m_stats) {
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()
{
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
{

View File

@ -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
@ -184,6 +185,21 @@ public:
oper_state_t(int v, const std::string& s);
};
/**
* 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
*/
@ -268,6 +284,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
*/
@ -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,9 +500,14 @@ 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
*/
@ -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
*/
@ -580,10 +606,30 @@ 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.
@ -622,11 +668,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
*/
@ -647,6 +688,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
*/
@ -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

View File

@ -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()
{
}

View File

@ -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>
@ -406,101 +405,6 @@ private:
interface::event_listener& m_listener;
};
/**
* 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
*/

View File

@ -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:
*/

View File

@ -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

View File

@ -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:
*/

View File

@ -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

View File

@ -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;
}

View File

@ -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)