From af25eb9b8463225827fd38223f36a9c361f2d254 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Mon, 13 Mar 2017 22:28:09 +0200 Subject: Software mode for latency and flow stat statistics Also supporting QinQ for flow stat Signed-off-by: Ido Barnea --- src/common/Network/Packet/EthernetHeader.h | 27 ++--- src/common/Network/Packet/EthernetHeader.inl | 10 ++ src/flow_stat.cpp | 88 +++++++++------- src/flow_stat.h | 3 +- src/flow_stat_parser.cpp | 123 +++++++++++++++++++++++ src/flow_stat_parser.h | 11 +- src/main_dpdk.cpp | 83 +++++++++++---- src/main_dpdk.h | 1 + src/stateless/rx/trex_stateless_rx_port_mngr.cpp | 16 ++- 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 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 : 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 : 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 : 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 *) -- cgit 1.2.3-korg