diff options
author | Mohsin Kazmi <sykazmi@cisco.com> | 2018-11-21 19:00:46 +0100 |
---|---|---|
committer | Neale Ranns <nranns@cisco.com> | 2018-12-13 07:46:02 +0000 |
commit | 51edc3ab01e0af58d457da97bf6ca9cc3ebc6b8d (patch) | |
tree | 61030afdb69ed1952021dad99fa209a280d68a49 /extras/vom | |
parent | eb6c7999477cfbca77223be3ef7f11528da9f093 (diff) |
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>
Diffstat (limited to 'extras/vom')
-rw-r--r-- | extras/vom/CMakeLists.txt | 1 | ||||
-rw-r--r-- | extras/vom/vom/CMakeLists.txt | 28 | ||||
-rw-r--r-- | extras/vom/vom/hw.cpp | 27 | ||||
-rw-r--r-- | extras/vom/vom/hw.hpp | 17 | ||||
-rw-r--r-- | extras/vom/vom/interface.cpp | 111 | ||||
-rw-r--r-- | extras/vom/vom/interface.hpp | 78 | ||||
-rw-r--r-- | extras/vom/vom/interface_cmds.cpp | 132 | ||||
-rw-r--r-- | extras/vom/vom/interface_cmds.hpp | 96 | ||||
-rw-r--r-- | extras/vom/vom/stat_client.cpp | 233 | ||||
-rw-r--r-- | extras/vom/vom/stat_client.hpp | 221 | ||||
-rw-r--r-- | extras/vom/vom/stat_reader.cpp | 117 | ||||
-rw-r--r-- | extras/vom/vom/stat_reader.hpp | 103 | ||||
-rw-r--r-- | extras/vom/vom/test_stats.cpp | 92 |
13 files changed, 990 insertions, 266 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; +} |