summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2017-03-13 22:28:09 +0200
committerIdo Barnea <ibarnea@cisco.com>2017-03-14 11:48:46 +0200
commitaf25eb9b8463225827fd38223f36a9c361f2d254 (patch)
treea730c203d0befb660501b7fdce982d6607019a62
parent11c76dca3353e3407c907a60d9b35746f9fc96c1 (diff)
Software mode for latency and flow stat statistics
Also supporting QinQ for flow stat Signed-off-by: Ido Barnea <ibarnea@cisco.com>
-rwxr-xr-xsrc/common/Network/Packet/EthernetHeader.h27
-rwxr-xr-xsrc/common/Network/Packet/EthernetHeader.inl10
-rw-r--r--src/flow_stat.cpp88
-rw-r--r--src/flow_stat.h3
-rw-r--r--src/flow_stat_parser.cpp123
-rw-r--r--src/flow_stat_parser.h11
-rw-r--r--src/main_dpdk.cpp83
-rw-r--r--src/main_dpdk.h1
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.cpp16
9 files changed, 286 insertions, 76 deletions
diff --git a/src/common/Network/Packet/EthernetHeader.h b/src/common/Network/Packet/EthernetHeader.h
index 002d6c25..cf93e850 100755
--- a/src/common/Network/Packet/EthernetHeader.h
+++ b/src/common/Network/Packet/EthernetHeader.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2015-2016 Cisco Systems, Inc.
+Copyright (c) 2015-2017 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -36,15 +36,16 @@ public:
{
enum Type
{
- IP = 0x0800,
- VLAN = 0x8100,
- ARP = 0x0806,
- IPv6 = 0x86DD,
- MPLS_Unicast = 0x8847,
- MPLS_Multicast = 0x8848,
- PPP = 0x880b,
- PPPoED = 0x8863,
- PPPoES = 0x8864
+ IP = 0x0800,
+ VLAN = 0x8100,
+ ARP = 0x0806,
+ IPv6 = 0x86DD,
+ MPLS_Unicast = 0x8847,
+ MPLS_Multicast = 0x8848,
+ PPP = 0x880b,
+ PPPoED = 0x8863,
+ PPPoES = 0x8864,
+ QINQ = 0x88A8
};
};
@@ -81,7 +82,8 @@ public:
// Retrieve VLAN fields for tag and protocol information
inline uint16_t getVlanTag ();
inline uint16_t getVlanProtocol ();
-
+ inline uint16_t getQinQTag ();
+ inline uint16_t getQinQProtocol ();
void dump (FILE* fd);
@@ -92,7 +94,8 @@ private:
uint16_t myProtocol;
uint16_t myVlanTag;
uint16_t myVlanProtocol;
-
+ uint16_t myQinQTag;
+ uint16_t myQinQProtocol;
};
#include "EthernetHeader.inl"
diff --git a/src/common/Network/Packet/EthernetHeader.inl b/src/common/Network/Packet/EthernetHeader.inl
index 0d6e32c9..4091b945 100755
--- a/src/common/Network/Packet/EthernetHeader.inl
+++ b/src/common/Network/Packet/EthernetHeader.inl
@@ -37,3 +37,13 @@ inline uint16_t EthernetHeader::getVlanTag()
{
return( PKT_HTONS(myVlanTag));
}
+
+inline uint16_t EthernetHeader::getQinQProtocol()
+{
+ return( PKT_HTONS(myQinQProtocol));
+}
+
+inline uint16_t EthernetHeader::getQinQTag()
+{
+ return( PKT_HTONS(myQinQTag));
+}
diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp
index 92cbca6e..fcbd8304 100644
--- a/src/flow_stat.cpp
+++ b/src/flow_stat.cpp
@@ -454,7 +454,8 @@ CFlowStatRuleMgr::CFlowStatRuleMgr() {
m_num_started_streams = 0;
m_ring_to_rx = NULL;
m_cap = 0;
- m_parser = NULL;
+ 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);
@@ -465,7 +466,8 @@ CFlowStatRuleMgr::CFlowStatRuleMgr() {
}
CFlowStatRuleMgr::~CFlowStatRuleMgr() {
- delete m_parser;
+ delete m_parser_ipid;
+ delete m_parser_pl;
#ifdef TREX_SIM
// In simulator, nobody handles the messages to RX, so need to free them to have clean valgrind run.
if (m_ring_to_rx) {
@@ -493,9 +495,19 @@ void CFlowStatRuleMgr::create() {
m_ring_to_rx = CMsgIns::Ins()->getCpRx()->getRingCpToDp(0);
assert(m_ring_to_rx);
m_rx_core = get_rx_sl_core_obj();
- m_parser = m_api->get_flow_stat_parser();
- assert(m_parser);
m_cap = cap;
+
+ if ((CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE)
+ || (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS)) {
+ set_mode(FLOW_STAT_MODE_PASS_ALL);
+ m_parser_ipid = new CFlowStatParserSW;
+ m_parser_pl = new CPassAllParser;
+ } else {
+ m_parser_ipid = m_api->get_flow_stat_parser();
+ m_parser_pl = m_api->get_flow_stat_parser();
+ }
+ assert(m_parser_ipid);
+ assert(m_parser_pl);
}
std::ostream& operator<<(std::ostream& os, const CFlowStatRuleMgr& cf) {
@@ -578,22 +590,17 @@ int CFlowStatRuleMgr::add_stream_internal(TrexStream * stream, bool do_action) {
throw TrexFStatEx("Interface does not support given rule type", TrexException::T_FLOW_STAT_BAD_RULE_TYPE_FOR_IF);
}
- // compile_stream throws exception if something goes wrong
- compile_stream(stream, m_parser);
-
switch(rule_type) {
case TrexPlatformApi::IF_STAT_IPV4_ID:
uint16_t l3_proto;
+ // compile_stream throws exception if something goes wrong
+ compile_stream(stream, m_parser_ipid);
- if (m_mode == FLOW_STAT_MODE_PASS_ALL) {
- throw TrexFStatEx("Can not add flow stat stream in 'receive all' mode", TrexException::T_FLOW_STAT_BAD_RULE_TYPE_FOR_MODE);
- }
-
- if (m_parser->get_l3_proto(l3_proto) < 0) {
+ if (m_parser_ipid->get_l3_proto(l3_proto) < 0) {
throw TrexFStatEx("Failed determining l3 proto for packet", TrexException::T_FLOW_STAT_FAILED_FIND_L3);
}
uint8_t l4_proto;
- if (m_parser->get_l4_proto(l4_proto) < 0) {
+ if (m_parser_ipid->get_l4_proto(l4_proto) < 0) {
throw TrexFStatEx("Failed determining l4 proto for packet", TrexException::T_FLOW_STAT_FAILED_FIND_L4);
}
@@ -606,7 +613,10 @@ int CFlowStatRuleMgr::add_stream_internal(TrexStream * stream, bool do_action) {
break;
case TrexPlatformApi::IF_STAT_PAYLOAD:
uint16_t payload_len;
- if (m_parser->get_payload_len(stream->m_pkt.binary, stream->m_pkt.len, payload_len) < 0) {
+ // compile_stream throws exception if something goes wrong
+ compile_stream(stream, m_parser_pl);
+
+ if (m_parser_pl->get_payload_len(stream->m_pkt.binary, stream->m_pkt.len, payload_len) < 0) {
throw TrexFStatEx("Failed getting payload len", TrexException::T_FLOW_STAT_BAD_PKT_FORMAT);
}
if (payload_len < sizeof(struct flow_stat_payload_header)) {
@@ -690,19 +700,19 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
// first handle streams that do not need rx stat
if (! stream->m_rx_check.m_enabled) {
try {
- compile_stream(stream, m_parser);
+ compile_stream(stream, m_parser_ipid);
} catch (TrexFStatEx) {
// If no statistics needed, and we can't parse the stream, that's OK.
return 0;
}
uint32_t ip_id;
- if (m_parser->get_ip_id(ip_id) < 0) {
+ 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->set_ip_id(ip_id & 0xefff) < 0) {
+ 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);
}
@@ -727,17 +737,18 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
if ((m_cap & rule_type) == 0) {
throw TrexFStatEx("Interface does not support given rule type", TrexException::T_FLOW_STAT_BAD_RULE_TYPE_FOR_IF);
}
-
- // compile_stream throws exception if something goes wrong
- if ((ret = compile_stream(stream, m_parser)) < 0)
- return ret;
-
uint16_t hw_id;
switch(rule_type) {
case TrexPlatformApi::IF_STAT_IPV4_ID:
+ // compile_stream throws exception if something goes wrong
+ if ((ret = compile_stream(stream, m_parser_ipid)) < 0)
+ return ret;
break;
case TrexPlatformApi::IF_STAT_PAYLOAD:
+ // compile_stream throws exception if something goes wrong
+ if ((ret = compile_stream(stream, m_parser_pl)) < 0)
+ return ret;
break;
default:
throw TrexFStatEx("Wrong rule_type", TrexException::T_FLOW_STAT_BAD_RULE_TYPE);
@@ -789,10 +800,10 @@ 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->set_ip_id(IP_ID_RESERVE_BASE + hw_id);
+ m_parser_ipid->set_ip_id(IP_ID_RESERVE_BASE + hw_id);
stream->m_rx_check.m_hw_id = hw_id;
} else {
- m_parser->set_ip_id(FLOW_STAT_PAYLOAD_IP_ID);
+ m_parser_pl->set_ip_id(FLOW_STAT_PAYLOAD_IP_ID);
// for payload rules, we use the range right after ip id rules
stream->m_rx_check.m_hw_id = hw_id + MAX_FLOW_STATS;
}
@@ -803,9 +814,9 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
#endif
if (m_num_started_streams == 0) {
-
+
send_start_stop_msg_to_rx(true); // First transmitting stream. Rx core should start reading packets;
-
+
//also good time to zero global counters
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));
@@ -824,7 +835,7 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
}
}
#endif
-
+
} else {
// make sure rx core is working. If not, we got really confused somehow.
if (m_rx_core)
@@ -951,18 +962,23 @@ int CFlowStatRuleMgr::set_mode(enum flow_stat_mode_e mode) {
switch (mode) {
case FLOW_STAT_MODE_PASS_ALL:
- delete m_parser;
- m_parser = new CPassAllParser;
+ delete m_parser_ipid;
+ delete m_parser_pl;
+ m_parser_ipid = new CFlowStatParserSW;
+ m_parser_pl = new CPassAllParser;
break;
case FLOW_STAT_MODE_NORMAL:
- delete m_parser;
- m_parser = m_api->get_flow_stat_parser();
- assert(m_parser);
+ delete m_parser_ipid;
+ delete m_parser_pl;
+ m_parser_ipid = m_api->get_flow_stat_parser();
+ m_parser_pl = m_api->get_flow_stat_parser();
break;
default:
return -1;
}
+ assert(m_parser_ipid);
+ assert(m_parser_pl);
m_mode = mode;
@@ -972,20 +988,20 @@ int CFlowStatRuleMgr::set_mode(enum flow_stat_mode_e mode) {
extern bool rx_should_stop;
void CFlowStatRuleMgr::send_start_stop_msg_to_rx(bool is_start) {
TrexStatelessCpToRxMsgBase *msg;
-
+
if (is_start) {
static MsgReply<bool> reply;
reply.reset();
-
+
msg = new TrexStatelessRxEnableLatency(reply);
m_ring_to_rx->Enqueue((CGenNode *)msg);
-
+
/* hold until message was ack'ed - otherwise we might lose packets */
if (m_rx_core) {
reply.wait_for_reply();
assert(m_rx_core->is_working());
}
-
+
} else {
msg = new TrexStatelessRxDisableLatency();
m_ring_to_rx->Enqueue((CGenNode *)msg);
diff --git a/src/flow_stat.h b/src/flow_stat.h
index e0c995ab..25bf421c 100644
--- a/src/flow_stat.h
+++ b/src/flow_stat.h
@@ -489,7 +489,8 @@ class CFlowStatRuleMgr {
int m_max_hw_id_payload; // max hw id we ever used for payload rules
int m_num_started_streams; // How many started (transmitting) streams we have
CNodeRing *m_ring_to_rx; // handle for sending messages to Rx core
- CFlowStatParser *m_parser;
+ CFlowStatParser *m_parser_ipid; // for IP_ID rules (flow stat)
+ 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
uint32_t m_rx_cant_count_err[TREX_MAX_PORTS];
diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp
index 4a6722e6..417299ee 100644
--- a/src/flow_stat_parser.cpp
+++ b/src/flow_stat_parser.cpp
@@ -371,6 +371,129 @@ int CFlowStatParserTest::test() {
return 0;
}
+int CFlowStatParserSW::parse(uint8_t *p, uint16_t len) {
+ EthernetHeader *ether = (EthernetHeader *)p;
+ int min_len = ETH_HDR_LEN;
+ reset();
+
+ if (len < min_len)
+ return -1;
+
+ m_start = p;
+ m_len = len;
+ switch( ether->getNextProtocol() ) {
+ case EthernetHeader::Protocol::IP :
+ min_len += IPV4_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv4 = (IPHeader *)(p + ETH_HDR_LEN);
+ m_l4 = ((uint8_t *)m_ipv4) + m_ipv4->getHeaderLength();
+ m_l4_proto = m_ipv4->getProtocol();
+ m_stat_supported = true;
+ break;
+ case EthernetHeader::Protocol::IPv6 :
+ min_len += IPV6_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv6 = (IPv6Header *)(p + ETH_HDR_LEN);
+ m_stat_supported = true;
+ break;
+ case EthernetHeader::Protocol::VLAN :
+ m_vlan_offset = 4;
+ min_len += 4;
+ if (len < min_len)
+ return -1;
+
+ switch ( ether->getVlanProtocol() ){
+ case EthernetHeader::Protocol::IP:
+ min_len += IPV4_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv4 = (IPHeader *)(p + ETH_HDR_LEN + 4);
+ m_l4 = ((uint8_t *)m_ipv4) + m_ipv4->getHeaderLength();
+ m_l4_proto = m_ipv4->getProtocol();
+ m_stat_supported = true;
+ break;
+ case EthernetHeader::Protocol::IPv6 :
+ min_len += IPV6_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv6 = (IPv6Header *)(p + ETH_HDR_LEN + 4);
+ m_stat_supported = true;
+ break;
+ case EthernetHeader::Protocol::VLAN :
+ m_vlan_offset = 8;
+ min_len += 8;
+ if (len < min_len)
+ return -1;
+
+ switch ( ether->getQinQProtocol() ){
+ case EthernetHeader::Protocol::IP:
+ min_len += IPV4_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv4 = (IPHeader *)(p + ETH_HDR_LEN + 8);
+ m_l4 = ((uint8_t *)m_ipv4) + m_ipv4->getHeaderLength();
+ m_l4_proto = m_ipv4->getProtocol();
+ m_stat_supported = true;
+ break;
+ case EthernetHeader::Protocol::IPv6 :
+ min_len += IPV6_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv6 = (IPv6Header *)(p + ETH_HDR_LEN + 8);
+ m_stat_supported = true;
+ break;
+ default:
+ m_stat_supported = false;
+ return -1;
+ }
+ break;
+
+ default:
+ m_stat_supported = false;
+ return -1;
+ }
+ break;
+
+ case EthernetHeader::Protocol::QINQ :
+ m_vlan_offset = 8;
+ min_len += 8;
+ if (len < min_len)
+ return -1;
+
+ switch ( ether->getQinQProtocol() ) {
+ case EthernetHeader::Protocol::IP:
+ min_len += IPV4_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv4 = (IPHeader *)(p + ETH_HDR_LEN + 8);
+ m_l4 = ((uint8_t *)m_ipv4) + m_ipv4->getHeaderLength();
+ m_l4_proto = m_ipv4->getProtocol();
+ m_stat_supported = true;
+ break;
+ case EthernetHeader::Protocol::IPv6 :
+ min_len += IPV6_HDR_LEN;
+ if (len < min_len)
+ return -1;
+ m_ipv6 = (IPv6Header *)(p + ETH_HDR_LEN + 8);
+ m_stat_supported = true;
+ break;
+ default:
+ m_stat_supported = false;
+ return -1;
+ }
+ break;
+
+ default:
+ m_stat_supported = false;
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
// In 82599 10G card we do not support VLANs
int C82599Parser::parse(uint8_t *p, uint16_t len) {
EthernetHeader *ether = (EthernetHeader *)p;
diff --git a/src/flow_stat_parser.h b/src/flow_stat_parser.h
index 51816e1a..682bc09f 100644
--- a/src/flow_stat_parser.h
+++ b/src/flow_stat_parser.h
@@ -28,7 +28,8 @@
#include "common/Network/Packet/TcpHeader.h"
#include "mbuf.h"
-// Basic flow stat parser. Relevant for xl710/x710/x350 cards
+// Basic flow stat parser. Imitating HW behavior. It can parse only packets matched by HW fdir rules we define.
+// Relevant for xl710/x710, i350, Cisco VIC, Mellanox cards
class CFlowStatParser {
friend class CFlowStatParserTest;
public:
@@ -97,6 +98,14 @@ class CFlowStatParser {
uint8_t m_vlan_offset;
};
+// parser used in --software mode and virtual cards. No hardware limitation. We can support any packert type here.
+class CFlowStatParserSW : public CFlowStatParser {
+ public:
+ CFlowStatParserSW() {}
+ ~CFlowStatParserSW() {}
+ int parse(uint8_t *pkt, uint16_t len);
+};
+
// relevant for 82599 card
class C82599Parser : public CFlowStatParser {
public:
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 1f9dadcd..89c6b654 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -268,6 +268,7 @@ public:
| TrexPlatformApi::IF_STAT_PAYLOAD;
}
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on) {return 0;}
+ CFlowStatParser *get_flow_stat_parser();
};
class CTRexExtendedDriverVirtio : public CTRexExtendedDriverVirtBase {
@@ -417,14 +418,18 @@ public:
virtual int get_rx_stat_capabilities() {
uint32_t ret = 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() ) {
+ 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;
}
return ret;
}
virtual int wait_for_stable_link();
virtual bool hw_rx_stat_supported(){
- if (CGlobalInfo::m_options.preview.get_disable_hw_flow_stat()) {
+ 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) {
return false;
} else {
return true;
@@ -776,7 +781,7 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_CLIENT_CFG_FILE, "--client_cfg", SO_REQ_SEP },
{ OPT_CLIENT_CFG_FILE, "--client-cfg", SO_REQ_SEP },
{ OPT_NO_KEYBOARD_INPUT, "--no-key", SO_NONE },
- { OPT_VIRT_ONE_TX_RX_QUEUE, "--vm-sim", SO_NONE },
+ { OPT_VIRT_ONE_TX_RX_QUEUE, "--software", SO_NONE },
{ OPT_PREFIX, "--prefix", SO_REQ_SEP },
{ OPT_SEND_DEBUG_PKT, "--send-debug-pkt", SO_REQ_SEP },
{ OPT_MBUF_FACTOR, "--mbuf-factor", SO_REQ_SEP },
@@ -859,10 +864,10 @@ static int usage(){
printf(" -s : Single core. Run only one data path core. For debug \n");
printf(" --send-debug-pkt <proto> : Do not run traffic generator. Just send debug packet and dump receive queues \n");
printf(" Supported protocols are 1 for icmp, 2 for UDP, 3 for TCP, 4 for ARP, 5 for 9K UDP \n");
+ printf(" --software : Do not configure any hardare rules. In this mode we used 1 core, and one RX queue and one TX queue per port\n");
printf(" -v <verbosity level> : The higher the value, print more debug information \n");
printf(" --vlan : Relevant only for stateless mode with Intel 82599 10G NIC \n");
printf(" When configuring flow stat and latency per stream rules, assume all streams uses VLAN \n");
- printf(" --vm-sim : Simulate vm with driver of one input queue and one output queue \n");
printf(" -w <num> : Wait num seconds between init of interfaces and sending traffic, default is 1 \n");
printf("\n");
@@ -870,7 +875,7 @@ static int usage(){
printf(" basic trex run for 20 sec and multiplier of 10 \n");
printf(" t-rex-64 -f cap2/dns.yaml -m 10 -d 20 \n");
printf("\n\n");
- printf(" Copyright (c) 2015-2016 Cisco Systems, Inc. \n");
+ printf(" Copyright (c) 2015-2017 Cisco Systems, Inc. \n");
printf(" \n");
printf(" Licensed under the Apache License, Version 2.0 (the 'License') \n");
printf(" you may not use this file except in compliance with the License. \n");
@@ -1118,6 +1123,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
case OPT_VIRT_ONE_TX_RX_QUEUE:
CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE);
+ po->preview.setCores(1); // Only one TX core supported in software mode currently
break;
case OPT_PREFIX:
@@ -1536,6 +1542,24 @@ void CPhyEthIF::configure_rx_duplicate_rules(){
}
}
+int CPhyEthIF::set_port_rcv_all(bool is_rcv) {
+ // In these modes we are always receiving all packets anyway.
+ switch (CGlobalInfo::get_queues_mode()) {
+ case CGlobalInfo::Q_MODE_ONE_QUEUE:
+ // In this mode we are always receiving all packets anyway.
+ break;
+ case CGlobalInfo::Q_MODE_RSS:
+ //todo: need to send announcment to all tx cores
+ //todo: need new function set_all_ports rcv all, to be able to send less tx messages
+ break;
+ default:
+ get_ex_drv()->set_rcv_all(this, is_rcv);
+ break;
+ }
+
+ return 0;
+}
+
void CPhyEthIF::stop_rx_drop_queue() {
// In debug mode, we want to see all packets. Don't want to disable any queue.
if ( (CGlobalInfo::get_queues_mode() != CGlobalInfo::Q_MODE_NORMAL)
@@ -3414,10 +3438,9 @@ void CGlobalTRex::pre_test() {
for (int port_id = 0; port_id < m_max_ports; port_id++) {
CPhyEthIF *pif = &m_ports[port_id];
// Configure port to send all packets to software
- CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, true);
+ pif->set_port_rcv_all(true);
}
-
pretest.send_grat_arp_all();
bool ret;
int count = 0;
@@ -3505,12 +3528,10 @@ void CGlobalTRex::pre_test() {
CPhyEthIF *pif = &m_ports[port_id];
CPreTestStats pre_stats = pretest.get_stats(port_id);
pif->set_ignore_stats_base(pre_stats);
-
// Configure port back to normal mode. Only relevant packets handled by software.
- CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, false);
-
- }
+ pif->set_port_rcv_all(false);
}
+ }
/* for stateless only - set port mode */
if (get_is_stateless()) {
@@ -5785,7 +5806,7 @@ int main_test(int argc , char * argv[]){
for (int i = 0; i < 100; i++) {
for (int port_id = 0; port_id < g_trex.m_max_ports; port_id++) {
CPhyEthIF *pif = &g_trex.m_ports[port_id];
- CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, true);
+ pif->set_port_rcv_all(true);
}
ret = debug.test_send(D_PKT_TYPE_HW_VERIFY_RCV_ALL);
if (ret != 0) {
@@ -5811,7 +5832,7 @@ int main_test(int argc , char * argv[]){
if (CGlobalInfo::m_options.m_debug_pkt_proto == D_PKT_TYPE_HW_VERIFY_RCV_ALL) {
for (int port_id = 0; port_id < g_trex.m_max_ports; port_id++) {
CPhyEthIF *pif = &g_trex.m_ports[port_id];
- CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, true);
+ pif->set_port_rcv_all(true);
}
}
ret = debug.test_send(CGlobalInfo::m_options.m_debug_pkt_proto);
@@ -5902,7 +5923,6 @@ void set_driver() {
}
CTRexExtendedDriverDb::Ins()->set_driver_name(dev_info.driver_name);
-
}
/*
@@ -6549,11 +6569,6 @@ static struct fdir_hw_id_params_t fdir_hw_id_rule_params[512];
// So, the rule will apply if packet has either the correct ttl or IP ID, depending if we are in statfull or stateless.
void CTRexExtendedDriverBase40G::add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint8_t ttl
, uint16_t ip_id, uint8_t l4_proto, int queue, uint16_t stat_idx) {
- // We want to allow the use of X710 in "VM mode", for performance testing.
- // In this mode, we don't want any hardware rules. Everything done by software.
- if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE)
- return;
-
int ret=rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
static int filter_soft_id = 0;
@@ -6605,6 +6620,7 @@ void CTRexExtendedDriverBase40G::add_del_rules(enum rte_filter_op op, uint8_t po
}
ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, op, (void*)&filter);
+
#if 0
//todo: fix
if ( ret != 0 ) {
@@ -7173,6 +7189,11 @@ void CTRexExtendedDriverBaseVIC::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSta
int CTRexExtendedDriverBaseVIC::verify_fw_ver(int port_id) {
+ if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
+ || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
+ return 0;
+ }
+
struct rte_eth_fdir_info fdir_info;
if ( rte_eth_dev_filter_ctrl(port_id,RTE_ETH_FILTER_FDIR, RTE_ETH_FILTER_INFO,(void *)&fdir_info) == 0 ){
@@ -7181,13 +7202,15 @@ int CTRexExtendedDriverBaseVIC::verify_fw_ver(int port_id) {
if (CGlobalInfo::m_options.preview.getVMode() >= 1) {
printf("VIC port %d: FW support advanced filtering \n", port_id);
}
- return (0);
+ return 0;
}
}
- printf("Error: VIC firmware should upgrade to support advanced filtering \n");
+ printf("Warning: In order to fully utilize the VIC NIC, firmware should be upgraded to support advanced filtering \n");
printf(" Please refer to %s for upgrade instructions\n",
"https://trex-tgn.cisco.com/trex/doc/trex_manual.html");
+ printf("If this is an unsupported card, or you do not want to upgrade, you can use --software command line arg\n");
+ printf("This will work without hardware support (meaning reduced performance)\n");
exit(1);
}
@@ -7252,6 +7275,12 @@ int CTRexExtendedDriverVirtBase::wait_for_stable_link(){
return (0);
}
+CFlowStatParser *CTRexExtendedDriverVirtBase::get_flow_stat_parser() {
+ CFlowStatParser *parser = new CFlowStatParserSW();
+ assert (parser);
+ return parser;
+}
+
void CTRexExtendedDriverVirtio::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats) {
get_extended_stats_fixed(_if, stats, 4, 4);
}
@@ -7478,12 +7507,22 @@ int TrexDpdkPlatformApi::reset_hw_flow_stats(uint8_t port_id) const {
int TrexDpdkPlatformApi::add_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto
, uint8_t ipv6_next_h, uint16_t id) const {
+ if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
+ || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
+ return 0;
+ }
+
return CTRexExtendedDriverDb::Ins()->get_drv()
->add_del_rx_flow_stat_rule(port_id, RTE_ETH_FILTER_ADD, l3_type, l4_proto, ipv6_next_h, id);
}
int TrexDpdkPlatformApi::del_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto
, uint8_t ipv6_next_h, uint16_t id) const {
+ if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
+ || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
+ return 0;
+ }
+
return CTRexExtendedDriverDb::Ins()->get_drv()
->add_del_rx_flow_stat_rule(port_id, RTE_ETH_FILTER_DELETE, l3_type, l4_proto, ipv6_next_h, id);
}
@@ -7540,7 +7579,7 @@ int DpdkTRexPortAttr::set_rx_filter_mode(rx_filter_mode_e rx_filter_mode) {
CPhyEthIF *_if = &g_trex.m_ports[m_port_id];
bool recv_all = (rx_filter_mode == RX_FILTER_MODE_ALL);
- int rc = CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(_if, recv_all);
+ int rc = _if->set_port_rcv_all(recv_all);
if (rc != 0) {
return (rc);
}
diff --git a/src/main_dpdk.h b/src/main_dpdk.h
index e444ad2b..3b5d283f 100644
--- a/src/main_dpdk.h
+++ b/src/main_dpdk.h
@@ -112,6 +112,7 @@ class CPhyEthIF {
const struct rte_eth_txconf *tx_conf);
void stop_rx_drop_queue();
void configure_rx_duplicate_rules();
+ int set_port_rcv_all(bool is_rcv);
void start();
void stop();
void disable_flow_control();
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
index ab7719f6..ca06619b 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
@@ -44,18 +44,26 @@ void
RXLatency::create(CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs) {
m_rfc2544 = rfc2544;
m_err_cntrs = err_cntrs;
+ if ((CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE)
+ || (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS)) {
+ m_rcv_all = true;
+ } else {
+ m_rcv_all = false;
+ }
}
void
RXLatency::handle_pkt(const rte_mbuf_t *m) {
- CFlowStatParser parser;
+ CFlowStatParserSW parser;
+ int ret = parser.parse(rte_pktmbuf_mtod(m, uint8_t *), m->pkt_len);
- if (m_rcv_all || parser.parse(rte_pktmbuf_mtod(m, uint8_t *), m->pkt_len) == 0) {
+ if (m_rcv_all || (ret == 0)) {
uint32_t ip_id;
- if (m_rcv_all || (parser.get_ip_id(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)) {
uint16_t hw_id;
- if (m_rcv_all || is_flow_stat_payload_id(ip_id)) {
+ if (is_flow_stat_payload_id(ip_id) || ((! is_flow_stat_id(ip_id)) && m_rcv_all)) {
bool good_packet = true;
uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*);
struct flow_stat_payload_header *fsp_head = (struct flow_stat_payload_header *)