summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-03-08 18:22:50 +0200
committerIdo Barnea <ibarnea@cisco.com>2016-03-08 18:22:50 +0200
commitcc8c0e225bc495f67a379a757cc01a3fe778620d (patch)
treecfb9227a7396d86d768e7b93d9b7251bce880358
parent8ea0aeb8506b4da6b574700519ff4ca77b833c62 (diff)
Additions and fixes to per flow stats
-rw-r--r--src/flow_stat.cpp89
-rw-r--r--src/flow_stat.h31
-rw-r--r--src/main_dpdk.cpp37
3 files changed, 114 insertions, 43 deletions
diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp
index ef32284b..266acb3f 100644
--- a/src/flow_stat.cpp
+++ b/src/flow_stat.cpp
@@ -23,7 +23,7 @@
#include <iostream>
#include <assert.h>
#include <os_time.h>
-#include <internal_api/trex_platform_api.h>
+#include "internal_api/trex_platform_api.h"
#include "trex_stateless.h"
#include "trex_stream.h"
#include "flow_stat_parser.h"
@@ -61,9 +61,14 @@ CFlowStatUserIdInfo::CFlowStatUserIdInfo(uint8_t proto) {
m_proto = proto;
m_ref_count = 1;
m_trans_ref_count = 0;
+ m_was_sent = false;
+ for (int i = 0; i < TREX_MAX_PORTS; i++) {
+ m_rx_changed[i] = false;
+ m_tx_changed[i] = false;
+ }
}
-std::ostream& operator<<(std::ostream& os, const class CFlowStatUserIdInfo& cf) {
+std::ostream& operator<<(std::ostream& os, const CFlowStatUserIdInfo& cf) {
os << "hw_id:" << cf.m_hw_id << " proto:" << (uint16_t) cf.m_proto << " ref("
<< (uint16_t) cf.m_ref_count << "," << (uint16_t) cf.m_trans_ref_count << ")";
os << " rx count (";
@@ -138,7 +143,7 @@ std::ostream& operator<<(std::ostream& os, const CFlowStatUserIdMap& cf) {
}
uint16_t CFlowStatUserIdMap::get_hw_id(uint32_t user_id) {
- class CFlowStatUserIdInfo *cf = find_user_id(user_id);
+ CFlowStatUserIdInfo *cf = find_user_id(user_id);
if (cf == NULL) {
return FREE_HW_ID;
@@ -147,7 +152,7 @@ uint16_t CFlowStatUserIdMap::get_hw_id(uint32_t user_id) {
}
}
-class CFlowStatUserIdInfo *
+CFlowStatUserIdInfo *
CFlowStatUserIdMap::find_user_id(uint32_t user_id) {
flow_stat_user_id_map_it_t it = m_map.find(user_id);
@@ -158,17 +163,17 @@ CFlowStatUserIdMap::find_user_id(uint32_t user_id) {
}
}
-class CFlowStatUserIdInfo *
+CFlowStatUserIdInfo *
CFlowStatUserIdMap::add_user_id(uint32_t user_id, uint8_t proto) {
#ifdef __DEBUG_FUNC_ENTRY__
std::cout << __METHOD_NAME__ << " user id:" << user_id << " proto:" << (uint16_t)proto
<< std::endl;
#endif
- class CFlowStatUserIdInfo *new_id = new CFlowStatUserIdInfo(proto);
+ CFlowStatUserIdInfo *new_id = new CFlowStatUserIdInfo(proto);
if (new_id != NULL) {
std::pair<flow_stat_user_id_map_it_t, bool> ret;
- ret = m_map.insert(std::pair<uint32_t, class CFlowStatUserIdInfo *>(user_id, new_id));
+ ret = m_map.insert(std::pair<uint32_t, CFlowStatUserIdInfo *>(user_id, new_id));
if (ret.second == false) {
printf("%s Error: Trying to add user id %d which already exist\n", __func__, user_id);
delete new_id;
@@ -186,7 +191,7 @@ int CFlowStatUserIdMap::add_stream(uint32_t user_id, uint8_t proto) {
<< std::endl;
#endif
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -204,7 +209,7 @@ int CFlowStatUserIdMap::del_stream(uint32_t user_id) {
std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
#endif
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -225,7 +230,7 @@ int CFlowStatUserIdMap::start_stream(uint32_t user_id, uint16_t hw_id) {
std::cout << __METHOD_NAME__ << " user id:" << user_id << " hw_id:" << hw_id << std::endl;
#endif
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -235,7 +240,7 @@ int CFlowStatUserIdMap::start_stream(uint32_t user_id, uint16_t hw_id) {
}
if (c_user_id->is_hw_id()) {
- fprintf(stderr, "%s Error: Trying to associate hw id %d to user_id %d but it is already associate to %ld\n"
+ fprintf(stderr, "%s Error: Trying to associate hw id %d to user_id %d but it is already associate to %u\n"
, __func__, hw_id, user_id, c_user_id->get_hw_id());
return -1;
}
@@ -250,7 +255,7 @@ int CFlowStatUserIdMap::start_stream(uint32_t user_id) {
std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
#endif
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -271,7 +276,7 @@ int CFlowStatUserIdMap::stop_stream(uint32_t user_id) {
std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
#endif
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -284,7 +289,7 @@ int CFlowStatUserIdMap::stop_stream(uint32_t user_id) {
}
bool CFlowStatUserIdMap::is_started(uint32_t user_id) {
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -295,7 +300,7 @@ bool CFlowStatUserIdMap::is_started(uint32_t user_id) {
}
uint8_t CFlowStatUserIdMap::l4_proto(uint32_t user_id) {
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -310,7 +315,7 @@ uint16_t CFlowStatUserIdMap::unmap(uint32_t user_id) {
std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
#endif
- class CFlowStatUserIdInfo *c_user_id;
+ CFlowStatUserIdInfo *c_user_id;
c_user_id = find_user_id(user_id);
if (! c_user_id) {
@@ -583,15 +588,21 @@ int CFlowStatRuleMgr::stop_stream(const TrexStream * stream) {
return -1;
} else {
// update counters, and reset before unmapping
- class CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(hw_id));
+ CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(hw_id));
assert(p_user_id != NULL);
uint64_t rx_counter;
tx_per_flow_t tx_counter;
for (uint8_t port = 0; port < m_num_ports; port++) {
m_api->del_rx_flow_stat_rule(port, FLOW_STAT_RULE_TYPE_IPV4_ID, proto, hw_id);
m_api->get_flow_stats(port, &rx_counter, (void *)&tx_counter, hw_id, hw_id, true);
- p_user_id->set_rx_counter(port, rx_counter);
- p_user_id->set_tx_counter(port, tx_counter);
+ if (p_user_id->get_rx_counter(port) != rx_counter) {
+ p_user_id->set_rx_counter(port, rx_counter);
+ p_user_id->set_need_to_send_rx(port);
+ }
+ if (p_user_id->get_tx_counter(port) != tx_counter) {
+ p_user_id->set_tx_counter(port, tx_counter);
+ p_user_id->set_need_to_send_tx(port);
+ }
}
m_user_id_map.unmap(stream->m_rx_check.m_pg_id);
m_hw_id_map.unmap(hw_id);
@@ -611,37 +622,48 @@ int CFlowStatRuleMgr::get_active_pgids(flow_stat_active_t &result) {
}
// return false if no counters changed since last run. true otherwise
-bool CFlowStatRuleMgr::dump_json(std::string & json) {
+bool CFlowStatRuleMgr::dump_json(std::string & json, bool force_sync) {
uint64_t rx_stats[MAX_FLOW_STATS];
tx_per_flow_t tx_stats[MAX_FLOW_STATS];
Json::FastWriter writer;
Json::Value root;
- if (m_user_id_map.is_empty()) {
- return false;
- }
root["name"] = "flow_stats";
root["type"] = 0;
Json::Value &data_section = root["data"];
+ data_section["timestamp"] = Json::Value::UInt64(os_get_hr_tick_64());
+
+ if (m_user_id_map.is_empty()) {
+ if (force_sync) {
+ json = writer.write(root);
+ return true;
+ } else
+ return false;
+ }
// read hw counters, and update
- data_section["timestamp"] = Json::Value::UInt64(os_get_hr_tick_64());
for (uint8_t port = 0; port < m_num_ports; port++) {
m_api->get_flow_stats(port, rx_stats, (void *)tx_stats, 0, m_max_hw_id, false);
for (int i = 0; i <= m_max_hw_id; i++) {
if (rx_stats[i] != 0) {
- class CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i));
+ CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i));
if (likely(p_user_id != NULL)) {
- p_user_id->set_rx_counter(port, rx_stats[i]);
+ if (p_user_id->get_rx_counter(port) != rx_stats[i]) {
+ p_user_id->set_rx_counter(port, rx_stats[i]);
+ p_user_id->set_need_to_send_rx(port);
+ }
} else {
std::cerr << __METHOD_NAME__ << i << ":Could not count " << rx_stats[i] << " rx packets, because no mapping was found" << std::endl;
}
}
if (tx_stats[i].get_pkts() != 0) {
tx_per_flow_t tx_pkts = tx_stats[i];
- class CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i));
+ CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i));
if (likely(p_user_id != NULL)) {
- p_user_id->set_tx_counter(port, tx_pkts);
+ if (p_user_id->get_tx_counter(port) != tx_pkts) {
+ p_user_id->set_tx_counter(port, tx_pkts);
+ p_user_id->set_need_to_send_tx(port);
+ }
} else {
std::cerr << __METHOD_NAME__ << i << ":Could not count tx " << tx_pkts << " because no mapping was found" << std::endl;
}
@@ -656,13 +678,18 @@ bool CFlowStatRuleMgr::dump_json(std::string & json) {
uint32_t user_id = it->first;
std::string str_user_id = static_cast<std::ostringstream*>( &(std::ostringstream()
<< user_id) )->str();
+ if (! user_id_info->was_sent()) {
+ data_section[str_user_id]["first_time"] = true;
+ user_id_info->set_was_sent(true);
+ }
for (uint8_t port = 0; port < m_num_ports; port++) {
std::string str_port = static_cast<std::ostringstream*>( &(std::ostringstream() << int(port) ) )->str();
-
- if (user_id_info->get_rx_counter(port) != 0) {
+ if (user_id_info->need_to_send_rx(port) || force_sync) {
+ user_id_info->set_no_need_to_send_rx(port);
data_section[str_user_id]["rx_pkts"][str_port] = Json::Value::UInt64(user_id_info->get_rx_counter(port));
}
- if (user_id_info->get_tx_counter(port).get_pkts() != 0) {
+ if (user_id_info->need_to_send_tx(port) || force_sync) {
+ user_id_info->set_no_need_to_send_tx(port);
data_section[str_user_id]["tx_pkts"][str_port] = Json::Value::UInt64(user_id_info->get_tx_counter(port).get_pkts());
data_section[str_user_id]["tx_bytes"][str_port] = Json::Value::UInt64(user_id_info->get_tx_counter(port).get_bytes());
}
diff --git a/src/flow_stat.h b/src/flow_stat.h
index 6f7671fd..6966b116 100644
--- a/src/flow_stat.h
+++ b/src/flow_stat.h
@@ -83,7 +83,13 @@ class tx_per_flow_t_ {
return *this;
}
- friend std::ostream& operator<<(std::ostream& os, const class tx_per_flow_t_ &t) {
+ inline bool operator!= (const tx_per_flow_t_ &t_in) {
+ if ((m_bytes != t_in.m_bytes) || (m_pkts != t_in.m_pkts))
+ return true;
+ return false;
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const tx_per_flow_t_ &t) {
os << "p:" << t.m_pkts << " b:" << t.m_bytes;
return os;
}
@@ -107,7 +113,7 @@ class CFlowStatUserIdInfo {
void set_tx_counter(uint8_t port, tx_per_flow_t val) {m_tx_counter[port] = val;}
tx_per_flow_t get_tx_counter(uint8_t port) {return m_tx_counter[port] + m_tx_counter_base[port];}
void set_hw_id(uint16_t hw_id) {m_hw_id = hw_id;}
- uint64_t get_hw_id() {return m_hw_id;}
+ uint16_t get_hw_id() {return m_hw_id;}
void reset_hw_id();
bool is_hw_id() {return (m_hw_id != UINT16_MAX);}
uint64_t get_proto() {return m_proto;}
@@ -117,8 +123,18 @@ class CFlowStatUserIdInfo {
void add_started_stream() {m_trans_ref_count++;}
int stop_started_stream() {m_trans_ref_count--; return m_trans_ref_count;}
bool is_started() {return (m_trans_ref_count != 0);}
+ bool need_to_send_rx(uint8_t port) {return m_rx_changed[port];}
+ bool need_to_send_tx(uint8_t port) {return m_tx_changed[port];}
+ void set_no_need_to_send_rx(uint8_t port) {m_rx_changed[port] = false;}
+ void set_no_need_to_send_tx(uint8_t port) {m_tx_changed[port] = false;}
+ void set_need_to_send_rx(uint8_t port) {m_rx_changed[port] = true;}
+ void set_need_to_send_tx(uint8_t port) {m_tx_changed[port] = true;}
+ bool was_sent() {return m_was_sent == true;}
+ void set_was_sent(bool val) {m_was_sent = val;}
private:
+ bool m_rx_changed[TREX_MAX_PORTS]; // Which RX counters changed since we last published
+ bool m_tx_changed[TREX_MAX_PORTS]; // Which TX counters changed since we last published
uint64_t m_rx_counter[TREX_MAX_PORTS]; // How many packets received with this user id since stream start
// How many packets received with this user id, since stream creation, before stream start.
uint64_t m_rx_counter_base[TREX_MAX_PORTS];
@@ -129,6 +145,7 @@ class CFlowStatUserIdInfo {
uint8_t m_proto; // protocol (UDP, TCP, other), associated with this user id.
uint8_t m_ref_count; // How many streams with this ref count exists
uint8_t m_trans_ref_count; // How many streams with this ref count currently transmit
+ bool m_was_sent; // Did we send this info to clients once?
};
typedef std::map<uint32_t, class CFlowStatUserIdInfo *> flow_stat_user_id_map_t;
@@ -140,8 +157,8 @@ class CFlowStatUserIdMap {
friend std::ostream& operator<<(std::ostream& os, const CFlowStatUserIdMap& cf);
bool is_empty() {return (m_map.empty() == true);};
uint16_t get_hw_id(uint32_t user_id);
- class CFlowStatUserIdInfo * find_user_id(uint32_t user_id);
- class CFlowStatUserIdInfo * add_user_id(uint32_t user_id, uint8_t proto);
+ CFlowStatUserIdInfo * find_user_id(uint32_t user_id);
+ CFlowStatUserIdInfo * add_user_id(uint32_t user_id, uint8_t proto);
int add_stream(uint32_t user_id, uint8_t proto);
int del_stream(uint32_t user_id);
int start_stream(uint32_t user_id, uint16_t hw_id);
@@ -185,15 +202,15 @@ class CFlowStatRuleMgr {
int start_stream(TrexStream * stream, uint16_t &ret_hw_id);
int stop_stream(const TrexStream * stream);
int get_active_pgids(flow_stat_active_t &result);
- bool dump_json(std::string & json);
+ bool dump_json(std::string & json, bool force_sync);
private:
int compile_stream(const TrexStream * stream, Cxl710Parser &parser);
int add_hw_rule(uint16_t hw_id, uint8_t proto);
private:
- class CFlowStatHwIdMap m_hw_id_map; // map hw ids to user ids
- class CFlowStatUserIdMap m_user_id_map; // map user ids to hw ids
+ CFlowStatHwIdMap m_hw_id_map; // map hw ids to user ids
+ CFlowStatUserIdMap m_user_id_map; // map user ids to hw ids
uint8_t m_num_ports; // How many ports are being used
const TrexPlatformApi *m_api;
int m_max_hw_id; // max hw id we ever used
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 0d40215a..12670969 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -2640,7 +2640,7 @@ public:
bool sanity_check();
void update_stats(void);
tx_per_flow_t get_flow_tx_stats(uint8_t port, uint16_t hw_id);
- void clear_flow_tx_stats(uint8_t port, uint16_t index);
+ tx_per_flow_t clear_flow_tx_stats(uint8_t port, uint16_t index);
void get_stats(CGlobalStats & stats);
void dump_post_test_stats(FILE *fd);
void dump_config(FILE *fd);
@@ -3307,8 +3307,32 @@ tx_per_flow_t CGlobalTRex::get_flow_tx_stats(uint8_t port, uint16_t index) {
return m_stats.m_port[port].m_tx_per_flow[index] - m_stats.m_port[port].m_prev_tx_per_flow[index];
}
-void CGlobalTRex::clear_flow_tx_stats(uint8_t port, uint16_t index) {
+// read stats. Return read value, and clear.
+tx_per_flow_t CGlobalTRex::clear_flow_tx_stats(uint8_t port, uint16_t index) {
+ uint8_t port0;
+ CFlowGenListPerThread * lpt;
+ tx_per_flow_t ret;
+
+ m_stats.m_port[port].m_tx_per_flow[index].clear();
+
+ for (int i=0; i < get_cores_tx(); i++) {
+ lpt = m_fl.m_threads_info[i];
+ port0 = lpt->getDualPortId() * 2;
+ if (port == port0) {
+ m_stats.m_port[port0].m_tx_per_flow[index] +=
+ lpt->m_node_gen.m_v_if->m_stats[0].m_tx_per_flow[index];
+ } else if (port == port0 + 1) {
+ m_stats.m_port[port0 + 1].m_tx_per_flow[index] +=
+ lpt->m_node_gen.m_v_if->m_stats[1].m_tx_per_flow[index];
+ }
+ }
+
+ ret = m_stats.m_port[port].m_tx_per_flow[index] - m_stats.m_port[port].m_prev_tx_per_flow[index];
+
+ // Since we return diff from prev, following "clears" the stats.
m_stats.m_port[port].m_prev_tx_per_flow[index] = m_stats.m_port[port].m_tx_per_flow[index];
+
+ return ret;
}
void CGlobalTRex::get_stats(CGlobalStats & stats){
@@ -3568,7 +3592,7 @@ CGlobalTRex::publish_async_data(bool sync_now) {
m_zmq_publisher.publish_json(json);
if (get_is_stateless()) {
- if (m_trex_stateless->m_rx_flow_stat.dump_json(json))
+ if (m_trex_stateless->m_rx_flow_stat.dump_json(json, sync_now))
m_zmq_publisher.publish_json(json);
}
}
@@ -3930,10 +3954,9 @@ int CPhyEthIF::get_flow_stats(uint64_t *rx_stats, tx_per_flow_t *tx_stats, int m
rx_stats[i - min] = m_stats.m_rx_per_flow[i] + diff_stats[i];
}
if (tx_stats != NULL) {
- tx_stats[i - min] = g_trex.get_flow_tx_stats(m_port_id, i);
+ tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i);
}
m_stats.m_rx_per_flow[i] = 0;
- g_trex.clear_flow_tx_stats(m_port_id, i);
} else {
m_stats.m_rx_per_flow[i] += diff_stats[i];
if (rx_stats != NULL) {
@@ -4911,6 +4934,10 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if) {
// instead of adding this to rte_ethdev.h
extern "C" int rte_eth_fdir_stats_get(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_t len);
+// get rx stats on _if, between min and max
+// prev_stats should be the previous values read from the hardware.
+// Getting changed to be equal to current HW values.
+// stats return the diff between prev_stats and current hw values
int CTRexExtendedDriverBase40G::get_rx_stats(CPhyEthIF * _if, uint32_t *stats, uint32_t *prev_stats, int min, int max) {
uint32_t hw_stats[MAX_FLOW_STATS];
uint32_t port_id = _if->get_port_id();