Software mode for latency and flow stat statistics
authorIdo Barnea <[email protected]>
Mon, 13 Mar 2017 20:28:09 +0000 (22:28 +0200)
committerIdo Barnea <[email protected]>
Tue, 14 Mar 2017 09:48:46 +0000 (11:48 +0200)
Also supporting QinQ for flow stat

Signed-off-by: Ido Barnea <[email protected]>
src/common/Network/Packet/EthernetHeader.h
src/common/Network/Packet/EthernetHeader.inl
src/flow_stat.cpp
src/flow_stat.h
src/flow_stat_parser.cpp
src/flow_stat_parser.h
src/main_dpdk.cpp
src/main_dpdk.h
src/stateless/rx/trex_stateless_rx_port_mngr.cpp

index 002d6c2..cf93e85 100755 (executable)
@@ -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"
index 0d6e32c..4091b94 100755 (executable)
@@ -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));
+}
index 92cbca6..fcbd830 100644 (file)
@@ -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);
index e0c995a..25bf421 100644 (file)
@@ -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];
index 4a6722e..417299e 100644 (file)
@@ -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;
index 51816e1..682bc09 100644 (file)
@@ -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:
index 1f9dadc..89c6b65 100644 (file)
@@ -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);
     }
index e444ad2..3b5d283 100644 (file)
@@ -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();
index ab7719f..ca06619 100644 (file)
@@ -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 *)