diff options
-rwxr-xr-x | src/bp_sim.cpp | 3 | ||||
-rwxr-xr-x | src/bp_sim.h | 34 | ||||
-rw-r--r-- | src/debug.cpp | 55 | ||||
-rw-r--r-- | src/debug.h | 3 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 541 | ||||
-rw-r--r-- | src/main_dpdk.h | 15 | ||||
-rw-r--r-- | src/pkt_gen.h | 3 | ||||
-rw-r--r-- | src/pre_test.cpp | 6 | ||||
-rw-r--r-- | src/pre_test.h | 4 |
9 files changed, 335 insertions, 329 deletions
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index 6cd0aa19..43cfed93 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -54,7 +54,7 @@ uint32_t CGlobalInfo::m_nodes_pool_size = 10*1024; CParserOption CGlobalInfo::m_options; CGlobalMemory CGlobalInfo::m_memory_cfg; CPlatformSocketInfo CGlobalInfo::m_socket; - +CGlobalInfo::queues_mode CGlobalInfo::m_q_mode = CGlobalInfo::Q_MODE_NORMAL; @@ -761,7 +761,6 @@ void CPreviewMode::Dump(FILE *fd){ fprintf(fd," vlan mode : %d\n", get_vlan_mode()); fprintf(fd," client_cfg : %d\n", (int)get_is_client_cfg_enable() ); fprintf(fd," mbuf_cache_disable : %d\n", (int)isMbufCacheDisabled() ); - fprintf(fd," vm mode : %d\n", (int)get_vm_one_queue_enable()?1:0 ); } void CPreviewMode::set_vlan_mode_verify(uint8_t mode) { diff --git a/src/bp_sim.h b/src/bp_sim.h index 8c882c51..435c054b 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -580,12 +580,7 @@ public: } } - - - bool get_vm_one_queue_enable(){ - return (btGetMaskBit32(m_flags1,2,2) ? true:false); - } - + // m_flags1 - bit 2 is free void set_no_keyboard(bool enable){ btSetMaskBit32(m_flags1,5,5,enable?1:0); } @@ -594,10 +589,6 @@ public: return (btGetMaskBit32(m_flags1,5,5) ? true:false); } - void set_vm_one_queue_enable(bool enable){ - btSetMaskBit32(m_flags1,2,2,enable?1:0); - } - /* -e */ void setClientServerFlowFlipAddr(bool enable){ btSetMaskBit32(m_flags1,3,3,enable?1:0); @@ -1250,6 +1241,14 @@ public: class CGlobalInfo { public: + typedef enum { + Q_MODE_NORMAL, + Q_MODE_ONE_QUEUE, // One RX queue and one TX queue + Q_MODE_RSS, + Q_MODE_MANY_DROP_Q // For Mellanox + } queues_mode; + + static void init_pools(uint32_t rx_buffers); /* for simulation */ static void free_pools(); @@ -1336,15 +1335,20 @@ public: static void dump_pool_as_json(Json::Value &json); static std::string dump_pool_as_json_str(void); - - + static inline int get_queues_mode() { + return m_q_mode; + } + static inline void set_queues_mode(queues_mode mode) { + m_q_mode = mode; + } + public: static CRteMemPool m_mem_pool[MAX_SOCKETS_SUPPORTED]; - static uint32_t m_nodes_pool_size; static CParserOption m_options; static CGlobalMemory m_memory_cfg; static CPlatformSocketInfo m_socket; + static queues_mode m_q_mode; }; static inline int get_is_stateless(){ @@ -1358,7 +1362,9 @@ static inline int get_is_rx_check_mode(){ static inline bool get_is_rx_filter_enable(){ uint32_t latency_rate=CGlobalInfo::m_options.m_latency_rate; return ( ( get_is_rx_check_mode() || CGlobalInfo::is_learn_mode() || latency_rate != 0 - || get_is_stateless()) ?true:false ); + || get_is_stateless()) && ((CGlobalInfo::get_queues_mode() != CGlobalInfo::Q_MODE_RSS) + || (CGlobalInfo::get_queues_mode() != CGlobalInfo::Q_MODE_ONE_QUEUE)) + ?true:false ); } static inline uint16_t get_rx_check_hops() { return (CGlobalInfo::m_options.m_rx_check_hops); diff --git a/src/debug.cpp b/src/debug.cpp index 4abd05a0..ccef8499 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2016-2016 Cisco Systems, Inc. + Copyright (c) 2016-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. @@ -63,10 +63,11 @@ const uint8_t udp_pkt[] = { 0xe7 }; -CTrexDebug::CTrexDebug(CPhyEthIF m_ports_arg[12], int max_ports) { +CTrexDebug::CTrexDebug(CPhyEthIF m_ports_arg[12], int max_ports, uint32_t rx_q_num) { m_test = NULL; m_ports = m_ports_arg; m_max_ports = max_ports; + m_rx_q_num = rx_q_num; } int CTrexDebug::rcv_send(int port, int queue_id) { @@ -340,7 +341,7 @@ struct pkt_params test_pkts[] = { // unit test for verifying hw queues rule configuration. Can be run by: // for stateful: --send-debug-pkt 100 -f cap2/dns.yaml -l 1 -// for stateless: --setnd-debug-pkt 100 -i +// for stateless: --send-debug-pkt 100 -i int CTrexDebug::verify_hw_rules(bool recv_all) { rte_mbuf_t *m = NULL; CPhyEthIF * lp; @@ -361,7 +362,7 @@ int CTrexDebug::verify_hw_rules(bool recv_all) { } else { switch (expected_q) { case ZERO: - exp_q = MAIN_DPDK_DATA_Q; + exp_q = MAIN_DPDK_DROP_Q; break; case ONE: exp_q = MAIN_DPDK_RX_Q; @@ -371,19 +372,19 @@ int CTrexDebug::verify_hw_rules(bool recv_all) { exp_q = MAIN_DPDK_RX_Q; pkt_flags |= DPF_TOS_1; } else { - exp_q = MAIN_DPDK_DATA_Q; + exp_q = MAIN_DPDK_DROP_Q; } break; case STF: if ( CGlobalInfo::m_options.is_stateless() ) { - exp_q = MAIN_DPDK_DATA_Q; + exp_q = MAIN_DPDK_DROP_Q; } else { exp_q = MAIN_DPDK_RX_Q; pkt_flags |= DPF_TOS_1; } break; default: - exp_q = MAIN_DPDK_DATA_Q; + exp_q = MAIN_DPDK_DROP_Q; break; } } @@ -394,17 +395,11 @@ int CTrexDebug::verify_hw_rules(bool recv_all) { delay(100); - int pkt_per_q[2]; + int pkt_per_q[16]; 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++) { - int max_q; - if (CGlobalInfo::m_options.preview.get_vm_one_queue_enable()) { - max_q = 0; - } else { - max_q = 1; - } - for(int queue_id = 0; queue_id <= max_q; queue_id++) { + for (int port = 0; port < m_max_ports; port++) { + 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; @@ -440,7 +435,7 @@ int CTrexDebug::test_send(uint pkt_type) { return verify_hw_rules(true); } - if (! (pkt_type >= 1 && pkt_type <= 4) && !(pkt_type >= 61 && pkt_type <= 63)) { + if (! (pkt_type >= 1 && pkt_type <= 5) && !(pkt_type >= 61 && pkt_type <= 63)) { printf("Unsupported packet type %d\n", pkt_type); printf("Supported packet types are: %d(ICMP), %d(UDP), %d(TCP) %d(9k UDP)\n", 1, 2, 3, 4); printf(" IPv6: %d(ICMP), %d(UDP), %d(TCP)\n", 61, 62, 63); @@ -461,7 +456,7 @@ int CTrexDebug::test_send(uint pkt_type) { } else { ip_ver = 4; } - if (pkt_type > D_PKT_TYPE_ARP) { + if (pkt_type > D_PKT_TYPE_RSS_TEST) { printf("Packet type not supported\n"); exit(1); } @@ -472,6 +467,7 @@ int CTrexDebug::test_send(uint pkt_type) { l4_proto = IPPROTO_ICMP; break; case D_PKT_TYPE_UDP: + case D_PKT_TYPE_RSS_TEST: l4_proto = IPPROTO_UDP; break; case D_PKT_TYPE_TCP: @@ -497,13 +493,30 @@ int CTrexDebug::test_send(uint pkt_type) { printf("Sending packet:\n"); utl_DumpBuffer(stdout, rte_pktmbuf_mtod(d, char *), 64, 0); - test_send_pkts(d, 0, 2, 0); - test_send_pkts(d, 0, 1, 1); + if (pkt_type == D_PKT_TYPE_RSS_TEST) { + rte_mbuf_t *mb[50]; + char *p_d = rte_pktmbuf_mtod(d, char *); + IPHeader *ip; + for (uint32_t src = 0; src < 50; src++) { + mb[src] = CGlobalInfo::pktmbuf_alloc_by_port(0, d->pkt_len); + char *p = rte_pktmbuf_append(mb[src], d->pkt_len); + assert(p); + memcpy(p, p_d, d->pkt_len); + ip = (IPHeader *) (p + 14); + ip->updateIpDst(src + 1); + ip->updateIpSrc(src + 5); + test_send_pkts(mb[src], 0, 1, 0); + } + } else { + test_send_pkts(d, 0, 2, 0); + test_send_pkts(d, 0, 1, 1); + } + rte_pktmbuf_free(d); delay(1000); int j=0; - for (j = 0; j < 2; j++) { + for (j = 0; j < m_rx_q_num; j++) { printf(" =========\n"); printf(" rx queue %d \n", j); printf(" =========\n"); diff --git a/src/debug.h b/src/debug.h index d178e3af..5af4eba1 100644 --- a/src/debug.h +++ b/src/debug.h @@ -23,6 +23,7 @@ class CTrexDebug { uint64_t m_test_drop; CPhyEthIF *m_ports; uint32_t m_max_ports; + uint32_t m_rx_q_num; int rcv_send(int port,int queue_id); int rcv_send_all(int queue_id); @@ -36,7 +37,7 @@ class CTrexDebug { int verify_hw_rules(bool recv_all); public: - CTrexDebug(CPhyEthIF *m_ports_arg, int max_ports); + CTrexDebug(CPhyEthIF *m_ports_arg, int max_ports, uint32_t rx_q_num); int test_send(uint pkt_type); }; diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 1a14a07d..12317d3f 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -4,7 +4,7 @@ */ /* - 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. @@ -91,12 +91,11 @@ extern "C" { #define BP_MAX_TX_QUEUE 16 #define BP_MASTER_AND_LATENCY 2 -#define RTE_TEST_RX_DESC_DEFAULT 64 -#define RTE_TEST_RX_LATENCY_DESC_DEFAULT (1*1024) -#define RTE_TEST_RX_DESC_DEFAULT_MLX 8 - -#define RTE_TEST_RX_DESC_VM_DEFAULT 512 -#define RTE_TEST_TX_DESC_VM_DEFAULT 512 +#define RX_DESC_NUM_DROP_Q 64 +#define RX_DESC_NUM_DATA_Q 1024 +#define RX_DESC_NUM_DROP_Q_MLX 8 +#define RX_DESC_NUM_DATA_Q_VM 512 +#define TX_DESC_NUM 512 typedef struct rte_mbuf * (*rte_mbuf_convert_to_one_seg_t)(struct rte_mbuf *m); struct rte_mbuf * rte_mbuf_convert_to_one_seg(struct rte_mbuf *m); @@ -104,16 +103,9 @@ extern "C" int rte_eth_dev_get_port_by_addr(const struct rte_pci_addr *addr, uin void set_driver(); void reorder_dpdk_ports(); -#define RTE_TEST_TX_DESC_DEFAULT 512 -#define RTE_TEST_RX_DESC_DROP 0 - static int max_stat_hw_id_seen = 0; static int max_stat_hw_id_seen_payload = 0; -static inline int get_vm_one_queue_enable(){ - return (CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ?1:0); -} - static inline int get_is_rx_thread_enabled() { return ((CGlobalInfo::m_options.is_rx_enabled() || CGlobalInfo::m_options.is_stateless()) ?1:0); } @@ -132,9 +124,6 @@ static char global_mlx5_so_id_str[50]; static char global_image_postfix[10]; #define TREX_NAME "_t-rex-64" - - - class CTRexExtendedDriverBase { protected: enum { @@ -149,6 +138,8 @@ protected: TREX_DRV_CAP_MAC_ADDR_CHG = 0x4, /* Mellanox driver does not work well with the DPDK port reorder we do */ TREX_DRV_CAP_NO_PORT_REORDER_POSSIBLE = 0x8, + // Does driver support flow control change + TREX_DRV_FLOW_CTRL_CHG = 0x10, } trex_drv_cap; public: @@ -167,11 +158,14 @@ public: bool drop_packets_incase_of_linkdown() { return ((m_cap & TREX_DRV_CAP_DROP_PKTS_IF_LNK_DOWN) != 0); } - virtual bool supports_port_reorder() { + bool supports_port_reorder() { // Since only Mellanox does not support, logic here is reveresed compared to other flags. // Put this only if not supported. return ((m_cap & TREX_DRV_CAP_NO_PORT_REORDER_POSSIBLE) == 0); } + bool flow_ctrl_chg_supp() { + return ((m_cap & TREX_DRV_FLOW_CTRL_CHG) != 0); + } virtual int stop_queue(CPhyEthIF * _if, uint16_t q_num); void get_extended_stats_fixed(CPhyEthIF * _if, CPhyEthIFStats *stats, int fix_i, int fix_o); virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0; @@ -190,12 +184,12 @@ public: virtual int set_rcv_all(CPhyEthIF * _if, bool set_on)=0; virtual TRexPortAttr * create_port_attr(uint8_t port_id) = 0; - /* Mellanox ConnectX-4 can drop only 35MPPS per Rx queue. to workaround this issue we will create multi rx queue and enable RSS. for Queue1 we will disable RSS - return zero for disable patch and rx queues number for enable - */ - - virtual uint16_t enable_rss_drop_workaround(void) { - return 0; + virtual void get_dpdk_drv_params(CTrexDpdkParams &p) { + p.rx_data_q_num = 1; + p.rx_drop_q_num = 1; + p.rx_desc_num_data_q = RX_DESC_NUM_DATA_Q; + p.rx_desc_num_drop_q = RX_DESC_NUM_DROP_Q; + p.tx_desc_num = TX_DESC_NUM; } protected: @@ -208,7 +202,7 @@ class CTRexExtendedDriverBase1G : public CTRexExtendedDriverBase { public: CTRexExtendedDriverBase1G(){ - m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG; + m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_FLOW_CTRL_CHG; } TRexPortAttr * create_port_attr(uint8_t port_id) { @@ -254,6 +248,14 @@ public: virtual int get_min_sample_rate(void){ return ( RX_CHECK_MIX_SAMPLE_RATE_1G); } + virtual void get_dpdk_drv_params(CTrexDpdkParams &p) { + p.rx_data_q_num = 1; + p.rx_drop_q_num = 0; + p.rx_desc_num_data_q = RX_DESC_NUM_DATA_Q_VM; + p.rx_desc_num_drop_q = RX_DESC_NUM_DROP_Q; + p.tx_desc_num = TX_DESC_NUM; + } + virtual void update_configuration(port_cfg_t * cfg); virtual int configure_rx_filter_rules(CPhyEthIF * _if); virtual int stop_queue(CPhyEthIF * _if, uint16_t q_num); @@ -271,8 +273,7 @@ public: class CTRexExtendedDriverVirtio : public CTRexExtendedDriverVirtBase { public: CTRexExtendedDriverVirtio() { - /* we are working in mode that we have 1 queue for rx and one queue for tx*/ - CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); + CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE); m_cap = /*TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG */ 0; } static CTRexExtendedDriverBase * create(){ @@ -284,8 +285,7 @@ public: class CTRexExtendedDriverVmxnet3 : public CTRexExtendedDriverVirtBase { public: CTRexExtendedDriverVmxnet3(){ - /* we are working in mode in which we have 1 queue for rx and one queue for tx*/ - CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); + CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE); m_cap = /*TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG*/0; } @@ -299,9 +299,8 @@ public: class CTRexExtendedDriverI40evf : public CTRexExtendedDriverVirtBase { public: CTRexExtendedDriverI40evf(){ - /* we are working in mode in which we have 1 queue for rx and one queue for tx*/ - CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); - m_cap = /*TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG */0; + CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE); + m_cap = /*TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG */ TREX_DRV_FLOW_CTRL_CHG; } virtual void get_extended_stats(CPhyEthIF * _if, CPhyEthIFStats *stats) { get_extended_stats_fixed(_if, stats, 4, 4); @@ -316,9 +315,8 @@ class CTRexExtendedDriverIxgbevf : public CTRexExtendedDriverI40evf { public: CTRexExtendedDriverIxgbevf(){ - /* we are working in mode in which we have 1 queue for rx and one queue for tx*/ - CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); - m_cap = /*TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG */0; + CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE); + m_cap = /*TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG */ TREX_DRV_FLOW_CTRL_CHG; } virtual void get_extended_stats(CPhyEthIF * _if, CPhyEthIFStats *stats) { get_extended_stats_fixed(_if, stats, 4, 4); @@ -332,7 +330,7 @@ public: class CTRexExtendedDriverBaseE1000 : public CTRexExtendedDriverVirtBase { CTRexExtendedDriverBaseE1000() { // E1000 driver is only relevant in VM in our case - CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); + CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE); m_cap = /*TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG */0; } public: @@ -348,7 +346,7 @@ public: class CTRexExtendedDriverBase10G : public CTRexExtendedDriverBase { public: CTRexExtendedDriverBase10G(){ - m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG; + m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_FLOW_CTRL_CHG; } TRexPortAttr * create_port_attr(uint8_t port_id) { @@ -388,7 +386,8 @@ public: // 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; + m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_CAP_DROP_PKTS_IF_LNK_DOWN + | TREX_DRV_FLOW_CTRL_CHG; } TRexPortAttr * create_port_attr(uint8_t port_id) { @@ -437,7 +436,7 @@ private: class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase { public: CTRexExtendedDriverBaseVIC(){ - m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG; + m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_FLOW_CTRL_CHG; } TRexPortAttr * create_port_attr(uint8_t port_id) { @@ -485,7 +484,8 @@ class CTRexExtendedDriverBaseMlnx5G : public CTRexExtendedDriverBase { public: CTRexExtendedDriverBaseMlnx5G(){ m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG - | TREX_DRV_CAP_NO_PORT_REORDER_POSSIBLE; + | TREX_DRV_CAP_NO_PORT_REORDER_POSSIBLE | TREX_DRV_FLOW_CTRL_CHG; + CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_MANY_DROP_Q); } TRexPortAttr * create_port_attr(uint8_t port_id) { @@ -503,8 +503,18 @@ public: virtual int get_min_sample_rate(void){ return (RX_CHECK_MIX_SAMPLE_RATE); } + virtual void get_dpdk_drv_params(CTrexDpdkParams &p) { + p.rx_data_q_num = 1; + /* Mellanox ConnectX-4 can drop only 35MPPS per Rx queue. + * to workaround this issue we will create multi rx queue and enable RSS. for Queue1 we will disable RSS + * return zero for disable patch and rx queues number for enable. + */ + p.rx_drop_q_num = 4; + p.rx_desc_num_data_q = RX_DESC_NUM_DATA_Q; + p.rx_desc_num_drop_q = RX_DESC_NUM_DROP_Q_MLX; + p.tx_desc_num = TX_DESC_NUM; + } virtual void update_configuration(port_cfg_t * cfg); - virtual int configure_rx_filter_rules(CPhyEthIF * _if); virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats); virtual void clear_extended_stats(CPhyEthIF * _if); @@ -521,10 +531,6 @@ public: virtual CFlowStatParser *get_flow_stat_parser(); virtual int set_rcv_all(CPhyEthIF * _if, bool set_on); - virtual uint16_t enable_rss_drop_workaround(void) { - return (5); - } - private: virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint16_t ip_id, uint8_t l4_proto , int queue); @@ -706,7 +712,7 @@ enum { OPT_HELP, OPT_NO_SCAPY_SERVER, OPT_ACTIVE_FLOW, OPT_RT, - OPT_MLX5_SO + OPT_MLX5_SO }; /* these are the argument types: @@ -1089,7 +1095,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t break; case OPT_VIRT_ONE_TX_RX_QUEUE: - po->preview.set_vm_one_queue_enable(true); + CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE); break; case OPT_PREFIX: @@ -1145,7 +1151,9 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t } if (po->preview.get_is_rx_check_enable() || po->is_latency_enabled() || CGlobalInfo::is_learn_mode() - || (CGlobalInfo::m_options.m_arp_ref_per != 0) || get_vm_one_queue_enable()) { + || (CGlobalInfo::m_options.m_arp_ref_per != 0) + || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE + || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) { po->set_rx_enabled(); } @@ -1295,8 +1303,6 @@ public: m_port_conf.rxmode.hw_strip_crc=1; } - - inline void update_var(void){ get_ex_drv()->update_configuration(this); } @@ -1305,40 +1311,6 @@ public: get_ex_drv()->update_global_config_fdir(this); } - /* enable FDIR */ - inline void update_global_config_fdir_10g(void){ - m_port_conf.fdir_conf.mode=RTE_FDIR_MODE_PERFECT_MAC_VLAN; - m_port_conf.fdir_conf.pballoc=RTE_FDIR_PBALLOC_64K; - m_port_conf.fdir_conf.status=RTE_FDIR_NO_REPORT_STATUS; - /* Offset of flexbytes field in RX packets (in 16-bit word units). */ - /* Note: divide by 2 to convert byte offset to word offset */ - if (get_is_stateless()) { - m_port_conf.fdir_conf.flexbytes_offset = (14+4)/2; - /* Increment offset 4 bytes for the case where we add VLAN */ - if ( CGlobalInfo::m_options.preview.get_vlan_mode() != CPreviewMode::VLAN_MODE_NONE) { - m_port_conf.fdir_conf.flexbytes_offset += (4/2); - } - } else { - if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ) { - m_port_conf.fdir_conf.flexbytes_offset = (14+6)/2; - } else { - m_port_conf.fdir_conf.flexbytes_offset = (14+8)/2; - } - - /* Increment offset 4 bytes for the case where we add VLAN */ - if ( CGlobalInfo::m_options.preview.get_vlan_mode() != CPreviewMode::VLAN_MODE_NONE ) { - m_port_conf.fdir_conf.flexbytes_offset += (4/2); - } - } - m_port_conf.fdir_conf.drop_queue=1; - } - - inline void update_global_config_fdir_40g(void){ - m_port_conf.fdir_conf.mode=RTE_FDIR_MODE_PERFECT; - m_port_conf.fdir_conf.pballoc=RTE_FDIR_PBALLOC_64K; - m_port_conf.fdir_conf.status=RTE_FDIR_NO_REPORT_STATUS; - } - struct rte_eth_conf m_port_conf; struct rte_eth_rxconf m_rx_conf; struct rte_eth_rxconf m_rx_drop_conf; @@ -1531,17 +1503,10 @@ void CPhyEthIF::configure(uint16_t nb_rx_queue, } } - /* - - rx-queue 0 - default- all traffic not goint to queue 1 - will be drop as queue is disable - - - rx-queue 1 - Latency measurement packets will go here - - pci_reg_write(IXGBE_L34T_IMIR(0),(1<<21)); - + rx-queue 0 is the default queue. All traffic not going to queue 1 + will be dropped as queue 0 is disabled + rx-queue 1 - Latency measurement packets and other features that need software processing will go here. */ void CPhyEthIF::configure_rx_duplicate_rules(){ if ( get_is_rx_filter_enable() ){ @@ -1551,7 +1516,8 @@ void CPhyEthIF::configure_rx_duplicate_rules(){ void CPhyEthIF::stop_rx_drop_queue() { // In debug mode, we want to see all packets. Don't want to disable any queue. - if ( get_vm_one_queue_enable() || (CGlobalInfo::m_options.m_debug_pkt_proto != 0)) { + if ( (CGlobalInfo::get_queues_mode() != CGlobalInfo::Q_MODE_NORMAL) + || (CGlobalInfo::m_options.m_debug_pkt_proto != 0)) { return; } if ( CGlobalInfo::m_options.is_rx_enabled() ) { @@ -1560,7 +1526,9 @@ void CPhyEthIF::stop_rx_drop_queue() { exit(1); } } - get_ex_drv()->stop_queue(this, MAIN_DPDK_DATA_Q); + // OK to only stop MAIN_DPDK_DROP_Q here. The only driver in which there are + // more than 1 drop q is Mellanox. stop_queue does not work in this case anyway. + get_ex_drv()->stop_queue(this, MAIN_DPDK_DROP_Q); } @@ -2116,26 +2084,26 @@ class CCoreEthIFStateless : public CCoreEthIF { public: virtual int send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * node_sl, CCorePerPort * lp_port , CVirtualIFPerSideStats * lp_stats, bool is_const); - + /** * fast path version */ virtual int send_node(CGenNode *node); - + /** * slow path version */ virtual int send_node_service_mode(CGenNode *node); - + protected: template <bool SERVICE_MODE> inline int send_node_common(CGenNode *no); - + inline rte_mbuf_t * generate_node_pkt(CGenNodeStateless *node_sl) __attribute__ ((always_inline)); inline int send_node_packet(CGenNodeStateless *node_sl, rte_mbuf_t *m, CCorePerPort *lp_port, CVirtualIFPerSideStats *lp_stats) __attribute__ ((always_inline)); - + rte_mbuf_t * generate_slow_path_node_pkt(CGenNodeStateless *node_sl); }; @@ -2277,7 +2245,7 @@ int CCoreEthIF::send_pkt(CCorePerPort * lp_port, uint16_t len = lp_port->m_len; lp_port->m_table[len]=m; len++; - + /* enough pkts to be sent */ if (unlikely(len == MAX_PKT_BURST)) { send_burst(lp_port, MAX_PKT_BURST,lp_stats); @@ -2382,10 +2350,10 @@ CCoreEthIFStateless::generate_node_pkt(CGenNodeStateless *node_sl) { if (unlikely(node_sl->get_is_slow_path())) { return generate_slow_path_node_pkt(node_sl); } - + /* check that we have mbuf */ rte_mbuf_t *m; - + if ( likely(node_sl->is_cache_mbuf_array()) ) { m = node_sl->cache_mbuf_array_get_cur(); rte_pktmbuf_refcnt_update(m,1); @@ -2409,7 +2377,7 @@ CCoreEthIFStateless::send_node_packet(CGenNodeStateless *node_sl, rte_mbuf_t *m, CCorePerPort *lp_port, CVirtualIFPerSideStats *lp_stats) { - + if (unlikely(node_sl->is_stat_needed())) { if ( unlikely(node_sl->is_cache_mbuf_array()) ) { // No support for latency + cache. If user asks for cache on latency stream, we change cache to 0. @@ -2431,26 +2399,26 @@ int CCoreEthIFStateless::send_node_service_mode(CGenNode *node) { } /** - * this is the common function and it is templated - * for two compiler evaluation for performance - * + * this is the common function and it is templated + * for two compiler evaluation for performance + * */ template <bool SERVICE_MODE> int CCoreEthIFStateless::send_node_common(CGenNode *node) { CGenNodeStateless * node_sl = (CGenNodeStateless *) node; - + pkt_dir_t dir = (pkt_dir_t)node_sl->get_mbuf_cache_dir(); CCorePerPort *lp_port = &m_ports[dir]; CVirtualIFPerSideStats *lp_stats = &m_stats[dir]; - + /* generate packet (can never fail) */ rte_mbuf_t *m = generate_node_pkt(node_sl); - + /* template boolean - this will be removed at compile time */ if (SERVICE_MODE) { TrexStatelessCaptureMngr::getInstance().handle_pkt_tx(m, lp_port->m_port->get_port_id()); } - + /* send */ return send_node_packet(node_sl, m, lp_port, lp_stats); } @@ -2651,10 +2619,10 @@ public: m_tx_queue_id=tx_queue; m_rx_queue_id=rx_queue; } - + virtual int tx(rte_mbuf_t *m) { rte_mbuf_t *tx_pkts[2]; - + tx_pkts[0] = m; uint8_t vlan_mode = CGlobalInfo::m_options.preview.get_vlan_mode(); if ( likely( vlan_mode != CPreviewMode::VLAN_MODE_NONE) ) { @@ -2681,13 +2649,13 @@ public: return (0); } - - + + /* nothing special with HW implementation */ virtual int tx_latency(rte_mbuf_t *m) { return tx(m); } - + virtual rte_mbuf_t * rx(){ rte_mbuf_t * rx_pkts[1]; uint16_t cnt=m_port->rx_burst(m_rx_queue_id,rx_pkts,1); @@ -2698,7 +2666,7 @@ public: } } - + virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, uint16_t nb_pkts){ uint16_t cnt=m_port->rx_burst(m_rx_queue_id,rx_pkts,nb_pkts); @@ -2719,18 +2687,18 @@ public: CNodeRing *ring, CLatencyManager *mgr, CPhyEthIF *p) { - + m_dir = (port_index % 2); m_ring_to_dp = ring; m_mgr = mgr; m_port = p; } - + virtual int tx(rte_mbuf_t *m) { return tx_common(m, false); } - + virtual int tx_latency(rte_mbuf_t *m) { return tx_common(m, true); } @@ -2752,7 +2720,7 @@ public: private: virtual int tx_common(rte_mbuf_t *m, bool fix_timestamp) { - + uint8_t vlan_mode = CGlobalInfo::m_options.preview.get_vlan_mode(); if ( likely( vlan_mode != CPreviewMode::VLAN_MODE_NONE) ) { @@ -2769,7 +2737,7 @@ private: if (!node) { return (-1); } - + node->m_msg_type = CGenNodeMsgBase::LATENCY_PKT; node->m_dir = m_dir; node->m_pkt = m; @@ -2780,14 +2748,14 @@ private: } else { node->m_update_ts = 0; } - + if ( m_ring_to_dp->Enqueue((CGenNode*)node) != 0 ){ return (-1); } - + return (0); } - + CPhyEthIF * m_port; uint8_t m_dir; CNodeRing * m_ring_to_dp; /* ring dp -> latency thread */ @@ -3183,7 +3151,6 @@ public: SHUTDOWN_RPC_REQ } shutdown_rc_e; - CGlobalTRex (){ m_max_ports=4; m_max_cores=1; @@ -3204,7 +3171,7 @@ public: int queues_prob_init(); int ixgbe_start(); int ixgbe_rx_queue_flush(); - void ixgbe_configure_mg(); + void rx_stf_conf(); void rx_sl_configure(); bool is_all_links_are_up(bool dump=false); void pre_test(); @@ -3303,7 +3270,7 @@ public: void dump_links_status(FILE *fd); bool lookup_port_by_mac(const uint8_t *mac, uint8_t &port_id); - + public: port_cfg_t m_port_cfg; uint32_t m_max_ports; /* active number of ports supported options are 2,4,8,10,12 */ @@ -3343,7 +3310,6 @@ private: std::mutex m_cp_lock; TrexMonitor m_monitor; - shutdown_rc_e m_mark_for_shutdown; public: @@ -3353,7 +3319,9 @@ public: // Before starting, send gratuitous ARP on our addresses, and try to resolve dst MAC addresses. void CGlobalTRex::pre_test() { - CPretest pretest(m_max_ports); + CTrexDpdkParams dpdk_p; + get_ex_drv()->get_dpdk_drv_params(dpdk_p); + CPretest pretest(m_max_ports, dpdk_p.rx_data_q_num + dpdk_p.rx_drop_q_num); bool resolve_needed = false; uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0}; bool need_grat_arp[TREX_MAX_PORTS]; @@ -3407,9 +3375,9 @@ void CGlobalTRex::pre_test() { } else { resolve_needed = false; } - + need_grat_arp[port_id] = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip() != 0; - + pretest.add_ip(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip() , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan() , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src); @@ -3521,13 +3489,13 @@ void CGlobalTRex::pre_test() { } } - + /* for stateless only - set port mode */ if (get_is_stateless()) { for (int port_id = 0; port_id < m_max_ports; port_id++) { uint32_t src_ipv4 = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip(); uint32_t dg = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw(); - const uint8_t *dst_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest; + const uint8_t *dst_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest; /* L3 mode */ if (src_ipv4 && dg) { @@ -3544,7 +3512,7 @@ void CGlobalTRex::pre_test() { } } - + } /** @@ -3669,7 +3637,7 @@ int CGlobalTRex::ixgbe_rx_queue_flush(){ // init stateful rx core -void CGlobalTRex::ixgbe_configure_mg(void) { +void CGlobalTRex::rx_stf_conf(void) { int i; CLatencyManagerCfg mg_cfg; mg_cfg.m_max_ports = m_max_ports; @@ -3688,7 +3656,7 @@ void CGlobalTRex::ixgbe_configure_mg(void) { } } - if ( get_vm_one_queue_enable() ) { + if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) { /* vm mode, indirect queues */ for (i=0; i<m_max_ports; i++) { CPhyEthIF * _if = &m_ports[i]; @@ -3724,8 +3692,8 @@ void CGlobalTRex::rx_sl_configure(void) { rx_sl_cfg.m_max_ports = m_max_ports; rx_sl_cfg.m_tx_cores = get_cores_tx(); - - if ( get_vm_one_queue_enable() ) { + + if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) { /* vm mode, indirect queues */ for (i=0; i < m_max_ports; i++) { CPhyEthIF * _if = &m_ports[i]; @@ -3748,92 +3716,18 @@ void CGlobalTRex::rx_sl_configure(void) { int CGlobalTRex::ixgbe_start(void){ int i; - for (i=0; i<m_max_ports; i++) { socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)i); assert(CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); CPhyEthIF * _if=&m_ports[i]; _if->Create((uint8_t)i); - uint16_t rx_rss = get_ex_drv()->enable_rss_drop_workaround(); - - if ( get_vm_one_queue_enable() ) { - m_port_cfg.m_port_conf.rxmode.max_rx_pkt_len = 2000; - /* In VM case, there is one tx q and one rx q */ - _if->configure(1, 1, &m_port_cfg.m_port_conf); - // Only 1 rx queue, so use it for everything - m_rx_core_tx_q_id = 0; - _if->set_rx_queue(0); - // We usually have less memory in VM, so don't use the 9k pool. This means that large packets will - // be received in chain of few mbufs - _if->rx_queue_setup(0, RTE_TEST_RX_DESC_VM_DEFAULT, socket_id, &m_port_cfg.m_rx_conf, - CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); - // 1 TX queue in VM case - _if->tx_queue_setup(0, RTE_TEST_TX_DESC_VM_DEFAULT, socket_id, &m_port_cfg.m_tx_conf); - } else { - // 2 rx queues in normal case. More if rss enabled. - // TX queues: 1 for each core handling the port pair + 1 for latency pkts + 1 for use by RX core - - uint16_t rx_queues; - - if (rx_rss==0) { - rx_queues=2; - }else{ - rx_queues=rx_rss; - } - - _if->configure(rx_queues, m_cores_to_dual_ports + 2, &m_port_cfg.m_port_conf); - m_rx_core_tx_q_id = m_cores_to_dual_ports; - - if ( rx_rss ) { - int j=0; - for (j=0;j<rx_rss; j++) { - if (j==MAIN_DPDK_RX_Q){ - continue; - } - /* drop queue */ - _if->rx_queue_setup(j, - // RTE_TEST_RX_DESC_DEFAULT_MLX, - RTE_TEST_RX_DESC_DEFAULT, - socket_id, - &m_port_cfg.m_rx_conf, - CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); - - - } - }else{ - // setup RX drop queue - _if->rx_queue_setup(MAIN_DPDK_DATA_Q, - RTE_TEST_RX_DESC_DEFAULT, - socket_id, - &m_port_cfg.m_rx_conf, - CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); - // setup RX filter queue - _if->set_rx_queue(MAIN_DPDK_RX_Q); - } - - _if->rx_queue_setup(MAIN_DPDK_RX_Q, - RTE_TEST_RX_LATENCY_DESC_DEFAULT, - socket_id, - &m_port_cfg.m_rx_conf, - CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k); - - for (int qid = 0; qid < m_max_queues_per_port; qid++) { - _if->tx_queue_setup((uint16_t)qid, - RTE_TEST_TX_DESC_DEFAULT , - socket_id, - &m_port_cfg.m_tx_conf); - } - } - - if ( rx_rss ){ - _if->configure_rss_redirect_table(rx_rss,MAIN_DPDK_RX_Q); - } - + _if->conf_queues(); _if->stats_clear(); _if->start(); _if->configure_rx_duplicate_rules(); - if ( ! get_vm_one_queue_enable() && ! CGlobalInfo::m_options.preview.get_is_disable_flow_control_setting() + if ( get_ex_drv()->flow_ctrl_chg_supp() + && ! CGlobalInfo::m_options.preview.get_is_disable_flow_control_setting() && _if->get_port_attr()->is_fc_change_supported()) { _if->disable_flow_control(); } @@ -3866,8 +3760,8 @@ int CGlobalTRex::ixgbe_start(void){ ixgbe_rx_queue_flush(); if (! get_is_stateless()) { - ixgbe_configure_mg(); - } + rx_stf_conf(); + } /* core 0 - control @@ -3880,7 +3774,7 @@ int CGlobalTRex::ixgbe_start(void){ int port_offset=0; uint8_t lat_q_id; - if ( get_vm_one_queue_enable() ) { + if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) { lat_q_id = 0; } else { lat_q_id = get_cores_tx() / get_base_num_cores() + 1; @@ -3981,16 +3875,12 @@ bool CGlobalTRex::Create(){ } /* allocate the memory */ + CTrexDpdkParams dpdk_p; + get_ex_drv()->get_dpdk_drv_params(dpdk_p); - uint32_t rx_mbuf = 0 ; - - if ( get_vm_one_queue_enable() ) { - rx_mbuf = (m_max_ports * RTE_TEST_RX_DESC_VM_DEFAULT); - }else{ - rx_mbuf = (m_max_ports * (RTE_TEST_RX_LATENCY_DESC_DEFAULT+RTE_TEST_RX_DESC_DEFAULT)); - } - - CGlobalInfo::init_pools(rx_mbuf); + CGlobalInfo::init_pools(m_max_ports * + (dpdk_p.rx_data_q_num * dpdk_p.rx_desc_num_data_q + + dpdk_p.rx_drop_q_num * dpdk_p.rx_desc_num_drop_q)); ixgbe_start(); dump_config(stdout); @@ -4010,7 +3900,7 @@ bool CGlobalTRex::Create(){ cfg.m_publisher = &m_zmq_publisher; m_trex_stateless = new TrexStateless(cfg); - + rx_sl_configure(); } @@ -4107,10 +3997,10 @@ int CGlobalTRex::ixgbe_prob_init(void){ m_port_cfg.update_global_config_fdir(); } - if ( get_vm_one_queue_enable() ) { + if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) { /* verify that we have only one thread/core per dual- interface */ if ( CGlobalInfo::m_options.preview.getCores()>1 ) { - printf(" ERROR the number of cores should be 1 when the driver support only one tx queue and one rx queue \n"); + printf("Error: the number of cores should be 1 when the driver support only one tx queue and one rx queue. Please use -c 1 \n"); exit(1); } } @@ -4178,7 +4068,7 @@ bool CGlobalTRex::lookup_port_by_mac(const uint8_t *mac, uint8_t &port_id) { return true; } } - + return false; } @@ -4907,9 +4797,9 @@ int CGlobalTRex::run_in_master() { int CGlobalTRex::run_in_rx_core(void){ CPreviewMode *lp = &CGlobalInfo::m_options.preview; - + rte_thread_setname(pthread_self(), "TRex RX"); - + /* set RT mode if set */ if (lp->get_rt_prio_mode()) { struct sched_param param; @@ -4919,7 +4809,7 @@ int CGlobalTRex::run_in_rx_core(void){ exit(EXIT_FAILURE); } } - + if (get_is_stateless()) { m_sl_rx_running = true; m_rx_sl.start(); @@ -4937,10 +4827,10 @@ int CGlobalTRex::run_in_rx_core(void){ int CGlobalTRex::run_in_core(virtual_thread_id_t virt_core_id){ std::stringstream ss; CPreviewMode *lp = &CGlobalInfo::m_options.preview; - + ss << "Trex DP core " << int(virt_core_id); rte_thread_setname(pthread_self(), ss.str().c_str()); - + /* set RT mode if set */ if (lp->get_rt_prio_mode()) { struct sched_param param; @@ -4951,7 +4841,7 @@ int CGlobalTRex::run_in_core(virtual_thread_id_t virt_core_id){ } } - + if ( lp->getSingleCore() && (virt_core_id==2 ) && (lp-> getCores() ==1) ){ @@ -5154,64 +5044,117 @@ int CGlobalTRex::start_master_statefull() { //////////////////////////////////////////// static CGlobalTRex g_trex; +void CPhyEthIF::conf_queues() { + CTrexDpdkParams dpdk_p; + get_ex_drv()->get_dpdk_drv_params(dpdk_p); + uint16_t num_tx_q = (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) ? + 1 : g_trex.m_max_queues_per_port; + socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)m_port_id); + assert(CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); -void CPhyEthIF::configure_rss_redirect_table(uint16_t numer_of_queues, - uint16_t skip_queue){ + configure(dpdk_p.rx_drop_q_num + dpdk_p.rx_data_q_num, num_tx_q, &g_trex.m_port_cfg.m_port_conf); + for (uint16_t qid = 0; qid < num_tx_q; qid++) { + tx_queue_setup(qid, dpdk_p.tx_desc_num , socket_id, &g_trex.m_port_cfg.m_tx_conf); + } - struct rte_eth_dev_info dev_info; - - rte_eth_dev_info_get(m_port_id,&dev_info); - assert(dev_info.reta_size>0); + switch (dpdk_p.rx_drop_q_num) { + case 0: + if (dpdk_p.rx_data_q_num == 1) { + // 1 rx rcv q. no drop q. VM mode. + // Only 1 rx queue, so use it for everything + g_trex.m_rx_core_tx_q_id = 0; + rx_queue_setup(0, dpdk_p.rx_desc_num_data_q, socket_id, &g_trex.m_port_cfg.m_rx_conf, + CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); + set_rx_queue(0); + } else { + // no drop q. Many rcv queues. RSS mode. + // rss on all rcv queues. Do not skip any q. + configure_rss_redirect_table(dpdk_p.rx_data_q_num, 0xff); + g_trex.m_rx_core_tx_q_id = g_trex.m_cores_to_dual_ports; + for (int queue = 0; queue < dpdk_p.rx_data_q_num; queue++) { + rx_queue_setup(queue, dpdk_p.rx_desc_num_data_q, socket_id, + &g_trex.m_port_cfg.m_rx_conf, CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k); + } + } + break; + case 1: + // 1 drop q. 1 or more rx queues. Normal mode. + // rx core will use largest tx q + g_trex.m_rx_core_tx_q_id = g_trex.m_cores_to_dual_ports; + // configure drop q + rx_queue_setup(MAIN_DPDK_DROP_Q, dpdk_p.rx_desc_num_drop_q, socket_id, &g_trex.m_port_cfg.m_rx_conf, + CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); + set_rx_queue(MAIN_DPDK_RX_Q); + rx_queue_setup(MAIN_DPDK_RX_Q, dpdk_p.rx_desc_num_data_q, socket_id, + &g_trex.m_port_cfg.m_rx_conf, CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k); + break; + default: + // Many drop queues. Mellanox mode. + g_trex.m_rx_core_tx_q_id = g_trex.m_cores_to_dual_ports; + // configure drop queues (all queues but MAIN_DPDK_RX_Q) + for (int j = 0; j < dpdk_p.rx_drop_q_num + 1; j++) { + if (j == MAIN_DPDK_RX_Q) { + continue; + } + rx_queue_setup(j, dpdk_p.rx_desc_num_drop_q, socket_id, &g_trex.m_port_cfg.m_rx_conf, + CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); + } + rx_queue_setup(MAIN_DPDK_RX_Q, dpdk_p.rx_desc_num_data_q, socket_id, + &g_trex.m_port_cfg.m_rx_conf, CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k); + // rss on all drop queues. Skip MAIN_DPDK_RX_Q + configure_rss_redirect_table(dpdk_p.rx_drop_q_num + 1, MAIN_DPDK_RX_Q); + break; + } +} - int reta_conf_size = - std::max(1, dev_info.reta_size / RTE_RETA_GROUP_SIZE); +void CPhyEthIF::configure_rss_redirect_table(uint16_t numer_of_queues, uint16_t skip_queue) { + struct rte_eth_dev_info dev_info; - struct rte_eth_rss_reta_entry64 reta_conf[reta_conf_size]; + rte_eth_dev_info_get(m_port_id,&dev_info); + assert(dev_info.reta_size > 0); + int reta_conf_size = std::max(1, dev_info.reta_size / RTE_RETA_GROUP_SIZE); + struct rte_eth_rss_reta_entry64 reta_conf[reta_conf_size]; rte_eth_dev_rss_reta_query(m_port_id,&reta_conf[0],dev_info.reta_size); - int i,j; - - for (j=0; j<reta_conf_size; j++) { - uint16_t skip=0; - reta_conf[j].mask = ~0ULL; - for (i=0; i<RTE_RETA_GROUP_SIZE; i++) { + for (int j = 0; j < reta_conf_size; j++) { + uint16_t skip = 0; + reta_conf[j].mask = ~0ULL; + for (int i = 0; i < RTE_RETA_GROUP_SIZE; i++) { uint16_t q; while (true) { - q=(i+skip)%numer_of_queues; - if (q!=skip_queue) { + q=(i + skip) % numer_of_queues; + if (q != skip_queue) { break; } - skip+=1; + skip += 1; } - reta_conf[j].reta[i]=q; + reta_conf[j].reta[i] = q; } } - assert (rte_eth_dev_rss_reta_update(m_port_id,&reta_conf[0],dev_info.reta_size) == 0); - - assert (rte_eth_dev_rss_reta_query(m_port_id,&reta_conf[0],dev_info.reta_size) == 0); + rte_eth_dev_rss_reta_update(m_port_id, &reta_conf[0], dev_info.reta_size); + rte_eth_dev_rss_reta_query(m_port_id, &reta_conf[0], dev_info.reta_size); #if 0 /* verification */ - for (j=0; j<reta_conf_size; j++) { - for (i=0; i<RTE_RETA_GROUP_SIZE; i++) { + for (j = 0; j < reta_conf_size; j++) { + for (i = 0; i<RTE_RETA_GROUP_SIZE; i++) { printf(" R %d %d %d \n",j,i,reta_conf[j].reta[i]); } } #endif } - void CPhyEthIF::update_counters() { get_ex_drv()->get_extended_stats(this, &m_stats); CRXCoreIgnoreStat ign_stats; - + if (get_is_stateless()) { g_trex.m_rx_sl.get_ignore_stats(m_port_id, ign_stats, true); } else { g_trex.m_mg.get_ignore_stats(m_port_id, ign_stats, true); } - + m_stats.obytes -= ign_stats.get_tx_bytes(); m_stats.opackets -= ign_stats.get_tx_pkts(); m_ignore_stats.opackets += ign_stats.get_tx_pkts(); @@ -5459,7 +5402,7 @@ int update_global_info_from_platform_file(){ cg->m_mac_info[i].copy_src(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.src) ; cg->m_mac_info[i].copy_dest(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.dest) ; CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.is_set = 1; - + CGlobalInfo::m_options.m_ip_cfg[i].set_def_gw(cg->m_mac_info[i].get_def_gw()); CGlobalInfo::m_options.m_ip_cfg[i].set_ip(cg->m_mac_info[i].get_ip()); CGlobalInfo::m_options.m_ip_cfg[i].set_mask(cg->m_mac_info[i].get_mask()); @@ -5807,7 +5750,10 @@ int main_test(int argc , char * argv[]){ // For unit testing of HW rules and queues configuration. Just send some packets and exit. if (CGlobalInfo::m_options.m_debug_pkt_proto != 0) { - CTrexDebug debug = CTrexDebug(g_trex.m_ports, g_trex.m_max_ports); + CTrexDpdkParams dpdk_p; + get_ex_drv()->get_dpdk_drv_params(dpdk_p); + CTrexDebug debug = CTrexDebug(g_trex.m_ports, g_trex.m_max_ports + , dpdk_p.rx_data_q_num + dpdk_p.rx_drop_q_num); int ret; if (CGlobalInfo::m_options.m_debug_pkt_proto == D_PKT_TYPE_HW_TOGGLE_TEST) { @@ -6039,7 +5985,6 @@ int CTRexExtendedDriverBase1G::wait_for_stable_link(){ } void CTRexExtendedDriverBase1G::update_configuration(port_cfg_t * cfg){ - cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH_1G; cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; cfg->m_tx_conf.tx_thresh.wthresh = 0; @@ -6323,8 +6268,31 @@ void CTRexExtendedDriverBase10G::clear_extended_stats(CPhyEthIF * _if){ _if->pci_reg_read(IXGBE_RXNFGPC); } -void CTRexExtendedDriverBase10G::update_global_config_fdir(port_cfg_t * cfg){ - cfg->update_global_config_fdir_10g(); +void CTRexExtendedDriverBase10G::update_global_config_fdir(port_cfg_t * cfg) { + cfg->m_port_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; + cfg->m_port_conf.fdir_conf.pballoc = RTE_FDIR_PBALLOC_64K; + cfg->m_port_conf.fdir_conf.status = RTE_FDIR_NO_REPORT_STATUS; + /* Offset of flexbytes field in RX packets (in 16-bit word units). */ + /* Note: divide by 2 to convert byte offset to word offset */ + if (get_is_stateless()) { + cfg->m_port_conf.fdir_conf.flexbytes_offset = (14+4)/2; + /* Increment offset 4 bytes for the case where we add VLAN */ + if ( CGlobalInfo::m_options.preview.get_vlan_mode() != CPreviewMode::VLAN_MODE_NONE) { + cfg->m_port_conf.fdir_conf.flexbytes_offset += (4/2); + } + } else { + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ) { + cfg->m_port_conf.fdir_conf.flexbytes_offset = (14+6)/2; + } else { + cfg->m_port_conf.fdir_conf.flexbytes_offset = (14+8)/2; + } + + /* Increment offset 4 bytes for the case where we add VLAN */ + if ( CGlobalInfo::m_options.preview.get_vlan_mode() != CPreviewMode::VLAN_MODE_NONE ) { + cfg->m_port_conf.fdir_conf.flexbytes_offset += (4/2); + } + } + cfg->m_port_conf.fdir_conf.drop_queue = 1; } void CTRexExtendedDriverBase10G::update_configuration(port_cfg_t * cfg){ @@ -6541,7 +6509,9 @@ void CTRexExtendedDriverBase40G::update_configuration(port_cfg_t * cfg){ cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH; cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; cfg->m_tx_conf.tx_thresh.wthresh = TX_WTHRESH; - cfg->update_global_config_fdir_40g(); + cfg->m_port_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT; + cfg->m_port_conf.fdir_conf.pballoc = RTE_FDIR_PBALLOC_64K; + cfg->m_port_conf.fdir_conf.status = RTE_FDIR_NO_REPORT_STATUS; } // What is the type of the rule the respective hw_id counter counts. @@ -6559,7 +6529,7 @@ void CTRexExtendedDriverBase40G::add_del_rules(enum rte_filter_op op, uint8_t po , 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 ( get_vm_one_queue_enable()) + if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) return; int ret=rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR); @@ -6614,7 +6584,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 - //????????? fix + //todo: fix if ( ret != 0 ) { rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_ctrl: err=%d, port=%u\n", ret, port_id); @@ -6675,7 +6645,7 @@ int CTRexExtendedDriverBase40G::add_del_rx_flow_stat_rule(uint8_t port_id, enum } } - add_del_rules(op, port_id, rte_type, 0, IP_ID_RESERVE_BASE + id, next_proto, MAIN_DPDK_DATA_Q, rule_id); + add_del_rules(op, port_id, rte_type, 0, IP_ID_RESERVE_BASE + id, next_proto, MAIN_DPDK_DROP_Q, rule_id); return 0; } @@ -6771,12 +6741,12 @@ int CTRexExtendedDriverBase40G::get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, ui uint32_t hw_id = start - min + i; add_del_rules( RTE_ETH_FILTER_ADD, port_id, fdir_hw_id_rule_params[hw_id].rule_type, 0 - , IP_ID_RESERVE_BASE + i, fdir_hw_id_rule_params[hw_id].l4_proto, MAIN_DPDK_DATA_Q + , IP_ID_RESERVE_BASE + i, fdir_hw_id_rule_params[hw_id].l4_proto, MAIN_DPDK_DROP_Q , FDIR_TEMP_HW_ID); delay(100); rte_eth_fdir_stats_reset(port_id, &counter, hw_id, 1); add_del_rules( RTE_ETH_FILTER_ADD, port_id, fdir_hw_id_rule_params[hw_id].rule_type, 0 - , IP_ID_RESERVE_BASE + i, fdir_hw_id_rule_params[hw_id].l4_proto, MAIN_DPDK_DATA_Q, hw_id); + , IP_ID_RESERVE_BASE + i, fdir_hw_id_rule_params[hw_id].l4_proto, MAIN_DPDK_DROP_Q, hw_id); delay(100); rte_eth_fdir_stats_reset(port_id, &temp_count, FDIR_TEMP_HW_ID, 1); pkts[i] = counter + temp_count - prev_pkts[i]; @@ -6889,7 +6859,9 @@ void CTRexExtendedDriverBaseMlnx5G::update_configuration(port_cfg_t * cfg){ cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH; cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; cfg->m_tx_conf.tx_thresh.wthresh = TX_WTHRESH; - cfg->update_global_config_fdir_40g(); + cfg->m_port_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT; + cfg->m_port_conf.fdir_conf.pballoc = RTE_FDIR_PBALLOC_64K; + cfg->m_port_conf.fdir_conf.status = RTE_FDIR_NO_REPORT_STATUS; /* update mask */ cfg->m_port_conf.fdir_conf.mask.ipv4_mask.proto=0xff; cfg->m_port_conf.fdir_conf.mask.ipv4_mask.tos=0x01; @@ -6898,8 +6870,8 @@ void CTRexExtendedDriverBaseMlnx5G::update_configuration(port_cfg_t * cfg){ /* enable RSS */ cfg->m_port_conf.rxmode.mq_mode =ETH_MQ_RX_RSS; + // This field does not do anything in case of mlx driver. Put it anyway in case it will be supported sometime. cfg->m_port_conf.rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP; - } /* @@ -7142,8 +7114,8 @@ int CTRexExtendedDriverBaseVIC::configure_rx_filter_rules_statefull(CPhyEthIF * // Because of some issue with VIC firmware, IPv6 UDP and ICMP go by default to q 1, so we // need these rules to make them go to q 0. // rule appply to all packets with 0 on tos lsb. - add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 1, 6, 0, MAIN_DPDK_DATA_Q); - add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, 1, 17, 0, MAIN_DPDK_DATA_Q); + add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 1, 6, 0, MAIN_DPDK_DROP_Q); + add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, 1, 17, 0, MAIN_DPDK_DROP_Q); return 0; } @@ -7228,12 +7200,13 @@ CFlowStatParser *CTRexExtendedDriverBaseVIC::get_flow_stat_parser() { ///////////////////////////////////////////////////////////////////////////////////// -void CTRexExtendedDriverVirtBase::update_configuration(port_cfg_t * cfg){ +void CTRexExtendedDriverVirtBase::update_configuration(port_cfg_t * cfg) { cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH_1G; cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; cfg->m_tx_conf.tx_thresh.wthresh = 0; // must have this, otherwise the driver fail at init cfg->m_tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOXSUMS; + cfg->m_port_conf.rxmode.max_rx_pkt_len = 2000; } int CTRexExtendedDriverVirtBase::configure_rx_filter_rules(CPhyEthIF * _if){ @@ -7266,6 +7239,7 @@ void CTRexExtendedDriverBaseE1000::get_extended_stats(CPhyEthIF * _if,CPhyEthIFS } void CTRexExtendedDriverBaseE1000::update_configuration(port_cfg_t * cfg) { + CTRexExtendedDriverVirtBase::update_configuration(cfg); // We configure hardware not to strip CRC. Then DPDK driver removes the CRC. // If configuring "hardware" to remove CRC, due to bug in ESXI e1000 emulation, we got packets with CRC. cfg->m_port_conf.rxmode.hw_strip_crc = 0; @@ -7274,6 +7248,7 @@ void CTRexExtendedDriverBaseE1000::update_configuration(port_cfg_t * cfg) { /////////////////////////////////////////////////////////// VMxnet3 void CTRexExtendedDriverVmxnet3::update_configuration(port_cfg_t * cfg){ + CTRexExtendedDriverVirtBase::update_configuration(cfg); cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH_1G; cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; cfg->m_tx_conf.tx_thresh.wthresh = 0; @@ -7283,6 +7258,7 @@ void CTRexExtendedDriverVmxnet3::update_configuration(port_cfg_t * cfg){ ///////////////////////////////////////////////////////// VF void CTRexExtendedDriverI40evf::update_configuration(port_cfg_t * cfg) { + CTRexExtendedDriverVirtBase::update_configuration(cfg); cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH; cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; cfg->m_tx_conf.tx_thresh.wthresh = TX_WTHRESH; @@ -7576,4 +7552,3 @@ DpdkTRexPortAttrMlnx5G::set_link_up(bool up) { void TrexDpdkPlatformApi::mark_for_shutdown() const { g_trex.mark_for_shutdown(CGlobalTRex::SHUTDOWN_RPC_REQ); } - diff --git a/src/main_dpdk.h b/src/main_dpdk.h index 25b19471..e444ad2b 100644 --- a/src/main_dpdk.h +++ b/src/main_dpdk.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. @@ -22,10 +22,19 @@ #include "bp_sim.h" enum { - MAIN_DPDK_DATA_Q = 0, + MAIN_DPDK_DROP_Q = 0, MAIN_DPDK_RX_Q = 1, }; +class CTrexDpdkParams { + public: + uint16_t rx_data_q_num; + uint16_t rx_drop_q_num; + uint16_t rx_desc_num_data_q; + uint16_t rx_desc_num_drop_q; + uint16_t tx_desc_num; +}; + // These are statistics for packets we send, and do not expect to get back (Like ARP) // We reduce them from general statistics we report (and report them separately, so we can keep the assumption // that tx_pkts == rx_pkts and tx_bytes==rx_bytes @@ -83,7 +92,7 @@ class CPhyEthIF { void set_rx_queue(uint8_t rx_queue){ m_rx_queue=rx_queue; } - + void conf_queues(); void configure(uint16_t nb_rx_queue, uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf); diff --git a/src/pkt_gen.h b/src/pkt_gen.h index 8dcba624..6a6416d1 100644 --- a/src/pkt_gen.h +++ b/src/pkt_gen.h @@ -27,7 +27,8 @@ enum { D_PKT_TYPE_UDP = 2, D_PKT_TYPE_TCP = 3, D_PKT_TYPE_ARP = 4, - D_PKT_TYPE_9k_UDP = 5, + D_PKT_TYPE_RSS_TEST = 5, + D_PKT_TYPE_9k_UDP = 6, D_PKT_TYPE_IPV6 = 60, D_PKT_TYPE_HW_VERIFY = 100, D_PKT_TYPE_HW_VERIFY_RCV_ALL = 101, diff --git a/src/pre_test.cpp b/src/pre_test.cpp index 7127645d..a72b7e8e 100644 --- a/src/pre_test.cpp +++ b/src/pre_test.cpp @@ -340,9 +340,9 @@ bool CPretest::resolve_all() { // If we are on loopback, We might get requests on port even after it is in RESOLVE_DONE state all_resolved = false; } - handle_rx(port, MAIN_DPDK_DATA_Q); - if (! CGlobalInfo::m_options.preview.get_vm_one_queue_enable()) - handle_rx(port, MAIN_DPDK_RX_Q); + for (uint16_t queue = 0; queue < m_num_q; queue++) { + handle_rx(port, queue); + } } if (all_resolved) { break; diff --git a/src/pre_test.h b/src/pre_test.h index 14b444cf..88616440 100644 --- a/src/pre_test.h +++ b/src/pre_test.h @@ -83,11 +83,12 @@ class CPretestOnePortInfo { class CPretest { public: - CPretest(uint16_t max_ports) { + CPretest(uint16_t max_ports, uint16_t queues_per_port) { m_max_ports = max_ports; for (int i =0; i < max_ports; i++) { m_port_info[i].set_port_id(i); } + m_num_q = queues_per_port; } void add_ip(uint16_t port, uint32_t ip, uint16_t vlan, MacAddress src_mac); void add_ip(uint16_t port, uint32_t ip, MacAddress src_mac); @@ -115,6 +116,7 @@ class CPretest { private: CPretestOnePortInfo m_port_info[TREX_MAX_PORTS]; uint16_t m_max_ports; + uint16_t m_num_q; }; #endif |