diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/bp_sim.cpp | 4 | ||||
-rwxr-xr-x | src/bp_sim.h | 10 | ||||
-rw-r--r-- | src/debug.cpp | 2 | ||||
-rw-r--r-- | src/flow_stat.cpp | 84 | ||||
-rw-r--r-- | src/flow_stat.h | 10 | ||||
-rw-r--r-- | src/flow_stat_parser.cpp | 29 | ||||
-rw-r--r-- | src/flow_stat_parser.h | 6 | ||||
-rw-r--r-- | src/internal_api/trex_platform_api.h | 9 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 119 | ||||
-rw-r--r-- | src/pkt_gen.cpp | 4 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 2 | ||||
-rw-r--r-- | src/stateless/cp/trex_exception.h | 1 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.cpp | 3 | ||||
-rw-r--r-- | src/stateless/dp/trex_stateless_dp_core.cpp | 2 | ||||
-rw-r--r-- | src/stateless/dp/trex_stream_node.h | 8 | ||||
-rw-r--r-- | src/stateless/rx/trex_stateless_rx_port_mngr.cpp | 16 | ||||
-rw-r--r-- | src/stateless/rx/trex_stateless_rx_port_mngr.h | 10 | ||||
-rw-r--r-- | src/trex_defs.h | 6 |
18 files changed, 222 insertions, 103 deletions
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index 43cfed93..9dfb7c3d 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -1687,7 +1687,7 @@ void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m, uint8_t save_header= ipv6->getNextHdr(); ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE); ipv6->setHopLimit(TTL_RESERVE_DUPLICATE); - ipv6->setTrafficClass(ipv6->getTrafficClass()|TOS_TTL_RESERVE_DUPLICATE); + ipv6->setTrafficClass(ipv6->getTrafficClass() | TOS_GO_TO_CPU); ipv6->setPayloadLen( ipv6->getPayloadLen() + sizeof(CRx_check_header)); rxhdr->m_option_type = save_header; @@ -1697,7 +1697,7 @@ void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m, ipv4->setHeaderLength(current_opt_len+opt_len); ipv4->setTotalLength(ipv4->getTotalLength()+opt_len); ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE); - ipv4->setTOS(ipv4->getTOS()|TOS_TTL_RESERVE_DUPLICATE); + ipv4->setTOS(ipv4->getTOS() | TOS_GO_TO_CPU); rxhdr->m_option_type = RX_CHECK_V4_OPT_TYPE; rxhdr->m_option_len = RX_CHECK_V4_OPT_LEN; diff --git a/src/bp_sim.h b/src/bp_sim.h index fd4e6627..c524723a 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -78,7 +78,7 @@ class CGenNodePCAP; /* reserve both 0xFF and 0xFE , router will -1 FF */ #define TTL_RESERVE_DUPLICATE 0xff -#define TOS_TTL_RESERVE_DUPLICATE 0x1 +#define TOS_GO_TO_CPU 0x1 /* * Length of string needed to hold the largest port (16-bit) address */ @@ -2832,18 +2832,18 @@ public: void setTOSReserve(){ BP_ASSERT(l3.m_ipv4); if (is_ipv6()) { - l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass() | TOS_TTL_RESERVE_DUPLICATE ); + l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass() | TOS_GO_TO_CPU ); }else{ - l3.m_ipv4->setTOS(l3.m_ipv4->getTOS()| TOS_TTL_RESERVE_DUPLICATE ); + l3.m_ipv4->setTOS(l3.m_ipv4->getTOS()| TOS_GO_TO_CPU ); } } void clearTOSReserve(){ BP_ASSERT(l3.m_ipv4); if (is_ipv6()) { - l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass()& (~TOS_TTL_RESERVE_DUPLICATE) ); + l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass()& (~TOS_GO_TO_CPU) ); }else{ - l3.m_ipv4->setTOS(l3.m_ipv4->getTOS() & (~TOS_TTL_RESERVE_DUPLICATE) ); + l3.m_ipv4->setTOS(l3.m_ipv4->getTOS() & (~TOS_GO_TO_CPU) ); } } diff --git a/src/debug.cpp b/src/debug.cpp index ccef8499..d20721bf 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -399,7 +399,7 @@ int CTrexDebug::verify_hw_rules(bool recv_all) { memset(pkt_per_q, 0, sizeof(pkt_per_q)); // We don't know which interfaces connected where, so sum all queue 1 and all queue 0 for (int port = 0; port < m_max_ports; port++) { - for(int queue_id = 0; queue_id <= m_rx_q_num; queue_id++) { + for(int queue_id = 0; queue_id < m_rx_q_num; queue_id++) { lp = &m_ports[port]; uint16_t cnt = lp->rx_burst(queue_id, rx_pkts, 32); pkt_per_q[queue_id] += cnt; diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp index 58d08c44..8d33bf3c 100644 --- a/src/flow_stat.cpp +++ b/src/flow_stat.cpp @@ -63,7 +63,7 @@ stream_del: HW_ID_INIT static const uint16_t HW_ID_INIT = UINT16_MAX; static const uint16_t HW_ID_FREE = UINT16_MAX - 1; static const uint8_t PAYLOAD_RULE_PROTO = 255; -const uint32_t FLOW_STAT_PAYLOAD_IP_ID = IP_ID_RESERVE_BASE + MAX_FLOW_STATS; +const uint32_t FLOW_STAT_PAYLOAD_IP_ID = UINT16_MAX; inline std::string methodName(const std::string& prettyFunction) { @@ -457,8 +457,6 @@ CFlowStatRuleMgr::CFlowStatRuleMgr() { m_parser_ipid = NULL; m_parser_pl = NULL; m_rx_core = NULL; - m_hw_id_map.create(MAX_FLOW_STATS); - m_hw_id_map_payload.create(MAX_FLOW_STATS_PAYLOAD); memset(m_rx_cant_count_err, 0, sizeof(m_rx_cant_count_err)); memset(m_tx_cant_count_err, 0, sizeof(m_tx_cant_count_err)); m_num_ports = 0; // need to call create to init @@ -481,21 +479,24 @@ CFlowStatRuleMgr::~CFlowStatRuleMgr() { } void CFlowStatRuleMgr::create() { - uint16_t num_counters, cap; + uint16_t num_counters, cap, ip_id_base; TrexStateless *tstateless = get_stateless_obj(); assert(tstateless); m_api = tstateless->get_platform_api(); assert(m_api); - m_api->get_interface_stat_info(0, num_counters, cap); + m_api->get_interface_stat_info(0, num_counters, cap, ip_id_base); m_api->get_port_num(m_num_ports); // This initialize m_num_ports for (uint8_t port = 0; port < m_num_ports; port++) { assert(m_api->reset_hw_flow_stats(port) == 0); } + m_hw_id_map.create(num_counters); + m_hw_id_map_payload.create(MAX_FLOW_STATS_PAYLOAD); m_ring_to_rx = CMsgIns::Ins()->getCpRx()->getRingCpToDp(0); assert(m_ring_to_rx); m_rx_core = get_rx_sl_core_obj(); m_cap = cap; + m_ip_id_reserve_base = ip_id_base; if ((CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) || (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS)) { @@ -662,6 +663,11 @@ int CFlowStatRuleMgr::del_stream(TrexStream * stream) { return 0; } m_user_id_map.del_stream(stream->m_rx_check.m_pg_id); // Throws exception in case of error + if (m_user_id_map.is_empty()) { + m_max_hw_id = 0; + m_max_hw_id_payload = 0; + } + stream->m_rx_check.m_hw_id = HW_ID_INIT; return 0; @@ -695,16 +701,13 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) { return 0; } - uint32_t ip_id; + uint32_t ip_id; // 32 bit, since this also supports IPv6 if (m_parser_ipid->get_ip_id(ip_id) < 0) { return 0; // if we could not find the ip id, no need to fix } // verify no reserved IP_ID used, and change if needed - if (ip_id >= IP_ID_RESERVE_BASE) { - if (m_parser_ipid->set_ip_id(ip_id & 0xefff) < 0) { - throw TrexFStatEx("Stream IP ID in reserved range. Failed changing it" - , TrexException::T_FLOW_STAT_FAILED_CHANGE_IP_ID); - } + if (ip_id >= m_ip_id_reserve_base) { + m_parser_ipid->set_ip_id(ip_id & 0x0000efff); } return 0; } @@ -789,10 +792,12 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) { // saving given hw_id on stream for use by tx statistics count if (rule_type == TrexPlatformApi::IF_STAT_IPV4_ID) { - m_parser_ipid->set_ip_id(IP_ID_RESERVE_BASE + hw_id); + m_parser_ipid->set_ip_id(m_ip_id_reserve_base + hw_id); + m_parser_ipid->set_tos_to_cpu(); stream->m_rx_check.m_hw_id = hw_id; } else { m_parser_pl->set_ip_id(FLOW_STAT_PAYLOAD_IP_ID); + m_parser_pl->set_tos_to_cpu(); // for payload rules, we use the range right after ip id rules stream->m_rx_check.m_hw_id = hw_id + MAX_FLOW_STATS; } @@ -1001,7 +1006,9 @@ void CFlowStatRuleMgr::send_start_stop_msg_to_rx(bool is_start) { // s_json - flow statistics json // l_json - latency data json // baseline - If true, send flow statistics fields even if they were not changed since last run -bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, bool baseline) { +// send_all - If true, send data for all pg_ids. This is used for getting statistics in automation API. +// If false, send small amount of pg ids. Used for async interface, for displaying in console +bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, bool baseline, bool send_all) { rx_per_flow_t rx_stats[MAX_FLOW_STATS]; rx_per_flow_t rx_stats_payload[MAX_FLOW_STATS]; tx_per_flow_t tx_stats[MAX_FLOW_STATS]; @@ -1036,13 +1043,39 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo m_api->get_rfc2544_info(rfc2544_info, 0, m_max_hw_id_payload, false); m_api->get_rx_err_cntrs(&rx_err_cntrs); + +#if 0 + // If we want to send all PG_IDs, in groups of 128, enable this, and remove the restrication + // of sending only 8 in loop of building json message below + static int min_to_send = 0; + static int max_to_send = m_max_hw_id; + + min_to_send += 128; + if (min_to_send > m_max_hw_id) { + min_to_send = 0; + } + max_to_send = min_to_send + 128; + if (max_to_send > m_max_hw_id) { + max_to_send = m_max_hw_id; + } + + // If asking for "baseline", send everything always. + if (baseline || send_all) { + min_to_send = 0; + max_to_send = m_max_hw_id; + } +#endif + + int min_to_send = 0; + int max_to_send = m_max_hw_id; + // read hw counters, and update 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, TrexPlatformApi::IF_STAT_IPV4_ID); - for (int i = 0; i <= m_max_hw_id; i++) { + m_api->get_flow_stats(port, rx_stats, (void *)tx_stats, min_to_send, max_to_send, false, TrexPlatformApi::IF_STAT_IPV4_ID); + for (int i = 0; i <= max_to_send - min_to_send; i++) { if (rx_stats[i].get_pkts() != 0) { rx_per_flow_t rx_pkts = rx_stats[i]; - 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 + min_to_send)); if (likely(p_user_id != NULL)) { if (p_user_id->get_rx_cntr(port) != rx_pkts) { p_user_id->set_rx_cntr(port, rx_pkts); @@ -1056,7 +1089,7 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo } if (tx_stats[i].get_pkts() != 0) { tx_per_flow_t tx_pkts = tx_stats[i]; - 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 + min_to_send)); if (likely(p_user_id != NULL)) { if (p_user_id->get_tx_cntr(port) != tx_pkts) { p_user_id->set_tx_cntr(port, tx_pkts); @@ -1125,8 +1158,25 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo l_data_section["global"]["old_flow"] = Json::Value::UInt64(tmp_cnt); } + // TUI only present 4 PG_IDs today, so we send everything only when explicit request comes + // (probably from automation API) + uint16_t max_pg_ids_to_send = 8; + static int times_send_all = 0; + if (send_all) { + times_send_all = 20; + } + if (baseline || (times_send_all > 0)) { + if (times_send_all > 0) + times_send_all--; + max_pg_ids_to_send = UINT16_MAX; + } + flow_stat_user_id_map_it_t it; for (it = m_user_id_map.begin(); it != m_user_id_map.end(); it++) { + if (max_pg_ids_to_send == 0) { + break; + } + max_pg_ids_to_send--; bool send_empty = true; CFlowStatUserIdInfo *user_id_info = it->second; uint32_t user_id = it->first; diff --git a/src/flow_stat.h b/src/flow_stat.h index 25bf421c..b155b917 100644 --- a/src/flow_stat.h +++ b/src/flow_stat.h @@ -32,9 +32,10 @@ #include "internal_api/trex_platform_api.h" // range reserved for rx stat measurement is from IP_ID_RESERVE_BASE to 0xffff -// Do not change this value. In i350 cards, we filter according to first byte of IP ID -// In other places, we identify packets by if (ip_id > IP_ID_RESERVE_BASE) -#define IP_ID_RESERVE_BASE 0xff00 +// This value is used by all NICs, except i350, where value of 0xff00 is used. +// We identify if packet needs handling as flow stat, by: "if (ip_id > IP_ID_RESERVE_BASE)" +#define IP_ID_RESERVE_BASE (0xffff - MAX_FLOW_STATS) + #define FLOW_STAT_PAYLOAD_MAGIC 0xAB #define FLOW_STAT_PAYLOAD_INITIAL_FLOW_SEQ 0x01 extern const uint32_t FLOW_STAT_PAYLOAD_IP_ID; @@ -469,7 +470,7 @@ class CFlowStatRuleMgr { int stop_stream(TrexStream * stream); int get_active_pgids(flow_stat_active_t &result); int set_mode(enum flow_stat_mode_e mode); - bool dump_json(std::string & s_json, std::string & l_json, bool baseline); + bool dump_json(std::string & s_json, std::string & l_json, bool baseline, bool send_all); private: void create(); @@ -493,6 +494,7 @@ class CFlowStatRuleMgr { CFlowStatParser *m_parser_pl; // for payload rules (latency) enum flow_stat_mode_e m_mode; uint16_t m_cap; // capabilities of the NIC driver we are using + uint16_t m_ip_id_reserve_base; // lowest IP ID we use for our needs uint32_t m_rx_cant_count_err[TREX_MAX_PORTS]; uint32_t m_tx_cant_count_err[TREX_MAX_PORTS]; }; diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp index f9ac8c9b..ef9a120b 100644 --- a/src/flow_stat_parser.cpp +++ b/src/flow_stat_parser.cpp @@ -150,6 +150,7 @@ CFlowStatParser_err_t CFlowStatParser::parse(uint8_t *p, uint16_t len) { return FSTAT_PARSER_E_OK; } +// arg is uint32_t in below two functions because we want same function to work for IPv4 and IPv6 int CFlowStatParser::get_ip_id(uint32_t &ip_id) { if (m_ipv4) { ip_id = m_ipv4->getId(); @@ -164,24 +165,34 @@ int CFlowStatParser::get_ip_id(uint32_t &ip_id) { return -1; } -int CFlowStatParser::set_ip_id(uint32_t new_id) { +void CFlowStatParser::set_ip_id(uint32_t new_id) { if (m_ipv4) { + uint16_t ipv4_ip_id = (uint16_t) new_id; // Updating checksum, not recalculating, so if someone put bad checksum on purpose, it will stay bad - m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getFirstWord()), PKT_NTOHS(m_ipv4->getFirstWord() |TOS_TTL_RESERVE_DUPLICATE)); - m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getId()), PKT_NTOHS(new_id)); - m_ipv4->setId(new_id); - m_ipv4->setTOS(m_ipv4->getTOS()|TOS_TTL_RESERVE_DUPLICATE); - return 0; + m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getId()), PKT_NTOHS(ipv4_ip_id)); + m_ipv4->setId(ipv4_ip_id); } if (m_ipv6) { - m_ipv6->setTrafficClass(m_ipv6->getTrafficClass()|TOS_TTL_RESERVE_DUPLICATE); m_ipv6->setFlowLabel(new_id); - return 0; } - return -1; } +// In Mellanox and VIC cards, we use TOS to mark packets to go to CPU +void CFlowStatParser::set_tos_to_cpu() { + if (m_ipv4) { + // Updating checksum, not recalculating, so if someone put bad checksum on purpose, it will stay bad + m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getFirstWord()), PKT_NTOHS(m_ipv4->getFirstWord() + | TOS_GO_TO_CPU)); + m_ipv4->setTOS(m_ipv4->getTOS() | TOS_GO_TO_CPU); + } + + if (m_ipv6) { + m_ipv6->setTrafficClass(m_ipv6->getTrafficClass() | TOS_GO_TO_CPU); + } +} + + int CFlowStatParser::get_l3_proto(uint16_t &proto) { if (m_ipv4) { proto = EthernetHeader::Protocol::IP; diff --git a/src/flow_stat_parser.h b/src/flow_stat_parser.h index c00d7e33..a6e43e0d 100644 --- a/src/flow_stat_parser.h +++ b/src/flow_stat_parser.h @@ -65,7 +65,8 @@ class CFlowStatParser { std::string get_error_str(CFlowStatParser_err_t err); virtual CFlowStatParser_err_t parse(uint8_t *pkt, uint16_t len); virtual int get_ip_id(uint32_t &ip_id); - virtual int set_ip_id(uint32_t ip_id); + virtual void set_ip_id(uint32_t ip_id); + virtual void set_tos_to_cpu(); virtual int get_l3_proto(uint16_t &proto); virtual int get_l4_proto(uint8_t &proto); virtual int get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload_len); @@ -129,8 +130,9 @@ class CPassAllParser : public CFlowStatParser { public: CPassAllParser() : CFlowStatParser (CFlowStatParser::FLOW_STAT_PARSER_MODE_SW) {} virtual CFlowStatParser_err_t parse(uint8_t *pkt, uint16_t len); + void set_tos_to_cpu() {} virtual int get_ip_id(uint32_t &ip_id) { ip_id = 0; return 0;} - virtual int set_ip_id(uint32_t ip_id){return 0;} + virtual void set_ip_id(uint32_t ip_id){} virtual int get_l3_proto(uint16_t &proto){proto = 0; return 0;} virtual int get_l4_proto(uint8_t &proto) {proto = 0; return 0;} virtual int get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload_len) {payload_len = m_len; return 0;} diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h index 16752652..6cb68690 100644 --- a/src/internal_api/trex_platform_api.h +++ b/src/internal_api/trex_platform_api.h @@ -133,7 +133,8 @@ public: virtual void publish_async_data_now(uint32_t key, bool baseline) const = 0; virtual void publish_async_port_attr_changed(uint8_t port_id) const = 0; virtual uint8_t get_dp_core_count() const = 0; - virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const =0; + virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities + , uint16_t &ip_id_base) const =0; virtual int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset , TrexPlatformApi::driver_stat_cap_e type) const = 0; virtual int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const = 0; @@ -174,7 +175,8 @@ public: void publish_async_data_now(uint32_t key, bool baseline) const; void publish_async_port_attr_changed(uint8_t port_id) const; uint8_t get_dp_core_count() const; - void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const; + void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities + , uint16_t &ip_id_base) const; int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset , TrexPlatformApi::driver_stat_cap_e type) const; int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const; @@ -232,7 +234,8 @@ public: virtual void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const { } - virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const {num_counters=128; capabilities=TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; } + virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities + , uint16_t &ip_id_base) const {num_counters=128; capabilities=TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; ip_id_base = 0xff00;} virtual void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const { for (int i = 0; i < m_dp_core_count; i++) { diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 434254a2..c26188d0 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -173,8 +173,7 @@ public: , int min, int max) {return -1;} virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) {} virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd) { return -1;} - virtual int get_stat_counters_num() {return 0;} - virtual int get_rx_stat_capabilities() {return 0;} + virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) = 0; virtual int verify_fw_ver(int i) {return 0;} virtual CFlowStatParser *get_flow_stat_parser(); virtual int set_rcv_all(CPhyEthIF * _if, bool set_on)=0; @@ -230,10 +229,20 @@ public: virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats); virtual void clear_extended_stats(CPhyEthIF * _if); virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd) {return 0;} - virtual int get_stat_counters_num() {return MAX_FLOW_STATS;} - virtual int get_rx_stat_capabilities() { - return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT + virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) { + flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT | TrexPlatformApi::IF_STAT_PAYLOAD; + + if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE + || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) { + num_counters = MAX_FLOW_STATS; + base_ip_id = IP_ID_RESERVE_BASE; + } else { + num_counters = UINT8_MAX; + // Must be 0xff00, since we configure HW filter for the 0xff byte + // The filter must catch all flow stat packets, and latency packets (having 0xffff in IP ID) + base_ip_id = 0xff00; + } } virtual int wait_for_stable_link(); virtual void wait_after_link_up(); @@ -268,11 +277,13 @@ public: virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0; virtual void clear_extended_stats(CPhyEthIF * _if); virtual int wait_for_stable_link(); - virtual int get_stat_counters_num() {return MAX_FLOW_STATS;} - virtual int get_rx_stat_capabilities() { - return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT + virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) { + flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT | TrexPlatformApi::IF_STAT_PAYLOAD; + num_counters = MAX_FLOW_STATS; + base_ip_id = IP_ID_RESERVE_BASE; } + virtual int set_rcv_all(CPhyEthIF * _if, bool set_on) {return 0;} CFlowStatParser *get_flow_stat_parser(); }; @@ -376,10 +387,16 @@ public: virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats); virtual void clear_extended_stats(CPhyEthIF * _if); virtual int wait_for_stable_link(); - virtual int get_stat_counters_num() {return MAX_FLOW_STATS;} - virtual int get_rx_stat_capabilities() { - return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT + virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) { + flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT | TrexPlatformApi::IF_STAT_PAYLOAD; + if ((CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) + || (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE)) { + num_counters = MAX_FLOW_STATS; + } else { + num_counters = 127; + } + base_ip_id = IP_ID_RESERVE_BASE; } virtual CFlowStatParser *get_flow_stat_parser(); int add_del_eth_filter(CPhyEthIF * _if, bool is_add, uint16_t ethertype); @@ -389,10 +406,11 @@ public: class CTRexExtendedDriverBase40G : public CTRexExtendedDriverBase { public: CTRexExtendedDriverBase40G(){ - // Since we support only 128 counters per if, it is OK to configure here 4 statically. + // 4 will make us support 127 flow stat counters // If we want to support more counters in case of card having less interfaces, we // Will have to identify the number of interfaces dynamically. m_if_per_card = 4; + m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_CAP_DROP_PKTS_IF_LNK_DOWN; } @@ -419,16 +437,23 @@ public: virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len); virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max); virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd); - virtual int get_stat_counters_num() {return MAX_FLOW_STATS;} - virtual int get_rx_stat_capabilities() { - uint32_t ret = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; + virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) { + flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; // HW counters on x710 does not support coutning bytes. if ( CGlobalInfo::m_options.preview.get_disable_hw_flow_stat() || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) { - ret |= TrexPlatformApi::IF_STAT_RX_BYTES_COUNT; + flags |= TrexPlatformApi::IF_STAT_RX_BYTES_COUNT; + num_counters = MAX_FLOW_STATS; + } else { + if (m_if_per_card == 4) { + num_counters = MAX_FLOW_STATS_X710; + } else { + num_counters = MAX_FLOW_STATS_XL710; + } } - return ret; + base_ip_id = IP_ID_RESERVE_BASE; + m_max_flow_stats = num_counters; } virtual int wait_for_stable_link(); virtual bool hw_rx_stat_supported(){ @@ -452,6 +477,7 @@ private: private: uint8_t m_if_per_card; + uint16_t m_max_flow_stats; }; class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase { @@ -484,9 +510,13 @@ public: virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len); virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max); virtual int get_stat_counters_num() {return MAX_FLOW_STATS;} - virtual int get_rx_stat_capabilities() { - return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; + virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) { + flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT + | TrexPlatformApi::IF_STAT_PAYLOAD; + num_counters = MAX_FLOW_STATS; + base_ip_id = IP_ID_RESERVE_BASE; } + virtual CFlowStatParser *get_flow_stat_parser(); virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd); virtual int set_rcv_all(CPhyEthIF * _if, bool set_on); @@ -541,9 +571,11 @@ public: virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len); virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max); virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd); - virtual int get_stat_counters_num() {return MAX_FLOW_STATS;} - virtual int get_rx_stat_capabilities() { - return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; + virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) { + flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT + | TrexPlatformApi::IF_STAT_PAYLOAD; + num_counters = 127; //With MAX_FLOW_STATS we saw packet failures in rx_test. Need to check. + base_ip_id = IP_ID_RESERVE_BASE; } virtual int wait_for_stable_link(); // disabling flow control on 40G using DPDK API causes the interface to malfunction @@ -1503,12 +1535,6 @@ void CPhyEthIF::dump_stats_extended(FILE *fd){ } } -int CPhyEthIF::get_rx_stat_capabilities() { - return get_ex_drv()->get_rx_stat_capabilities(); -} - - - void CPhyEthIF::configure(uint16_t nb_rx_queue, uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf){ @@ -4561,7 +4587,7 @@ CGlobalTRex::publish_async_data(bool sync_now, bool baseline) { if (get_is_stateless()) { std::string stat_json; std::string latency_json; - if (m_trex_stateless->m_rx_flow_stat.dump_json(stat_json, latency_json, baseline)) { + if (m_trex_stateless->m_rx_flow_stat.dump_json(stat_json, latency_json, baseline, sync_now)) { m_zmq_publisher.publish_json(stat_json); m_zmq_publisher.publish_json(latency_json); } @@ -6371,19 +6397,26 @@ int CTRexExtendedDriverBase10G::configure_rx_filter_rules(CPhyEthIF * _if) { int CTRexExtendedDriverBase10G::configure_rx_filter_rules_stateless(CPhyEthIF * _if) { uint8_t port_id = _if->get_rte_port_id(); - int ip_id_lsb; + uint8_t ip_id_lsb; - // 0..MAX_FLOW_STATS-1 is for rules using ip_id. - // MAX_FLOW_STATS rule is for the payload rules. Meaning counter value is in the payload - for (ip_id_lsb = 0; ip_id_lsb <= MAX_FLOW_STATS; ip_id_lsb++ ) { + // 0..128-1 is for rules using ip_id. + // 128 rule is for the payload rules. Meaning counter value is in the payload + for (ip_id_lsb = 0; ip_id_lsb <= 128; ip_id_lsb++ ) { struct rte_eth_fdir_filter fdir_filter; int res = 0; memset(&fdir_filter,0,sizeof(fdir_filter)); fdir_filter.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER; fdir_filter.soft_id = ip_id_lsb; // We can use the ip_id_lsb also as filter soft_id - fdir_filter.input.flow_ext.flexbytes[0] = 0xff; - fdir_filter.input.flow_ext.flexbytes[1] = ip_id_lsb; + if (ip_id_lsb == 128) { + // payload rule is for 0xffff + fdir_filter.input.flow_ext.flexbytes[0] = 0xff; + fdir_filter.input.flow_ext.flexbytes[1] = 0xff; + } else { + // less than 255 flow stats, so only byte 1 changes + fdir_filter.input.flow_ext.flexbytes[0] = 0xff & (IP_ID_RESERVE_BASE >> 8); + fdir_filter.input.flow_ext.flexbytes[1] = ip_id_lsb; + } fdir_filter.action.rx_queue = 1; fdir_filter.action.behavior = RTE_ETH_FDIR_ACCEPT; fdir_filter.action.report_status = RTE_ETH_FDIR_NO_REPORT_STATUS; @@ -6664,10 +6697,10 @@ extern "C" int rte_eth_fdir_stats_reset(uint8_t port_id, uint32_t *stats, uint32 // type - rule type. Currently we only support rules in IP ID. // proto - Packet protocol: UDP or TCP -// id - Counter id in HW. We assume it is in the range 0..MAX_FLOW_STATS +// id - Counter id in HW. We assume it is in the range 0..m_max_flow_stats int CTRexExtendedDriverBase40G::add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint16_t l3_proto , uint8_t l4_proto, uint8_t ipv6_next_h, uint16_t id) { - uint32_t rule_id = (port_id % m_if_per_card) * MAX_FLOW_STATS + id; + uint32_t rule_id = (port_id % m_if_per_card) * m_max_flow_stats + id; uint16_t rte_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER; uint8_t next_proto; @@ -6765,7 +6798,7 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if) { void CTRexExtendedDriverBase40G::reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) { uint32_t port_id = _if->get_port_id(); - uint32_t rule_id = (port_id % m_if_per_card) * MAX_FLOW_STATS + min; + uint32_t rule_id = (port_id % m_if_per_card) * m_max_flow_stats + min; // Since flow dir counters are not wrapped around as promised in the data sheet, but rather get stuck at 0xffffffff // we reset the HW value @@ -6786,9 +6819,9 @@ extern "C" int rte_eth_fdir_stats_get(uint8_t port_id, uint32_t *stats, uint32_t // bytes and prev_bytes are not used. X710 fdir filters do not support byte count. int CTRexExtendedDriverBase40G::get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts ,uint32_t *bytes, uint32_t *prev_bytes, int min, int max) { - uint32_t hw_stats[MAX_FLOW_STATS]; + uint32_t hw_stats[MAX_FLOW_STATS_XL710]; uint32_t port_id = _if->get_port_id(); - uint32_t start = (port_id % m_if_per_card) * MAX_FLOW_STATS + min; + uint32_t start = (port_id % m_if_per_card) * m_max_flow_stats + min; uint32_t len = max - min + 1; uint32_t loop_start = min; @@ -7494,9 +7527,9 @@ TrexDpdkPlatformApi::publish_async_port_attr_changed(uint8_t port_id) const { } void -TrexDpdkPlatformApi::get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const { - num_counters = CTRexExtendedDriverDb::Ins()->get_drv()->get_stat_counters_num(); - capabilities = CTRexExtendedDriverDb::Ins()->get_drv()->get_rx_stat_capabilities(); +TrexDpdkPlatformApi::get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities + , uint16_t &ip_id_base) const { + CTRexExtendedDriverDb::Ins()->get_drv()->get_rx_stat_capabilities(capabilities, num_counters ,ip_id_base); } int TrexDpdkPlatformApi::get_flow_stats(uint8 port_id, void *rx_stats, void *tx_stats, int min, int max, bool reset diff --git a/src/pkt_gen.cpp b/src/pkt_gen.cpp index 9dc5ade1..e95398d4 100644 --- a/src/pkt_gen.cpp +++ b/src/pkt_gen.cpp @@ -236,7 +236,7 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t case EthernetHeader::Protocol::IP: ip->setTimeToLive(ttl); if (flags & DPF_TOS_1) { - ip->setTOS(TOS_TTL_RESERVE_DUPLICATE); + ip->setTOS(TOS_GO_TO_CPU); }else{ ip->setTOS(0x2); } @@ -246,7 +246,7 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t case EthernetHeader::Protocol::IPv6: ipv6->setHopLimit(ttl); if (flags & DPF_TOS_1) { - ipv6->setTrafficClass(TOS_TTL_RESERVE_DUPLICATE); + ipv6->setTrafficClass(TOS_GO_TO_CPU); }else{ ipv6->setTrafficClass(0x2); } diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index 836dc5de..54945f1c 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -72,7 +72,7 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { /* check packet size */ if ( (pkt_binary.size() < TrexStream::MIN_PKT_SIZE_BYTES) || (pkt_binary.size() > TrexStream::MAX_PKT_SIZE_BYTES) ) { std::stringstream ss; - ss << "bad packet size provided: should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES; + ss << "Bad packet size provided: " << pkt_binary.size() << ". Should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES; generate_execute_err(result, ss.str()); } diff --git a/src/stateless/cp/trex_exception.h b/src/stateless/cp/trex_exception.h index ffc2f734..f4d7195a 100644 --- a/src/stateless/cp/trex_exception.h +++ b/src/stateless/cp/trex_exception.h @@ -51,7 +51,6 @@ class TrexException : public std::runtime_error T_FLOW_STAT_NO_STREAMS_EXIST, T_FLOW_STAT_ALREADY_STARTED, T_FLOW_STAT_ALREADY_EXIST, - T_FLOW_STAT_FAILED_CHANGE_IP_ID, T_FLOW_STAT_NO_FREE_HW_ID, T_FLOW_STAT_RX_CORE_START_FAIL, T_FLOW_STAT_BAD_HW_ID, diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 423cd443..8aa45753 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -174,7 +174,8 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api api->get_interface_info(port_id, m_api_info); /* get RX caps */ - api->get_interface_stat_info(port_id, m_rx_count_num, m_rx_caps); + uint16_t ip_id_base; + api->get_interface_stat_info(port_id, m_rx_count_num, m_rx_caps, ip_id_base); /* get the DP cores belonging to this port */ api->port_id_to_cores(m_port_id, core_pair_list); diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index b6aa15be..dd5282b8 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -998,7 +998,7 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port, if (stream->m_rx_check.m_enabled) { node->set_stat_needed(); - uint8_t hw_id = stream->m_rx_check.m_hw_id; + uint16_t hw_id = stream->m_rx_check.m_hw_id; assert (hw_id < MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD); node->set_stat_hw_id(hw_id); // no support for cache with flow stat payload rules diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index b74e0f62..9accc3f2 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -100,10 +100,10 @@ private: double m_next_time_offset; /* in sec */ uint16_t m_action_counter; - uint8_t m_stat_hw_id; // hw id used to count rx and tx stats - uint8_t m_null_stream; + uint16_t m_stat_hw_id; // hw id used to count rx and tx stats uint16_t m_cache_array_cnt; - uint16_t m_pad12; + uint8_t m_null_stream; + uint8_t m_pad12; stream_state_t m_state; uint8_t m_port_id; @@ -301,7 +301,7 @@ public: m_stat_hw_id = hw_id; } - socket_id_t get_stat_hw_id() { + uint16_t get_stat_hw_id() { return ( m_stat_hw_id ); } diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp index 0beeae69..17aecb03 100644 --- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp @@ -24,6 +24,7 @@ #include "common/Network/Packet/Arp.h" #include "pkt_gen.h" #include "trex_stateless_capture.h" +#include "stateless/cp/trex_stateless.h" /************************************** * latency RX feature @@ -36,6 +37,8 @@ RXLatency::RXLatency() { for (int i = 0; i < MAX_FLOW_STATS; i++) { m_rx_pg_stat[i].clear(); + } + for (int i = 0; i < MAX_FLOW_STATS_PAYLOAD; i++) { m_rx_pg_stat_payload[i].clear(); } } @@ -50,6 +53,15 @@ RXLatency::create(CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs) { } else { m_rcv_all = false; } + + uint16_t num_counters, cap, ip_id_base; + TrexStateless *tstateless = get_stateless_obj(); + assert(tstateless); + + const TrexPlatformApi *api = tstateless->get_platform_api(); + assert(api); + api->get_interface_stat_info(0, num_counters, cap, ip_id_base); + m_ip_id_base = ip_id_base; } void @@ -58,7 +70,7 @@ RXLatency::handle_pkt(const rte_mbuf_t *m) { int ret = parser.parse(rte_pktmbuf_mtod(m, uint8_t *), m->pkt_len); if (m_rcv_all || (ret == 0)) { - uint32_t ip_id; + uint32_t ip_id = 0; int ret2 = parser.get_ip_id(ip_id); if (m_rcv_all || ( ret2 == 0)) { if (m_rcv_all || is_flow_stat_id(ip_id)) { @@ -157,7 +169,7 @@ RXLatency::handle_pkt(const rte_mbuf_t *m) { curr_rfc2544->add_sample(ctime); } } else { - hw_id = get_hw_id(ip_id); + hw_id = get_hw_id((uint16_t)ip_id); if (hw_id < MAX_FLOW_STATS) { m_rx_pg_stat[hw_id].add_pkts(1); m_rx_pg_stat[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.h b/src/stateless/rx/trex_stateless_rx_port_mngr.h index ea360490..b6d929ed 100644 --- a/src/stateless/rx/trex_stateless_rx_port_mngr.h +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h @@ -55,9 +55,12 @@ public: void reset_stats(); private: + // below functions for both IP v4 and v6, so they need uint32_t id bool is_flow_stat_id(uint32_t id) { - if ((id & 0x000fff00) == IP_ID_RESERVE_BASE) return true; - return false; + if ((uint16_t) id >= m_ip_id_base) + return true; + else + return false; } bool is_flow_stat_payload_id(uint32_t id) { @@ -66,7 +69,7 @@ private: } uint16_t get_hw_id(uint16_t id) { - return (0x00ff & id); + return (~m_ip_id_base & (uint16_t )id); } public: @@ -77,6 +80,7 @@ public: bool m_rcv_all; CRFC2544Info *m_rfc2544; CRxCoreErrCntrs *m_err_cntrs; + uint16_t m_ip_id_base; }; diff --git a/src/trex_defs.h b/src/trex_defs.h index 60a60df9..c4d6531e 100644 --- a/src/trex_defs.h +++ b/src/trex_defs.h @@ -23,8 +23,10 @@ limitations under the License. #define TREX_MAX_PORTS 16 -// maximum number of IP ID type flow stats we support -#define MAX_FLOW_STATS 127 +// maximum number of IP ID type flow stats we support. Must be in the form 2^x - 1 +#define MAX_FLOW_STATS 1023 +#define MAX_FLOW_STATS_X710 127 +#define MAX_FLOW_STATS_XL710 255 // maximum number of payload type flow stats we support #define MAX_FLOW_STATS_PAYLOAD 128 |