summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bp_gtest.cpp2
-rwxr-xr-xsrc/bp_sim.cpp49
-rwxr-xr-xsrc/bp_sim.h121
-rw-r--r--src/common/Network/Packet/Arp.h43
-rwxr-xr-xsrc/common/Network/Packet/EthernetHeader.h6
-rwxr-xr-xsrc/common/Network/Packet/IPHeader.h9
-rw-r--r--src/common/Network/Packet/IcmpHeader.h5
-rwxr-xr-xsrc/common/Network/Packet/MacAddress.h133
-rwxr-xr-xsrc/common/basic_utils.cpp44
-rwxr-xr-xsrc/common/basic_utils.h6
-rwxr-xr-xsrc/common/captureFile.h5
-rwxr-xr-xsrc/common/erf.cpp6
-rwxr-xr-xsrc/common/erf.h7
-rwxr-xr-xsrc/common/pcap.cpp7
-rwxr-xr-xsrc/common/pcap.h12
-rw-r--r--src/debug.cpp17
-rw-r--r--src/dpdk/drivers/net/enic/base/vnic_dev.c38
-rw-r--r--src/dpdk/drivers/net/enic/base/vnic_dev.h3
-rw-r--r--src/dpdk/drivers/net/enic/base/vnic_devcmd.h346
-rw-r--r--src/dpdk/drivers/net/enic/enic.h14
-rw-r--r--src/dpdk/drivers/net/enic/enic_clsf.c352
-rw-r--r--src/dpdk/drivers/net/enic/enic_ethdev.c9
-rw-r--r--src/dpdk/drivers/net/enic/enic_main.c6
-rw-r--r--src/dpdk/drivers/net/enic/enic_res.c5
-rw-r--r--src/dpdk/drivers/net/ixgbe/ixgbe_ethdev.c6
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5.c20
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5.h31
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5_autoconf.h8
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5_fdir.c98
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5_rxq.c4
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5_rxtx.c4
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5_rxtx.h4
-rw-r--r--src/dpdk/drivers/net/mlx5/mlx5_stats.c321
-rw-r--r--src/flow_stat.cpp25
-rw-r--r--src/flow_stat_parser.cpp4
-rw-r--r--src/gtest/client_cfg_test.cpp186
-rw-r--r--src/gtest/trex_stateless_gtest.cpp4
-rw-r--r--src/internal_api/trex_platform_api.h11
-rw-r--r--src/main_dpdk.cpp1250
-rw-r--r--src/main_dpdk.h3
-rwxr-xr-xsrc/pal/linux_dpdk/x86_64-default-linuxapp-gcc/include/rte_config.h8
-rw-r--r--src/pkt_gen.cpp18
-rw-r--r--src/pkt_gen.h3
-rw-r--r--src/pre_test.cpp641
-rw-r--r--src/pre_test.h79
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp305
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp33
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h19
-rw-r--r--src/rpc-server/trex_rpc_cmd.cpp38
-rw-r--r--src/rpc-server/trex_rpc_cmd_api.h20
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp6
-rw-r--r--src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp9
-rw-r--r--src/rpc-server/trex_rpc_jsonrpc_v2_parser.h9
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.cpp24
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.h1
-rwxr-xr-xsrc/rx_check.cpp4
-rw-r--r--src/stateful_rx_core.cpp172
-rw-r--r--src/stateful_rx_core.h38
-rw-r--r--src/stateless/cp/trex_exception.h5
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp179
-rw-r--r--src/stateless/cp/trex_stateless_port.h84
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp13
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.h2
-rw-r--r--src/stateless/dp/trex_stream_node.h6
-rw-r--r--src/stateless/messaging/trex_stateless_messaging.cpp85
-rw-r--r--src/stateless/messaging/trex_stateless_messaging.h220
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.cpp434
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.h117
-rw-r--r--src/stateless/rx/trex_stateless_rx_defs.h62
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.cpp889
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.h517
-rw-r--r--src/trex_client_config.cpp265
-rw-r--r--src/trex_client_config.h304
-rw-r--r--src/trex_port_attr.cpp152
-rwxr-xr-xsrc/trex_port_attr.h150
-rwxr-xr-xsrc/tuple_gen.cpp94
-rwxr-xr-xsrc/tuple_gen.h18
-rw-r--r--src/utl_ip.cpp139
-rw-r--r--src/utl_ip.h269
-rwxr-xr-xsrc/utl_term_io.cpp7
-rwxr-xr-xsrc/utl_yaml.cpp75
-rwxr-xr-xsrc/utl_yaml.h1
82 files changed, 7210 insertions, 1528 deletions
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index ca514c88..11bd6235 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -196,7 +196,7 @@ public:
ports[i]=lpg->GenerateOneSourcePort();
}
}
-
+ CGlobalInfo::m_options.m_run_mode = CParserOption::RUN_MODE_BATCH;
lpt->start_generate_stateful(buf,CGlobalInfo::m_options.preview);
lpt->m_node_gen.DumpHist(stdout);
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index 62e8d822..80297c32 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -160,8 +160,8 @@ uint64_t CPlatformSocketInfoNoConfig::get_cores_mask(){
int i;
int offset=0;
/* master */
- uint32_t res=1;
- uint32_t mask=(1<<(offset+1));
+ uint64_t res=1;
+ uint64_t mask=(1LL<<(offset+1));
for (i=0; i<(cores_number-1); i++) {
res |= mask ;
mask = mask <<1;
@@ -238,6 +238,13 @@ bool CPlatformSocketInfoConfig::init(){
}
}
+ if (m_threads_per_dual_if > m_max_threads_per_dual_if) {
+ printf("ERROR: Maximum threads in platform section of config file is %d, unable to run with -c %d.\n",
+ m_max_threads_per_dual_if, m_threads_per_dual_if);
+ printf("Please increase the pool in config or use lower -c.\n");
+ exit(1);
+ }
+
int j;
for (j=0; j<m_threads_per_dual_if; j++) {
@@ -381,14 +388,14 @@ uint64_t CPlatformSocketInfoConfig::get_cores_mask(){
printf(" ERROR phy threads can't be higher than 64 \n");
exit(1);
}
- mask |=(1<<i);
+ mask |=(1LL<<i);
}
}
- mask |=(1<<m_platform->m_master_thread);
+ mask |=(1LL<<m_platform->m_master_thread);
assert(m_platform->m_master_thread<64);
if (m_rx_is_enabled) {
- mask |=(1<<m_platform->m_rx_thread);
+ mask |=(1LL<<m_platform->m_rx_thread);
assert(m_platform->m_rx_thread<64);
}
return (mask);
@@ -1668,7 +1675,8 @@ void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
IPv6Header * ipv6=(IPv6Header *)(mp1 + 14);
uint8_t save_header= ipv6->getNextHdr();
ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE);
- ipv6->setHopLimit(TTL_RESERVE_DUPLICATE);
+ ipv6->setHopLimit(TTL_RESERVE_DUPLICATE);
+ ipv6->setTrafficClass(ipv6->getTrafficClass()|TOS_TTL_RESERVE_DUPLICATE);
ipv6->setPayloadLen( ipv6->getPayloadLen() +
sizeof(CRx_check_header));
rxhdr->m_option_type = save_header;
@@ -1678,6 +1686,8 @@ void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
ipv4->setHeaderLength(current_opt_len+opt_len);
ipv4->setTotalLength(ipv4->getTotalLength()+opt_len);
ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE);
+ ipv4->setTOS(ipv4->getTOS()|TOS_TTL_RESERVE_DUPLICATE);
+
rxhdr->m_option_type = RX_CHECK_V4_OPT_TYPE;
rxhdr->m_option_len = RX_CHECK_V4_OPT_LEN;
}
@@ -2148,6 +2158,7 @@ void CCapFileFlowInfo::update_info(){
lp = GetPacket(1);
assert(lp);
lp->m_pkt_indication.setTTL(TTL_RESERVE_DUPLICATE);
+ lp->m_pkt_indication.setTOSReserve();
}
}
@@ -2234,6 +2245,9 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st
pkt_indication.setTTL(TTL_RESERVE_DUPLICATE-4);
}
+ pkt_indication.clearTOSReserve();
+
+
// Validation for first packet in flow
if (is_fif) {
lpflow->flow_id = m_total_flows;
@@ -4419,7 +4433,7 @@ void CFlowGenListPerThread::stop_stateless_simulation_file(){
}
void CFlowGenListPerThread::start_stateless_daemon_simulation(){
-
+ CGlobalInfo::m_options.m_run_mode = CParserOption::RUN_MODE_INTERACTIVE;
m_cur_time_sec = 0;
/* if no pending CP messages - the core will simply be stuck forever */
@@ -4438,6 +4452,7 @@ bool CFlowGenListPerThread::set_stateless_next_node( CGenNodeStateless * cur_nod
void CFlowGenListPerThread::start_stateless_daemon(CPreviewMode &preview){
+ CGlobalInfo::m_options.m_run_mode = CParserOption::RUN_MODE_INTERACTIVE;
m_cur_time_sec = 0;
/* set per thread global info, for performance */
m_preview_mode = preview;
@@ -4562,6 +4577,22 @@ int CFlowGenList::load_client_config_file(std::string file_name) {
return (0);
}
+void CFlowGenList::set_client_config_tuple_gen_info(CTupleGenYamlInfo * tg) {
+ m_client_config_info.set_tuple_gen_info(tg);
+}
+
+void CFlowGenList::get_client_cfg_ip_list(std::vector<ClientCfgCompactEntry *> &ret) {
+ m_client_config_info.get_entry_list(ret);
+}
+
+void CFlowGenList::set_client_config_resolved_macs(CManyIPInfo &pretest_result) {
+ m_client_config_info.set_resolved_macs(pretest_result);
+}
+
+void CFlowGenList::dump_client_config(FILE *fd) {
+ m_client_config_info.dump(fd);
+}
+
int CFlowGenList::load_from_yaml(std::string file_name,
uint32_t num_threads){
uint8_t idx;
@@ -5217,11 +5248,11 @@ void CErfIF::add_vlan(uint16_t vlan_id) {
m_raw->pkt_len += 4;
}
-void CErfIF::apply_client_config(const ClientCfg *cfg, pkt_dir_t dir) {
+void CErfIF::apply_client_config(const ClientCfgBase *cfg, pkt_dir_t dir) {
assert(cfg);
uint8_t *p = (uint8_t *)m_raw->raw;
- const ClientCfgDir &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
+ const ClientCfgDirBase &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
/* dst mac */
if (cfg_dir.has_dst_mac_addr()) {
diff --git a/src/bp_sim.h b/src/bp_sim.h
index cd0f6a13..5d7df59d 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -44,6 +44,7 @@ limitations under the License.
#include <common/bitMan.h>
#include <yaml-cpp/yaml.h>
#include "trex_defs.h"
+#include "utl_ip.h"
#include "os_time.h"
#include "pal_utl.h"
#include "rx_check_header.h"
@@ -72,14 +73,9 @@ class CGenNodePCAP;
#define FORCE_NO_INLINE __attribute__ ((noinline))
#define FORCE_INLINE __attribute__((always_inline))
-/* IP address, last 32-bits of IPv6 remaps IPv4 */
-typedef struct {
- uint16_t v6[6]; /* First 96-bits of IPv6 */
- uint32_t v4; /* Last 32-bits IPv6 overloads v4 */
-} ipaddr_t;
-
/* reserve both 0xFF and 0xFE , router will -1 FF */
#define TTL_RESERVE_DUPLICATE 0xff
+#define TOS_TTL_RESERVE_DUPLICATE 0x1
/*
* Length of string needed to hold the largest port (16-bit) address
@@ -174,38 +170,6 @@ typedef enum { VM_REPLACE_IP_OFFSET =0x12, /* fix ip at offset */
/* work only on x86 littel */
#define MY_B(b) (((int)b)&0xff)
-// Routine to create IPv4 address string
-inline int ip_to_str(uint32_t ip,char * str){
- uint32_t ipv4 = PKT_HTONL(ip);
- inet_ntop(AF_INET, (const char *)&ipv4, str, INET_ADDRSTRLEN);
- return(strlen(str));
-}
-
-inline std::string ip_to_str(uint32_t ip) {
- char tmp[INET_ADDRSTRLEN];
- ip_to_str(ip, tmp);
- return tmp;
-}
-
-// Routine to create IPv6 address string
-inline int ipv6_to_str(ipaddr_t *ip,char * str){
- int idx=0;
- uint16_t ipv6[8];
- for (uint8_t i=0; i<6; i++) {
- ipv6[i] = PKT_HTONS(ip->v6[i]);
- }
- uint32_t ipv4 = PKT_HTONL(ip->v4);
- ipv6[6] = ipv4 & 0xffff;
- ipv6[7] = ipv4 >> 16;
-
- str[idx++] = '[';
- inet_ntop(AF_INET6, (const char *)&ipv6, &str[1], INET6_ADDRSTRLEN);
- idx = strlen(str);
- str[idx++] = ']';
- str[idx] = 0;
- return(idx);
-}
-
class CFlowPktInfo ;
class CMiniVM {
@@ -679,7 +643,6 @@ public:
CMacAddrCfg (){
memset(u.m_data,0,sizeof(u.m_data));
u.m_mac.dest[3]=1;
- u.m_mac.src[3]=1;
}
union {
mac_align_t m_mac;
@@ -693,21 +656,19 @@ class CPerPortIPCfg {
uint32_t get_mask() {return m_mask;}
uint32_t get_def_gw() {return m_def_gw;}
uint32_t get_vlan() {return m_vlan;}
- bool grat_arp_needed() {return m_grat_arp_needed;}
void set_ip(uint32_t val) {m_ip = val;}
void set_mask(uint32_t val) {m_mask = val;}
void set_def_gw(uint32_t val) {m_def_gw = val;}
void set_vlan(uint16_t val) {m_vlan = val;}
- void set_grat_arp_needed(bool val) {m_grat_arp_needed = val;}
private:
uint32_t m_def_gw;
uint32_t m_ip;
uint32_t m_mask;
uint16_t m_vlan;
- bool m_grat_arp_needed;
};
+
class CParserOption {
public:
@@ -824,6 +785,11 @@ public:
return ( (m_expected_portd>>1) * preview.getCores());
}
bool is_stateless(){
+ if (m_run_mode == RUN_MODE_INVALID) {
+ fprintf(stderr, "Internal bug: Calling is stateless before initializing run mode\n");
+ fprintf(stderr, "Try to put -i or -f <file> option as first in the option list\n");
+ exit(-1);
+ }
return (m_run_mode == RUN_MODE_INTERACTIVE ?true:false);
}
bool is_latency_enabled() {
@@ -1199,12 +1165,13 @@ public:
/* for simulation */
static void free_pools();
-
static inline rte_mbuf_t * pktmbuf_alloc_small(socket_id_t socket){
return ( m_mem_pool[socket].pktmbuf_alloc_small() );
}
-
+ static inline rte_mbuf_t * pktmbuf_alloc_small_by_port(uint8_t port_id) {
+ return ( m_mem_pool[m_socket.port_to_socket(port_id)].pktmbuf_alloc_small() );
+ }
/**
* try to allocate small buffers too
@@ -1222,6 +1189,13 @@ public:
return (m_mem_pool[socket].pktmbuf_alloc(size));
}
+ static inline rte_mbuf_t * pktmbuf_alloc_by_port(uint8_t port_id, uint16_t size){
+ socket_id_t socket = m_socket.port_to_socket(port_id);
+ if (size<FIRST_PKT_SIZE) {
+ return ( pktmbuf_alloc_small(socket));
+ }
+ return (m_mem_pool[socket].pktmbuf_alloc(size));
+ }
static inline bool is_learn_verify_mode(){
return ( (m_options.m_learn_mode != CParserOption::LEARN_MODE_DISABLED) && m_options.preview.get_learn_and_verify_mode_enable());
@@ -1550,7 +1524,7 @@ public:
uint32_t m_nat_tcp_seq_diff_server; // And some do seq num randomization for server->client also
uint16_t m_nat_external_port; // NAT client port
uint16_t m_nat_pad[1];
- const ClientCfg *m_client_cfg;
+ const ClientCfgBase *m_client_cfg;
uint32_t m_src_idx;
uint32_t m_dest_idx;
uint32_t m_end_of_cache_line[6];
@@ -1875,7 +1849,7 @@ typedef std::priority_queue<CGenNode *, std::vector<CGenNode *>,CGenNodeCompare>
class CErfIF : public CVirtualIF {
-
+ friend class basic_client_cfg_test1_Test;
public:
CErfIF(){
m_writer=NULL;
@@ -1914,7 +1888,7 @@ public:
protected:
void add_vlan(uint16_t vlan_id);
- void apply_client_config(const ClientCfg *cfg, pkt_dir_t dir);
+ void apply_client_config(const ClientCfgBase *cfg, pkt_dir_t dir);
virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir);
CFileWriterBase * m_writer;
@@ -2682,6 +2656,26 @@ public:
return (0);
}
}
+
+
+ void setTOSReserve(){
+ BP_ASSERT(l3.m_ipv4);
+ if (is_ipv6()) {
+ l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass() | TOS_TTL_RESERVE_DUPLICATE );
+ }else{
+ l3.m_ipv4->setTOS(l3.m_ipv4->getTOS()| TOS_TTL_RESERVE_DUPLICATE );
+ }
+ }
+
+ void clearTOSReserve(){
+ BP_ASSERT(l3.m_ipv4);
+ if (is_ipv6()) {
+ l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass()& (~TOS_TTL_RESERVE_DUPLICATE) );
+ }else{
+ l3.m_ipv4->setTOS(l3.m_ipv4->getTOS() & (~TOS_TTL_RESERVE_DUPLICATE) );
+ }
+ }
+
uint8_t getTTL(){
BP_ASSERT(l3.m_ipv4);
if (is_ipv6()) {
@@ -3054,6 +3048,8 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
printf(" %.3f : DP : learn packet !\n",now_sec());
#endif
ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE);
+ ipv4->setTOS(ipv4->getTOS()|TOS_TTL_RESERVE_DUPLICATE);
+
/* first ipv4 option add the info in case of learn packet, usualy only the first packet */
if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION)) {
@@ -3995,6 +3991,10 @@ public:
int load_from_yaml(std::string csv_file,uint32_t num_threads);
int load_client_config_file(std::string file_name);
+ void set_client_config_tuple_gen_info(CTupleGenYamlInfo * tg);
+ void get_client_cfg_ip_list(std::vector<ClientCfgCompactEntry *> &ret);
+ void set_client_config_resolved_macs(CManyIPInfo &pretest_result);
+ void dump_client_config(FILE *fd);
public:
void Dump(FILE *fd);
@@ -4240,6 +4240,33 @@ inline pkt_dir_t CGenNode::cur_interface_dir(){
}
}
+/* Itay: move this to a better place (common for RX STL and RX STF) */
+class CRXCoreIgnoreStat {
+ friend class CCPortLatency;
+ friend class CLatencyManager;
+ friend class RXGratARP;
+ public:
+ inline CRXCoreIgnoreStat operator- (const CRXCoreIgnoreStat &t_in) const {
+ CRXCoreIgnoreStat t_out;
+ t_out.m_tx_arp = this->m_tx_arp - t_in.m_tx_arp;
+ t_out.m_tx_ipv6_n_solic = this->m_tx_ipv6_n_solic - t_in.m_tx_ipv6_n_solic;
+ t_out.m_tot_bytes = this->m_tot_bytes - t_in.m_tot_bytes;
+ return t_out;
+ }
+ uint64_t get_tx_bytes() {return m_tot_bytes;}
+ uint64_t get_tx_pkts() {return m_tx_arp + m_tx_ipv6_n_solic;}
+ uint64_t get_tx_arp() {return m_tx_arp;}
+ uint64_t get_tx_n_solic() {return m_tx_ipv6_n_solic;}
+ void clear() {
+ m_tx_arp = 0;
+ m_tx_ipv6_n_solic = 0;
+ m_tot_bytes = 0;
+ }
+ private:
+ uint64_t m_tx_arp;
+ uint64_t m_tx_ipv6_n_solic;
+ uint64_t m_tot_bytes;
+};
#endif
diff --git a/src/common/Network/Packet/Arp.h b/src/common/Network/Packet/Arp.h
index a16605bd..e23ff139 100644
--- a/src/common/Network/Packet/Arp.h
+++ b/src/common/Network/Packet/Arp.h
@@ -20,8 +20,7 @@ limitations under the License.
#pragma pack(push, 1)
class ArpHdr {
public:
- enum arp_hdr_enum_e {
- ARP_HDR_HRD_ETHER = 1,
+ enum arp_hdr_op_e {
ARP_HDR_OP_REQUEST = 1, /* request to resolve address */
ARP_HDR_OP_REPLY = 2, /* response to previous request */
ARP_HDR_OP_REVREQUEST = 3, /* request proto addr given hardware */
@@ -30,6 +29,46 @@ class ArpHdr {
ARP_HDR_OP_INVREPLY = 6, /* response identifying peer */
};
+ enum arp_hdr_hrd_e {
+ ARP_HDR_HRD_ETHER = 1,
+ };
+
+ enum arp_hdr_proto_e {
+ ARP_HDR_PROTO_IPV4 = 0x800,
+ };
+
+ void setOp(uint16_t op) {
+ m_arp_op = PKT_HTONS(op);
+ }
+
+ uint16_t getOp() const {
+ return PKT_NTOHS(m_arp_op);
+ }
+
+ uint16_t getHrdType() const {
+ return PKT_NTOHS(m_arp_hrd);
+ }
+
+ uint16_t getProtocolType() const {
+ return PKT_NTOHS(m_arp_pro);
+ }
+
+ uint32_t getSip() const {
+ return PKT_NTOHL(m_arp_sip);
+ }
+
+ void setSip(uint32_t sip) {
+ m_arp_sip = PKT_HTONL(sip);
+ }
+
+ uint32_t getTip() const {
+ return PKT_NTOHL(m_arp_tip);
+ }
+
+ void setTip(uint32_t tip) {
+ m_arp_tip = PKT_HTONL(tip);
+ }
+
public:
uint16_t m_arp_hrd; /* format of hardware address */
uint16_t m_arp_pro; /* format of protocol address */
diff --git a/src/common/Network/Packet/EthernetHeader.h b/src/common/Network/Packet/EthernetHeader.h
index c9dcdbe2..002d6c25 100755
--- a/src/common/Network/Packet/EthernetHeader.h
+++ b/src/common/Network/Packet/EthernetHeader.h
@@ -62,8 +62,10 @@ public:
inline EthernetHeader(uint8_t* packet);
inline uint8_t* getPointer (){return (uint8_t*)this;}
- static inline uint32_t getSize (){return (uint32_t)sizeof(EthernetHeader);}
-
+ inline uint32_t getSize () {
+ return ( (getNextProtocol() == Protocol::VLAN) ? 18 : 14);
+ }
+
// Get dest MAC pointer
MacAddress *getDestMacP() { return &myDestination; }
diff --git a/src/common/Network/Packet/IPHeader.h b/src/common/Network/Packet/IPHeader.h
index da9ba52c..0bf97fbb 100755
--- a/src/common/Network/Packet/IPHeader.h
+++ b/src/common/Network/Packet/IPHeader.h
@@ -91,6 +91,15 @@ public:
*/
inline void setHeaderLength (uint8_t);
+ inline uint16_t getFirstWord(){
+ return PKT_NTOHS(*((uint16_t *)&myVer_HeaderLength));
+ }
+
+ inline void setFirstWord (uint16_t word){
+ *((uint16_t *)&myVer_HeaderLength) = PKT_NTOHS(word);
+ }
+
+
inline uint8_t getTOS ();
inline void setTOS (uint8_t);
diff --git a/src/common/Network/Packet/IcmpHeader.h b/src/common/Network/Packet/IcmpHeader.h
index 99d89329..4bc102e3 100644
--- a/src/common/Network/Packet/IcmpHeader.h
+++ b/src/common/Network/Packet/IcmpHeader.h
@@ -24,6 +24,11 @@ class ICMPHeader
{
public:
+ enum {
+ TYPE_ECHO_REPLY = 0,
+ TYPE_ECHO_REQUEST = 8,
+ };
+
ICMPHeader()
{
setCode(0);
diff --git a/src/common/Network/Packet/MacAddress.h b/src/common/Network/Packet/MacAddress.h
index 7e872fd6..924f774e 100755
--- a/src/common/Network/Packet/MacAddress.h
+++ b/src/common/Network/Packet/MacAddress.h
@@ -29,7 +29,7 @@ public:
MacAddress()
{
- set(0xca, 0xfe, 0xde, 0xad, 0xbe, 0xef);
+ set(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
};
MacAddress(uint8_t a0,
@@ -47,15 +47,15 @@ public:
a5);
};
- MacAddress(uint8_t macAddr[ETHER_ADDR_LEN])
- {
- set(macAddr[0],
- macAddr[1],
- macAddr[2],
- macAddr[3],
- macAddr[4],
- macAddr[5] );
- };
+ MacAddress(const uint8_t macAddr[ETHER_ADDR_LEN])
+ {
+ set(macAddr[0],
+ macAddr[1],
+ macAddr[2],
+ macAddr[3],
+ macAddr[4],
+ macAddr[5] );
+ };
void set(uint8_t a0,
uint8_t a1,
@@ -81,50 +81,83 @@ public:
data[5]=val;
}
+ void set(uint64_t val) {
+ for (int i = 0; i < 6; i++) {
+ data[i] = ( val >> ((5 - i) * 8) ) & 0xFF;
+ }
+ }
+
+ bool isDefaultAddress() const
+ {
+ static MacAddress defaultMac;
+ return (*this == defaultMac);
+ }
+
+ bool isInvalidAddress() const
+ {
+ static MacAddress allZeros(0,0,0,0,0,0);
+ static MacAddress defaultMac;
+ return (*this == allZeros || *this == defaultMac);
+ }
+ void setIdentifierAsBogusAddr(uint32_t identifier)
+ {
+ *(uint32_t*)data = identifier;
+ }
+
+ uint32_t getIdentifierFromBogusAddr()
+ {
+ return *(uint32_t*)data;
+ }
+
+ MacAddress& operator+=(const int& val) {
+ uint64_t tmp = 0;
+
+ for (int i = 0; i < 6; i++) {
+ tmp <<= 8;
+ tmp |= data[i];
+ }
+
+ tmp += val;
+
+ for (int i = 0; i < 6; i++) {
+ data[i] = ( tmp >> ((5 - i) * 8) ) & 0xFF;
+ }
+
+ return *this;
+ }
+
+ bool operator == (const MacAddress& rhs) const
+ {
+ for(int i = 0; i < ETHER_ADDR_LEN; i++)
+ {
+ if(data[i] != rhs.data[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ MacAddress& operator = (const uint8_t *rhs) {
+ memcpy(data, rhs, ETHER_ADDR_LEN);
+ return (*this);
+ }
+
+ uint8_t* GetBuffer()
+ {
+ return data;
+ }
- bool isInvalidAddress() const
- {
- static MacAddress allZeros(0,0,0,0,0,0);
- static MacAddress cafeDeadBeef;
- return (*this == allZeros || *this == cafeDeadBeef);
- }
- void setIdentifierAsBogusAddr(uint32_t identifier)
- {
- *(uint32_t*)data = identifier;
- }
-
- uint32_t getIdentifierFromBogusAddr()
- {
- return *(uint32_t*)data;
- }
-
- bool operator == (const MacAddress& rhs) const
- {
- for(int i = 0; i < ETHER_ADDR_LEN; i++)
- {
- if(data[i] != rhs.data[i])
- return false;
- }
-
- return true;
- }
-
- uint8_t* GetBuffer()
- {
- return data;
- }
-
- const uint8_t* GetConstBuffer() const
- {
- return data;
- }
+ const uint8_t* GetConstBuffer() const
+ {
+ return data;
+ }
void dump(FILE *fd) const;
- void copyToArray(uint8_t *arrayToFill) const
- {
+ void copyToArray(uint8_t *arrayToFill) const
+ {
((uint32_t*)arrayToFill)[0] = ((uint32_t*)data)[0];//Copy first 32bit
- ((uint16_t*)arrayToFill)[2] = ((uint16_t*)data)[2];//Copy last 16bit
- }
+ ((uint16_t*)arrayToFill)[2] = ((uint16_t*)data)[2];//Copy last 16bit
+ }
public:
uint8_t data[ETHER_ADDR_LEN];
diff --git a/src/common/basic_utils.cpp b/src/common/basic_utils.cpp
index f169c29f..fded49ec 100755
--- a/src/common/basic_utils.cpp
+++ b/src/common/basic_utils.cpp
@@ -20,6 +20,10 @@ limitations under the License.
#include <sstream>
#include <sys/resource.h>
+#include "pal_utl.h"
+
+int my_inet_pton4(const char *src, unsigned char *dst);
+
bool utl_is_file_exists (const std::string& name) {
if (FILE *file = fopen(name.c_str(), "r")) {
fclose(file);
@@ -190,6 +194,26 @@ void utl_macaddr_to_str(const uint8_t *macaddr, std::string &output) {
}
+std::string utl_macaddr_to_str(const uint8_t *macaddr) {
+ std::string tmp;
+ utl_macaddr_to_str(macaddr, tmp);
+
+ return tmp;
+}
+
+bool utl_str_to_macaddr(const std::string &s, uint8_t *mac) {
+ int last = -1;
+ int rc = sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%n",
+ mac + 0, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
+ &last);
+
+ if ( (rc != 6) || (s.size() != last) ) {
+ return false;
+ }
+
+ return true;
+}
+
/**
* generate a random connection handler
*
@@ -248,3 +272,23 @@ void utl_set_coredump_size(long size, bool map_huge_pages) {
fprintf(fp, "%08x\n", mask);
fclose(fp);
}
+
+bool utl_ipv4_to_uint32(const char *ipv4_str, uint32_t &ipv4_num) {
+
+ uint32_t tmp;
+
+ int rc = my_inet_pton4(ipv4_str, (unsigned char *)&tmp);
+ if (!rc) {
+ return false;
+ }
+
+ ipv4_num = PAL_NTOHL(tmp);
+
+ return true;
+}
+
+std::string utl_uint32_to_ipv4(uint32_t ipv4_addr) {
+ std::stringstream ss;
+ ss << ((ipv4_addr >> 24) & 0xff) << "." << ((ipv4_addr >> 16) & 0xff) << "." << ((ipv4_addr >> 8) & 0xff) << "." << (ipv4_addr & 0xff);
+ return ss.str();
+}
diff --git a/src/common/basic_utils.h b/src/common/basic_utils.h
index f6250a2b..36f9db85 100755
--- a/src/common/basic_utils.h
+++ b/src/common/basic_utils.h
@@ -85,6 +85,9 @@ inline void utl_swap(T& a, T& b) {
bool utl_is_file_exists (const std::string& name) ;
void utl_macaddr_to_str(const uint8_t *macaddr, std::string &output);
+std::string utl_macaddr_to_str(const uint8_t *macaddr);
+
+bool utl_str_to_macaddr(const std::string &s, uint8_t *mac);
std::string utl_generate_random_str(unsigned int &seed, int len);
@@ -98,6 +101,9 @@ std::string utl_generate_random_str(unsigned int &seed, int len);
*/
void utl_set_coredump_size(long size, bool map_huge_pages = false);
+bool utl_ipv4_to_uint32(const char *ipv4_str, uint32_t &ipv4_num);
+std::string utl_uint32_to_ipv4(uint32_t ipv4_addr);
+
#endif
diff --git a/src/common/captureFile.h b/src/common/captureFile.h
index fefa62bd..d87e57b6 100755
--- a/src/common/captureFile.h
+++ b/src/common/captureFile.h
@@ -227,9 +227,10 @@ class CFileWriterBase {
public:
- virtual ~CFileWriterBase(){};
- virtual bool Create(char * name) = 0;
+ virtual ~CFileWriterBase(){};
+ virtual bool Create(char * name) = 0;
virtual bool write_packet(CCapPktRaw * lpPacket)=0;
+ virtual void flush_to_disk() = 0;
};
diff --git a/src/common/erf.cpp b/src/common/erf.cpp
index 76945b01..f872a281 100755
--- a/src/common/erf.cpp
+++ b/src/common/erf.cpp
@@ -280,7 +280,11 @@ bool CErfFileWriter::write_packet(CCapPktRaw * lpPacket){
return true;
}
-
+void CErfFileWriter::flush_to_disk() {
+ if (m_fd) {
+ fflush(m_fd);
+ }
+}
bool CPcapFileWriter::Create(char *file_name){
m_fd=CAP_FOPEN_64(file_name,"wb");
diff --git a/src/common/erf.h b/src/common/erf.h
index e1b83e46..bec94872 100755
--- a/src/common/erf.h
+++ b/src/common/erf.h
@@ -224,6 +224,13 @@ public:
virtual bool Create(char *file_name);
void Delete();
virtual bool write_packet(CCapPktRaw * lpPacket);
+
+ /**
+ * flush all packets to disk
+ *
+ */
+ void flush_to_disk();
+
private:
FILE *m_fd;
int m_cnt;
diff --git a/src/common/pcap.cpp b/src/common/pcap.cpp
index 8e9bf0ac..b976aed7 100755
--- a/src/common/pcap.cpp
+++ b/src/common/pcap.cpp
@@ -223,11 +223,18 @@ bool LibPCapWriter::Create(char * name)
printf(" ERROR create file \n");
return(false);
}
+
/* prepare the write counter */
m_pkt_count = 0;
return init();
}
+void LibPCapWriter::flush_to_disk() {
+ if (m_is_open) {
+ fflush(m_file_handler);
+ }
+}
+
/**
*
* Write the libpcap header.
diff --git a/src/common/pcap.h b/src/common/pcap.h
index 3f8dfd21..265ea17b 100755
--- a/src/common/pcap.h
+++ b/src/common/pcap.h
@@ -1,5 +1,5 @@
-#ifndef __LIBPCAP_H__
-#define __LIBPCAP_H__
+#ifndef __TREX_LIBPCAP_H__
+#define __TREX_LIBPCAP_H__
/*
Copyright (c) 2015-2015 Cisco Systems, Inc.
@@ -143,6 +143,13 @@ public:
*/
void Close();
+ /**
+ * flush all packets to disk
+ *
+ * @author imarom (11/24/2016)
+ */
+ void flush_to_disk();
+
private:
bool init();
@@ -151,4 +158,5 @@ private:
bool m_is_open;
uint32_t m_pkt_count;
};
+
#endif
diff --git a/src/debug.cpp b/src/debug.cpp
index 3a9cd506..e272424c 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -106,7 +106,7 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t t
0x07, 0x08, 0x50, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0a, 0x01, 0x02, 0x03, 0x04,
// bad - 0x03, 0x04, 0x06, 0x02, 0x20, 0x00, 0xBB, 0x79, 0x00, 0x00};
0x03, 0x04, 0x50, 0x02, 0x20, 0x00, 0xBB, 0x79, 0x00, 0x00};
- rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(0, sizeof(test_pkt));
+ rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_by_port(0, sizeof(test_pkt));
char *p = rte_pktmbuf_append(m, sizeof(test_pkt));
assert(p);
@@ -141,7 +141,12 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t t
}
pkt = CTestPktGen::create_test_pkt(l3_type, l4_proto, ttl, ip_id, flags, 1000, pkt_size);
- m = CGlobalInfo::pktmbuf_alloc(0, pkt_size);
+
+ /* DEBUG print the packet
+ utl_k12_pkt_format(stdout,pkt, pkt_size) ;
+ */
+
+ m = CGlobalInfo::pktmbuf_alloc_by_port(0, pkt_size);
if ( unlikely(m == 0) ) {
printf("ERROR no packets \n");
return (NULL);
@@ -156,7 +161,7 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t t
#endif
rte_mbuf_t *CTrexDebug::create_pkt(uint8_t *pkt, int pkt_size) {
- rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(0, pkt_size);
+ rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_by_port(0, pkt_size);
if ( unlikely(m == 0) ) {
printf("ERROR no packets \n");
return 0;
@@ -170,7 +175,7 @@ rte_mbuf_t *CTrexDebug::create_pkt(uint8_t *pkt, int pkt_size) {
}
rte_mbuf_t *CTrexDebug::create_pkt_indirect(rte_mbuf_t *m, uint32_t new_pkt_size){
- rte_mbuf_t *d = CGlobalInfo::pktmbuf_alloc(0, 60);
+ rte_mbuf_t *d = CGlobalInfo::pktmbuf_alloc_by_port(0, 60);
assert(d);
rte_pktmbuf_attach(d, m);
@@ -341,7 +346,7 @@ int CTrexDebug::verify_hw_rules(bool recv_all) {
rte_mbuf_t *m = NULL;
CPhyEthIF * lp;
rte_mbuf_t * rx_pkts[32];
- int sent_num = 20;
+ int sent_num = 8; /* reduce the size, there are driver that can handle only burst of 8 in QUEUE 0 */
int ret = 0;
for (int pkt_num = 0; pkt_num < sizeof(test_pkts) / sizeof (test_pkts[0]); pkt_num++) {
@@ -365,6 +370,7 @@ int CTrexDebug::verify_hw_rules(bool recv_all) {
case STL:
if ( CGlobalInfo::m_options.is_stateless() ) {
exp_q = MAIN_DPDK_RX_Q;
+ pkt_flags |= DPF_TOS_1;
} else {
exp_q = MAIN_DPDK_DATA_Q;
}
@@ -374,6 +380,7 @@ int CTrexDebug::verify_hw_rules(bool recv_all) {
exp_q = MAIN_DPDK_DATA_Q;
} else {
exp_q = MAIN_DPDK_RX_Q;
+ pkt_flags |= DPF_TOS_1;
}
break;
default:
diff --git a/src/dpdk/drivers/net/enic/base/vnic_dev.c b/src/dpdk/drivers/net/enic/base/vnic_dev.c
index fc2e4cc3..e50b90e7 100644
--- a/src/dpdk/drivers/net/enic/base/vnic_dev.c
+++ b/src/dpdk/drivers/net/enic/base/vnic_dev.c
@@ -462,6 +462,18 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
}
}
+int vnic_dev_capable_adv_filters(struct vnic_dev *vdev)
+{
+ u64 a0 = (u32)CMD_ADD_ADV_FILTER, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait);
+ if (err)
+ return 0;
+ return (a1 >= (u32)FILTER_DPDK_1);
+}
+
static int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd)
{
u64 a0 = (u32)cmd, a1 = 0;
@@ -655,7 +667,12 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
(promisc ? CMD_PFILTER_PROMISCUOUS : 0) |
(allmulti ? CMD_PFILTER_ALL_MULTICAST : 0);
+#define TREX_PATCH
+#ifdef TREX_PATCH
+ err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER_ALL, &a0, &a1, wait);
+#else
err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
+#endif
if (err)
pr_err("Can't set packet filter\n");
@@ -999,7 +1016,7 @@ int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr)
* @data: filter data
*/
int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
- struct filter *data)
+ struct filter_v2 *data)
{
u64 a0, a1;
int wait = 1000;
@@ -1008,11 +1025,20 @@ int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
struct filter_tlv *tlv, *tlv_va;
struct filter_action *action;
u64 tlv_size;
+ u32 filter_size;
static unsigned int unique_id;
char z_name[RTE_MEMZONE_NAMESIZE];
+ enum vnic_devcmd_cmd dev_cmd;
+
if (cmd == CLSF_ADD) {
- tlv_size = sizeof(struct filter) +
+ if (data->type == FILTER_DPDK_1)
+ dev_cmd = CMD_ADD_ADV_FILTER;
+ else
+ dev_cmd = CMD_ADD_FILTER;
+
+ filter_size = vnic_filter_size(data);
+ tlv_size = filter_size +
sizeof(struct filter_action) +
2*sizeof(struct filter_tlv);
snprintf((char *)z_name, sizeof(z_name),
@@ -1026,12 +1052,12 @@ int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
a1 = tlv_size;
memset(tlv, 0, tlv_size);
tlv->type = CLSF_TLV_FILTER;
- tlv->length = sizeof(struct filter);
- *(struct filter *)&tlv->val = *data;
+ tlv->length = filter_size;
+ memcpy(&tlv->val, (void *)data, filter_size);
tlv = (struct filter_tlv *)((char *)tlv +
sizeof(struct filter_tlv) +
- sizeof(struct filter));
+ filter_size);
tlv->type = CLSF_TLV_ACTION;
tlv->length = sizeof(struct filter_action);
@@ -1039,7 +1065,7 @@ int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
action->type = FILTER_ACTION_RQ_STEERING;
action->u.rq_idx = *entry;
- ret = vnic_dev_cmd(vdev, CMD_ADD_FILTER, &a0, &a1, wait);
+ ret = vnic_dev_cmd(vdev, dev_cmd, &a0, &a1, wait);
*entry = (u16)a0;
vdev->free_consistent(vdev->priv, tlv_size, tlv_va, tlv_pa);
} else if (cmd == CLSF_DEL) {
diff --git a/src/dpdk/drivers/net/enic/base/vnic_dev.h b/src/dpdk/drivers/net/enic/base/vnic_dev.h
index 689442f3..06ebd4ce 100644
--- a/src/dpdk/drivers/net/enic/base/vnic_dev.h
+++ b/src/dpdk/drivers/net/enic/base/vnic_dev.h
@@ -134,6 +134,7 @@ void vnic_dev_cmd_proxy_by_bdf_start(struct vnic_dev *vdev, u16 bdf);
void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev);
int vnic_dev_fw_info(struct vnic_dev *vdev,
struct vnic_devcmd_fw_info **fw_info);
+int vnic_dev_capable_adv_filters(struct vnic_dev *vdev);
int vnic_dev_asic_info(struct vnic_dev *vdev, u16 *asic_type, u16 *asic_rev);
int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size,
void *value);
@@ -201,7 +202,7 @@ int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status);
int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status);
int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
- struct filter *data);
+ struct filter_v2 *data);
#ifdef ENIC_VXLAN
int vnic_dev_overlay_offload_enable_disable(struct vnic_dev *vdev,
u8 overlay, u8 config);
diff --git a/src/dpdk/drivers/net/enic/base/vnic_devcmd.h b/src/dpdk/drivers/net/enic/base/vnic_devcmd.h
index b3d5a6cc..785fd6fd 100644
--- a/src/dpdk/drivers/net/enic/base/vnic_devcmd.h
+++ b/src/dpdk/drivers/net/enic/base/vnic_devcmd.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2016 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* Copyright (c) 2014, Cisco Systems, Inc.
@@ -126,7 +126,8 @@ enum vnic_devcmd_cmd {
/* dev-specific block member:
* in: (u16)a0=offset,(u8)a1=size
- * out: a0=value */
+ * out: a0=value
+ */
CMD_DEV_SPEC = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 2),
/* stats clear */
@@ -146,8 +147,9 @@ enum vnic_devcmd_cmd {
CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8),
/* MAC address in (u48)a0 */
- CMD_GET_MAC_ADDR = _CMDC(_CMD_DIR_READ,
+ CMD_MAC_ADDR = _CMDC(_CMD_DIR_READ,
_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9),
+#define CMD_GET_MAC_ADDR CMD_MAC_ADDR /* some uses are aliased */
/* add addr from (u48)a0 */
CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE,
@@ -387,9 +389,8 @@ enum vnic_devcmd_cmd {
* Subvnic migration from MQ <--> VF.
* Enable the LIF migration from MQ to VF and vice versa. MQ and VF
* indexes are statically bound at the time of initialization.
- * Based on the
- * direction of migration, the resources of either MQ or the VF shall
- * be attached to the LIF.
+ * Based on the direction of migration, the resources of either MQ or
+ * the VF shall be attached to the LIF.
* in: (u32)a0=Direction of Migration
* 0=> Migrate to VF
* 1=> Migrate to MQ
@@ -397,7 +398,6 @@ enum vnic_devcmd_cmd {
*/
CMD_MIGRATE_SUBVNIC = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 53),
-
/*
* Register / Deregister the notification block for MQ subvnics
* in:
@@ -433,6 +433,10 @@ enum vnic_devcmd_cmd {
* in: (u64) a0= filter address
* (u32) a1= size of filter
* out: (u32) a0=filter identifier
+ *
+ * Capability query:
+ * out: (u64) a0= 1 if capability query supported
+ * (u64) a1= MAX filter type supported
*/
CMD_ADD_FILTER = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 58),
@@ -471,23 +475,133 @@ enum vnic_devcmd_cmd {
CMD_QP_STATS_CLEAR = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 63),
/*
- * Enable/Disable overlay offloads on the given vnic
+ * UEFI BOOT API: (u64)a0= UEFI FLS_CMD_xxx
+ * (ui64)a1= paddr for the info buffer
+ */
+ CMD_FC_REQ = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_FC, 64),
+
+ /*
+ * Return the iSCSI config details required by the EFI Option ROM
+ * in: (u32) a0=0 Get Boot Info for PXE eNIC as per pxe_boot_config_t
+ * a0=1 Get Boot info for iSCSI enic as per
+ * iscsi_boot_efi_cfg_t
+ * in: (u64) a1=Host address where iSCSI config info is returned
+ */
+ CMD_VNIC_BOOT_CONFIG_INFO = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 65),
+
+ /*
+ * Create a Queue Pair (RoCE)
+ * in: (u32) a0 = Queue Pair number
+ * (u32) a1 = Remote QP
+ * (u32) a2 = RDMA-RQ
+ * (u16) a3 = RQ Res Group
+ * (u16) a4 = SQ Res Group
+ * (u32) a5 = Protection Domain
+ * (u64) a6 = Remote MAC
+ * (u32) a7 = start PSN
+ * (u16) a8 = MSS
+ * (u32) a9 = protocol version
+ */
+ CMD_RDMA_QP_CREATE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 66),
+
+ /*
+ * Delete a Queue Pair (RoCE)
+ * in: (u32) a0 = Queue Pair number
+ */
+ CMD_RDMA_QP_DELETE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 67),
+
+ /*
+ * Retrieve a Queue Pair's status information (RoCE)
+ * in: (u32) a0 = Queue Pair number
+ * (u64) a1 = host buffer addr for QP status struct
+ * (u32) a2 = length of the buffer
+ */
+ CMD_RDMA_QP_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 68),
+
+ /*
+ * Use this devcmd for agreeing on the highest common version supported
+ * by both driver and fw for by features who need such a facility.
+ * in: (u64) a0 = feature (driver requests for the supported versions
+ * on this feature)
+ * out: (u64) a0 = bitmap of all supported versions for that feature
+ */
+ CMD_GET_SUPP_FEATURE_VER = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 69),
+
+ /*
+ * Initialize the RDMA notification work queue
+ * in: (u64) a0 = host buffer address
+ * in: (u16) a1 = number of entries in buffer
+ * in: (u16) a2 = resource group number
+ * in: (u16) a3 = CQ number to post completion
+ */
+ CMD_RDMA_INIT_INFO_BUF = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 70),
+
+ /*
+ * De-init the RDMA notification work queue
+ * in: (u64) a0=resource group number
+ */
+ CMD_RDMA_DEINIT_INFO_BUF = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 71),
+
+ /*
+ * Control (Enable/Disable) overlay offloads on the given vnic
* in: (u8) a0 = OVERLAY_FEATURE_NVGRE : NVGRE
* a0 = OVERLAY_FEATURE_VXLAN : VxLAN
- * in: (u8) a1 = OVERLAY_OFFLOAD_ENABLE : Enable
- * a1 = OVERLAY_OFFLOAD_DISABLE : Disable
+ * in: (u8) a1 = OVERLAY_OFFLOAD_ENABLE : Enable or
+ * a1 = OVERLAY_OFFLOAD_DISABLE : Disable or
+ * a1 = OVERLAY_OFFLOAD_ENABLE_V2 : Enable with version 2
*/
- CMD_OVERLAY_OFFLOAD_ENABLE_DISABLE =
- _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 72),
+ CMD_OVERLAY_OFFLOAD_CTRL =
+ _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 72),
/*
* Configuration of overlay offloads feature on a given vNIC
- * in: (u8) a0 = DEVCMD_OVERLAY_NVGRE : NVGRE
- * a0 = DEVCMD_OVERLAY_VXLAN : VxLAN
- * in: (u8) a1 = VXLAN_PORT_UPDATE : VxLAN
- * in: (u16) a2 = unsigned short int port information
+ * in: (u8) a0 = OVERLAY_CFG_VXLAN_PORT_UPDATE : VxLAN
+ * in: (u16) a1 = unsigned short int port information
*/
CMD_OVERLAY_OFFLOAD_CFG = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 73),
+
+ /*
+ * Return the configured name for the device
+ * in: (u64) a0=Host address where the name is copied
+ * (u32) a1=Size of the buffer
+ */
+ CMD_GET_CONFIG_NAME = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 74),
+
+ /*
+ * Enable group interrupt for the VF
+ * in: (u32) a0 = GRPINTR_ENABLE : enable
+ * a0 = GRPINTR_DISABLE : disable
+ * a0 = GRPINTR_UPD_VECT: update group vector addr
+ * in: (u32) a1 = interrupt group count
+ * in: (u64) a2 = Start of host buffer address for DMAing group
+ * vector bitmap
+ * in: (u64) a3 = Stride between group vectors
+ */
+ CMD_CONFIG_GRPINTR = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 75),
+
+ /*
+ * Set cq arrary base and size in a list of consective wqs and
+ * rqs for a device
+ * in: (u16) a0 = the wq relative index in the device.
+ * -1 indicates skipping wq configuration
+ * in: (u16) a1 = the wcq relative index in the device
+ * in: (u16) a2 = the rq relative index in the device
+ * -1 indicates skipping rq configuration
+ * in: (u16) a3 = the rcq relative index in the device
+ */
+ CMD_CONFIG_CQ_ARRAY = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 76),
+
+ /*
+ * Add an advanced filter.
+ * in: (u64) a0= filter address
+ * (u32) a1= size of filter
+ * out: (u32) a0=filter identifier
+ *
+ * Capability query:
+ * out: (u64) a0= 1 if capabliity query supported
+ * (u64) a1= MAX filter type supported
+ */
+ CMD_ADD_ADV_FILTER = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 77),
};
/* CMD_ENABLE2 flags */
@@ -520,6 +634,9 @@ enum vnic_devcmd_status {
STAT_NONE = 0,
STAT_BUSY = 1 << 0, /* cmd in progress */
STAT_ERROR = 1 << 1, /* last cmd caused error (code in a0) */
+ STAT_FAILOVER = 1 << 2, /* always set on vnics in pci standby state
+ * if seen a failover to the standby happened
+ */
};
enum vnic_devcmd_error {
@@ -558,9 +675,9 @@ enum fwinfo_asic_type {
FWINFO_ASIC_TYPE_UNKNOWN,
FWINFO_ASIC_TYPE_PALO,
FWINFO_ASIC_TYPE_SERENO,
+ FWINFO_ASIC_TYPE_CRUZ,
};
-
struct vnic_devcmd_notify {
u32 csum; /* checksum over following words */
@@ -595,25 +712,16 @@ struct vnic_devcmd_provinfo {
*/
#define FILTER_FIELD_VALID(fld) (1 << (fld - 1))
-#define FILTER_FIELDS_USNIC (FILTER_FIELD_VALID(1) | \
- FILTER_FIELD_VALID(2) | \
- FILTER_FIELD_VALID(3) | \
- FILTER_FIELD_VALID(4))
-
-#define FILTER_FIELDS_IPV4_5TUPLE (FILTER_FIELD_VALID(1) | \
- FILTER_FIELD_VALID(2) | \
- FILTER_FIELD_VALID(3) | \
- FILTER_FIELD_VALID(4) | \
- FILTER_FIELD_VALID(5))
-
-#define FILTER_FIELDS_MAC_VLAN (FILTER_FIELD_VALID(1) | \
- FILTER_FIELD_VALID(2))
-
#define FILTER_FIELD_USNIC_VLAN FILTER_FIELD_VALID(1)
#define FILTER_FIELD_USNIC_ETHTYPE FILTER_FIELD_VALID(2)
#define FILTER_FIELD_USNIC_PROTO FILTER_FIELD_VALID(3)
#define FILTER_FIELD_USNIC_ID FILTER_FIELD_VALID(4)
+#define FILTER_FIELDS_USNIC (FILTER_FIELD_USNIC_VLAN | \
+ FILTER_FIELD_USNIC_ETHTYPE | \
+ FILTER_FIELD_USNIC_PROTO | \
+ FILTER_FIELD_USNIC_ID)
+
struct filter_usnic_id {
u32 flags;
u16 vlan;
@@ -628,10 +736,18 @@ struct filter_usnic_id {
#define FILTER_FIELD_5TUP_SRC_PT FILTER_FIELD_VALID(4)
#define FILTER_FIELD_5TUP_DST_PT FILTER_FIELD_VALID(5)
+#define FILTER_FIELDS_IPV4_5TUPLE (FILTER_FIELD_5TUP_PROTO | \
+ FILTER_FIELD_5TUP_SRC_AD | \
+ FILTER_FIELD_5TUP_DST_AD | \
+ FILTER_FIELD_5TUP_SRC_PT | \
+ FILTER_FIELD_5TUP_DST_PT)
+
/* Enums for the protocol field. */
enum protocol_e {
PROTO_UDP = 0,
PROTO_TCP = 1,
+ PROTO_IPV4 = 2,
+ PROTO_IPV6 = 3
};
struct filter_ipv4_5tuple {
@@ -646,12 +762,78 @@ struct filter_ipv4_5tuple {
#define FILTER_FIELD_VMQ_VLAN FILTER_FIELD_VALID(1)
#define FILTER_FIELD_VMQ_MAC FILTER_FIELD_VALID(2)
+#define FILTER_FIELDS_MAC_VLAN (FILTER_FIELD_VMQ_VLAN | \
+ FILTER_FIELD_VMQ_MAC)
+
+#define FILTER_FIELDS_NVGRE FILTER_FIELD_VMQ_MAC
+
struct filter_mac_vlan {
u32 flags;
u16 vlan;
u8 mac_addr[6];
} __attribute__((packed));
+#define FILTER_FIELD_VLAN_IP_3TUP_VLAN FILTER_FIELD_VALID(1)
+#define FILTER_FIELD_VLAN_IP_3TUP_L3_PROTO FILTER_FIELD_VALID(2)
+#define FILTER_FIELD_VLAN_IP_3TUP_DST_AD FILTER_FIELD_VALID(3)
+#define FILTER_FIELD_VLAN_IP_3TUP_L4_PROTO FILTER_FIELD_VALID(4)
+#define FILTER_FIELD_VLAN_IP_3TUP_DST_PT FILTER_FIELD_VALID(5)
+
+#define FILTER_FIELDS_VLAN_IP_3TUP (FILTER_FIELD_VLAN_IP_3TUP_VLAN | \
+ FILTER_FIELD_VLAN_IP_3TUP_L3_PROTO | \
+ FILTER_FIELD_VLAN_IP_3TUP_DST_AD | \
+ FILTER_FIELD_VLAN_IP_3TUP_L4_PROTO | \
+ FILTER_FIELD_VLAN_IP_3TUP_DST_PT)
+
+struct filter_vlan_ip_3tuple {
+ u32 flags;
+ u16 vlan;
+ u16 l3_protocol;
+ union {
+ u32 dst_addr_v4;
+ u8 dst_addr_v6[16];
+ } u;
+ u32 l4_protocol;
+ u16 dst_port;
+} __attribute__((packed));
+
+#define FILTER_GENERIC_1_BYTES 64
+
+enum filter_generic_1_layer {
+ FILTER_GENERIC_1_L2,
+ FILTER_GENERIC_1_L3,
+ FILTER_GENERIC_1_L4,
+ FILTER_GENERIC_1_L5,
+ FILTER_GENERIC_1_NUM_LAYERS
+};
+
+#define FILTER_GENERIC_1_IPV4 (1 << 0)
+#define FILTER_GENERIC_1_IPV6 (1 << 1)
+#define FILTER_GENERIC_1_UDP (1 << 2)
+#define FILTER_GENERIC_1_TCP (1 << 3)
+#define FILTER_GENERIC_1_TCP_OR_UDP (1 << 4)
+#define FILTER_GENERIC_1_IP4SUM_OK (1 << 5)
+#define FILTER_GENERIC_1_L4SUM_OK (1 << 6)
+#define FILTER_GENERIC_1_IPFRAG (1 << 7)
+
+#define FILTER_GENERIC_1_KEY_LEN 64
+
+/*
+ * Version 1 of generic filter specification
+ * position is only 16 bits, reserving positions > 64k to be used by firmware
+ */
+struct filter_generic_1 {
+ u16 position; /* lower position comes first */
+ u32 mask_flags;
+ u32 val_flags;
+ u16 mask_vlan;
+ u16 val_vlan;
+ struct {
+ u8 mask[FILTER_GENERIC_1_KEY_LEN]; /* 0 bit means "don't care"*/
+ u8 val[FILTER_GENERIC_1_KEY_LEN];
+ } __attribute__((packed)) layer[FILTER_GENERIC_1_NUM_LAYERS];
+} __attribute__((packed));
+
/* Specifies the filter_action type. */
enum {
FILTER_ACTION_RQ_STEERING = 0,
@@ -670,6 +852,10 @@ enum filter_type {
FILTER_USNIC_ID = 0,
FILTER_IPV4_5TUPLE = 1,
FILTER_MAC_VLAN = 2,
+ FILTER_VLAN_IP_3TUPLE = 3,
+ FILTER_NVGRE_VMQ = 4,
+ FILTER_USNIC_IP = 5,
+ FILTER_DPDK_1 = 6,
FILTER_MAX
};
@@ -679,6 +865,27 @@ struct filter {
struct filter_usnic_id usnic;
struct filter_ipv4_5tuple ipv4;
struct filter_mac_vlan mac_vlan;
+ struct filter_vlan_ip_3tuple vlan_3tuple;
+ } u;
+} __attribute__((packed));
+
+/*
+ * This is a strict superset of "struct filter" and exists only
+ * because many drivers use "sizeof (struct filter)" in deciding TLV size.
+ * This new, larger struct filter would cause any code that uses that method
+ * to not work with older firmware, so we add filter_v2 to hold the
+ * new filter types. Drivers should use vnic_filter_size() to determine
+ * the TLV size instead of sizeof (struct fiter_v2) to guard against future
+ * growth.
+ */
+struct filter_v2 {
+ u32 type;
+ union {
+ struct filter_usnic_id usnic;
+ struct filter_ipv4_5tuple ipv4;
+ struct filter_mac_vlan mac_vlan;
+ struct filter_vlan_ip_3tuple vlan_3tuple;
+ struct filter_generic_1 generic_1;
} u;
} __attribute__((packed));
@@ -687,14 +894,55 @@ enum {
CLSF_TLV_ACTION = 1,
};
-#define FILTER_MAX_BUF_SIZE 100 /* Maximum size of buffer to CMD_ADD_FILTER */
-
struct filter_tlv {
- uint32_t type;
- uint32_t length;
- uint32_t val[0];
+ u_int32_t type;
+ u_int32_t length;
+ u_int32_t val[0];
};
+/* Data for CMD_ADD_FILTER is 2 TLV and filter + action structs */
+#define FILTER_MAX_BUF_SIZE 100
+#define FILTER_V2_MAX_BUF_SIZE (sizeof(struct filter_v2) + \
+ sizeof(struct filter_action) + \
+ (2 * sizeof(struct filter_tlv)))
+
+/*
+ * Compute actual structure size given filter type. To be "future-proof,"
+ * drivers should use this instead of "sizeof (struct filter_v2)" when
+ * computing length for TLV.
+ */
+static inline u_int32_t
+vnic_filter_size(struct filter_v2 *fp)
+{
+ u_int32_t size;
+
+ switch (fp->type) {
+ case FILTER_USNIC_ID:
+ size = sizeof(fp->u.usnic);
+ break;
+ case FILTER_IPV4_5TUPLE:
+ size = sizeof(fp->u.ipv4);
+ break;
+ case FILTER_MAC_VLAN:
+ case FILTER_NVGRE_VMQ:
+ size = sizeof(fp->u.mac_vlan);
+ break;
+ case FILTER_VLAN_IP_3TUPLE:
+ size = sizeof(fp->u.vlan_3tuple);
+ break;
+ case FILTER_USNIC_IP:
+ case FILTER_DPDK_1:
+ size = sizeof(fp->u.generic_1);
+ break;
+ default:
+ size = sizeof(fp->u);
+ break;
+ }
+ size += sizeof(fp->type);
+ return size;
+}
+
+
enum {
CLSF_ADD = 0,
CLSF_DEL = 1,
@@ -766,8 +1014,30 @@ typedef enum {
OVERLAY_FEATURE_MAX,
} overlay_feature_t;
-#define OVERLAY_OFFLOAD_ENABLE 0
-#define OVERLAY_OFFLOAD_DISABLE 1
+#define OVERLAY_OFFLOAD_ENABLE 0
+#define OVERLAY_OFFLOAD_DISABLE 1
+#define OVERLAY_OFFLOAD_ENABLE_V2 2
#define OVERLAY_CFG_VXLAN_PORT_UPDATE 0
+
+/*
+ * Use this enum to get the supported versions for each of these features
+ * If you need to use the devcmd_get_supported_feature_version(), add
+ * the new feature into this enum and install function handler in devcmd.c
+ */
+typedef enum {
+ VIC_FEATURE_VXLAN,
+ VIC_FEATURE_RDMA,
+ VIC_FEATURE_MAX,
+} vic_feature_t;
+
+/*
+ * CMD_CONFIG_GRPINTR subcommands
+ */
+typedef enum {
+ GRPINTR_ENABLE = 1,
+ GRPINTR_DISABLE,
+ GRPINTR_UPD_VECT,
+} grpintr_subcmd_t;
+
#endif /* _VNIC_DEVCMD_H_ */
diff --git a/src/dpdk/drivers/net/enic/enic.h b/src/dpdk/drivers/net/enic/enic.h
index 4c16ef17..c00d3fb8 100644
--- a/src/dpdk/drivers/net/enic/enic.h
+++ b/src/dpdk/drivers/net/enic/enic.h
@@ -92,6 +92,12 @@ struct enic_fdir {
struct rte_eth_fdir_stats stats;
struct rte_hash *hash;
struct enic_fdir_node *nodes[ENICPMD_FDIR_MAX];
+ u32 modes;
+ u32 types_mask;
+ void (*copy_fltr_fn)(struct filter_v2 *filt,
+ struct rte_eth_fdir_input *input,
+ struct rte_eth_fdir_masks *masks);
+
};
struct enic_soft_stats {
@@ -128,6 +134,7 @@ struct enic {
int link_status;
u8 hw_ip_checksum;
u16 max_mtu;
+ u16 adv_filters;
unsigned int flags;
unsigned int priv_flags;
@@ -273,4 +280,11 @@ uint16_t enic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
uint16_t enic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
int enic_set_mtu(struct enic *enic, uint16_t new_mtu);
+void enic_fdir_info(struct enic *enic);
+void enic_fdir_info_get(struct enic *enic, struct rte_eth_fdir_info *stats);
+void copy_fltr_v1(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
+ struct rte_eth_fdir_masks *masks);
+void copy_fltr_v2(__rte_unused struct filter_v2 *fltr,
+ __rte_unused struct rte_eth_fdir_input *input,
+ __rte_unused struct rte_eth_fdir_masks *masks);
#endif /* _ENIC_H_ */
diff --git a/src/dpdk/drivers/net/enic/enic_clsf.c b/src/dpdk/drivers/net/enic/enic_clsf.c
index e6f57bea..8f68faab 100644
--- a/src/dpdk/drivers/net/enic/enic_clsf.c
+++ b/src/dpdk/drivers/net/enic/enic_clsf.c
@@ -38,6 +38,11 @@
#include <rte_malloc.h>
#include <rte_hash.h>
#include <rte_byteorder.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_sctp.h>
+#include <rte_eth_ctrl.h>
#include "enic_compat.h"
#include "enic.h"
@@ -67,6 +72,296 @@ void enic_fdir_stats_get(struct enic *enic, struct rte_eth_fdir_stats *stats)
*stats = enic->fdir.stats;
}
+void enic_fdir_info_get(struct enic *enic, struct rte_eth_fdir_info *info)
+{
+ info->mode = enic->fdir.modes;
+ info->flow_types_mask[0] = enic->fdir.types_mask;
+}
+
+void enic_fdir_info(struct enic *enic)
+{
+ enic->fdir.modes = (u32)RTE_FDIR_MODE_PERFECT;
+ enic->fdir.types_mask = 1 << RTE_ETH_FLOW_NONFRAG_IPV4_UDP |
+ 1 << RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
+ if (enic->adv_filters) {
+ enic->fdir.types_mask |= 1 << RTE_ETH_FLOW_NONFRAG_IPV4_OTHER |
+ 1 << RTE_ETH_FLOW_NONFRAG_IPV4_SCTP |
+ 1 << RTE_ETH_FLOW_NONFRAG_IPV6_UDP |
+ 1 << RTE_ETH_FLOW_NONFRAG_IPV6_TCP |
+ 1 << RTE_ETH_FLOW_NONFRAG_IPV6_SCTP |
+ 1 << RTE_ETH_FLOW_NONFRAG_IPV6_OTHER;
+ enic->fdir.copy_fltr_fn = copy_fltr_v2;
+ } else {
+ enic->fdir.copy_fltr_fn = copy_fltr_v1;
+ }
+}
+
+static void
+enic_set_layer(struct filter_generic_1 *gp, unsigned int flag,
+ enum filter_generic_1_layer layer, void *mask, void *val,
+ unsigned int len)
+{
+ gp->mask_flags |= flag;
+ gp->val_flags |= gp->mask_flags;
+ memcpy(gp->layer[layer].mask, mask, len);
+ memcpy(gp->layer[layer].val, val, len);
+}
+
+
+/* Copy Flow Director filter to a VIC ipv4 filter (for Cisco VICs
+ * without advanced filter support.
+ */
+void
+copy_fltr_v1(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
+ __rte_unused struct rte_eth_fdir_masks *masks)
+{
+ fltr->type = FILTER_IPV4_5TUPLE;
+ fltr->u.ipv4.src_addr = rte_be_to_cpu_32(
+ input->flow.ip4_flow.src_ip);
+ fltr->u.ipv4.dst_addr = rte_be_to_cpu_32(
+ input->flow.ip4_flow.dst_ip);
+ fltr->u.ipv4.src_port = rte_be_to_cpu_16(
+ input->flow.udp4_flow.src_port);
+ fltr->u.ipv4.dst_port = rte_be_to_cpu_16(
+ input->flow.udp4_flow.dst_port);
+
+ if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_TCP)
+ fltr->u.ipv4.protocol = PROTO_TCP;
+ else
+ fltr->u.ipv4.protocol = PROTO_UDP;
+
+ fltr->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
+}
+
+#define TREX_PATCH
+#ifdef TREX_PATCH
+void
+copy_fltr_recv_all(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
+ struct rte_eth_fdir_masks *masks) {
+ struct filter_generic_1 *gp = &fltr->u.generic_1;
+ memset(gp, 0, sizeof(*gp));
+
+ struct ether_hdr eth_mask, eth_val;
+ memset(&eth_mask, 0, sizeof(eth_mask));
+ memset(&eth_val, 0, sizeof(eth_val));
+
+ eth_val.ether_type = 0x0806;
+ eth_mask.ether_type = 0;
+
+ gp->position = 0;
+ enic_set_layer(gp, 0, FILTER_GENERIC_1_L2,
+ &eth_mask, &eth_val, sizeof(struct ether_hdr));
+
+}
+#endif
+
+/* Copy Flow Director filter to a VIC generic filter (requires advanced
+ * filter support.
+ */
+void
+copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
+ struct rte_eth_fdir_masks *masks)
+{
+ struct filter_generic_1 *gp = &fltr->u.generic_1;
+ int i;
+
+ RTE_ASSERT(enic->adv_filters);
+
+ fltr->type = FILTER_DPDK_1;
+ memset(gp, 0, sizeof(*gp));
+#ifdef TREX_PATCH
+ // important for this to be below 2.
+ // If added with position 2, IPv6 UDP and ICMP seems to be caught by some other rule
+ gp->position = 1;
+#endif
+
+ if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_UDP) {
+ struct udp_hdr udp_mask, udp_val;
+ memset(&udp_mask, 0, sizeof(udp_mask));
+ memset(&udp_val, 0, sizeof(udp_val));
+
+ if (input->flow.udp4_flow.src_port) {
+ udp_mask.src_port = masks->src_port_mask;
+ udp_val.src_port = input->flow.udp4_flow.src_port;
+ }
+ if (input->flow.udp4_flow.dst_port) {
+ udp_mask.src_port = masks->dst_port_mask;
+ udp_val.dst_port = input->flow.udp4_flow.dst_port;
+ }
+
+ enic_set_layer(gp, FILTER_GENERIC_1_UDP, FILTER_GENERIC_1_L4,
+ &udp_mask, &udp_val, sizeof(struct udp_hdr));
+ } else if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_TCP) {
+ struct tcp_hdr tcp_mask, tcp_val;
+ memset(&tcp_mask, 0, sizeof(tcp_mask));
+ memset(&tcp_val, 0, sizeof(tcp_val));
+
+ if (input->flow.tcp4_flow.src_port) {
+ tcp_mask.src_port = masks->src_port_mask;
+ tcp_val.src_port = input->flow.tcp4_flow.src_port;
+ }
+ if (input->flow.tcp4_flow.dst_port) {
+ tcp_mask.dst_port = masks->dst_port_mask;
+ tcp_val.dst_port = input->flow.tcp4_flow.dst_port;
+ }
+
+ enic_set_layer(gp, FILTER_GENERIC_1_TCP, FILTER_GENERIC_1_L4,
+ &tcp_mask, &tcp_val, sizeof(struct tcp_hdr));
+ } else if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_SCTP) {
+ struct sctp_hdr sctp_mask, sctp_val;
+ memset(&sctp_mask, 0, sizeof(sctp_mask));
+ memset(&sctp_val, 0, sizeof(sctp_val));
+
+ if (input->flow.sctp4_flow.src_port) {
+ sctp_mask.src_port = masks->src_port_mask;
+ sctp_val.src_port = input->flow.sctp4_flow.src_port;
+ }
+ if (input->flow.sctp4_flow.dst_port) {
+ sctp_mask.dst_port = masks->dst_port_mask;
+ sctp_val.dst_port = input->flow.sctp4_flow.dst_port;
+ }
+ if (input->flow.sctp4_flow.verify_tag) {
+ sctp_mask.tag = 0xffffffff;
+ sctp_val.tag = input->flow.sctp4_flow.verify_tag;
+ }
+
+ /* v4 proto should be 132, override ip4_flow.proto */
+ input->flow.ip4_flow.proto = 132;
+
+ enic_set_layer(gp, 0, FILTER_GENERIC_1_L4, &sctp_mask,
+ &sctp_val, sizeof(struct sctp_hdr));
+ }
+
+ if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_UDP ||
+ input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_TCP ||
+ input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_SCTP ||
+ input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_OTHER) {
+ struct ipv4_hdr ip4_mask, ip4_val;
+ memset(&ip4_mask, 0, sizeof(struct ipv4_hdr));
+ memset(&ip4_val, 0, sizeof(struct ipv4_hdr));
+
+ if (input->flow.ip4_flow.tos) {
+ ip4_mask.type_of_service = masks->ipv4_mask.tos;
+ ip4_val.type_of_service = input->flow.ip4_flow.tos;
+ }
+ if (input->flow.ip4_flow.ip_id) {
+ ip4_mask.packet_id = 0xffff;
+ ip4_val.packet_id = input->flow.ip4_flow.ip_id;
+ }
+ if (input->flow.ip4_flow.ttl) {
+ ip4_mask.time_to_live = 0xff;
+ ip4_val.time_to_live = input->flow.ip4_flow.ttl;
+ }
+ if (input->flow.ip4_flow.proto) {
+ ip4_mask.next_proto_id = 0xff;
+ ip4_val.next_proto_id = input->flow.ip4_flow.proto;
+ }
+ if (input->flow.ip4_flow.src_ip) {
+ ip4_mask.src_addr = masks->ipv4_mask.src_ip;
+ ip4_val.src_addr = input->flow.ip4_flow.src_ip;
+ }
+ if (input->flow.ip4_flow.dst_ip) {
+ ip4_mask.dst_addr = masks->ipv4_mask.dst_ip;
+ ip4_val.dst_addr = input->flow.ip4_flow.dst_ip;
+ }
+
+ enic_set_layer(gp, FILTER_GENERIC_1_IPV4, FILTER_GENERIC_1_L3,
+ &ip4_mask, &ip4_val, sizeof(struct ipv4_hdr));
+ }
+
+ if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_UDP) {
+ struct udp_hdr udp_mask, udp_val;
+ memset(&udp_mask, 0, sizeof(udp_mask));
+ memset(&udp_val, 0, sizeof(udp_val));
+
+ if (input->flow.udp6_flow.src_port) {
+ udp_mask.src_port = masks->src_port_mask;
+ udp_val.src_port = input->flow.udp6_flow.src_port;
+ }
+ if (input->flow.udp6_flow.dst_port) {
+ udp_mask.dst_port = masks->dst_port_mask;
+ udp_val.dst_port = input->flow.udp6_flow.dst_port;
+ }
+ enic_set_layer(gp, FILTER_GENERIC_1_UDP, FILTER_GENERIC_1_L4,
+ &udp_mask, &udp_val, sizeof(struct udp_hdr));
+ } else if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_TCP) {
+ struct tcp_hdr tcp_mask, tcp_val;
+ memset(&tcp_mask, 0, sizeof(tcp_mask));
+ memset(&tcp_val, 0, sizeof(tcp_val));
+
+ if (input->flow.tcp6_flow.src_port) {
+ tcp_mask.src_port = masks->src_port_mask;
+ tcp_val.src_port = input->flow.tcp6_flow.src_port;
+ }
+ if (input->flow.tcp6_flow.dst_port) {
+ tcp_mask.dst_port = masks->dst_port_mask;
+ tcp_val.dst_port = input->flow.tcp6_flow.dst_port;
+ }
+ enic_set_layer(gp, FILTER_GENERIC_1_TCP, FILTER_GENERIC_1_L4,
+ &tcp_mask, &tcp_val, sizeof(struct tcp_hdr));
+ } else if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_SCTP) {
+ struct sctp_hdr sctp_mask, sctp_val;
+ memset(&sctp_mask, 0, sizeof(sctp_mask));
+ memset(&sctp_val, 0, sizeof(sctp_val));
+
+ if (input->flow.sctp6_flow.src_port) {
+ sctp_mask.src_port = masks->src_port_mask;
+ sctp_val.src_port = input->flow.sctp6_flow.src_port;
+ }
+ if (input->flow.sctp6_flow.dst_port) {
+ sctp_mask.dst_port = masks->dst_port_mask;
+ sctp_val.dst_port = input->flow.sctp6_flow.dst_port;
+ }
+ if (input->flow.sctp6_flow.verify_tag) {
+ sctp_mask.tag = 0xffffffff;
+ sctp_val.tag = input->flow.sctp6_flow.verify_tag;
+ }
+
+ /* v4 proto should be 132, override ipv6_flow.proto */
+ input->flow.ipv6_flow.proto = 132;
+
+ enic_set_layer(gp, 0, FILTER_GENERIC_1_L4, &sctp_mask,
+ &sctp_val, sizeof(struct sctp_hdr));
+ }
+
+ if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_UDP ||
+ input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_TCP ||
+ input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_SCTP ||
+ input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_OTHER) {
+ struct ipv6_hdr ipv6_mask, ipv6_val;
+ memset(&ipv6_mask, 0, sizeof(struct ipv6_hdr));
+ memset(&ipv6_val, 0, sizeof(struct ipv6_hdr));
+
+ if (input->flow.ipv6_flow.proto) {
+ ipv6_mask.proto = masks->ipv6_mask.proto;
+ ipv6_val.proto = input->flow.ipv6_flow.proto;
+ }
+ for (i = 0; i < 4; i++) {
+ *(uint32_t *)&ipv6_mask.src_addr[i * 4] =
+ masks->ipv6_mask.src_ip[i];
+ *(uint32_t *)&ipv6_val.src_addr[i * 4] =
+ input->flow.ipv6_flow.src_ip[i];
+ }
+ for (i = 0; i < 4; i++) {
+ *(uint32_t *)&ipv6_mask.dst_addr[i * 4] =
+ masks->ipv6_mask.src_ip[i];
+ *(uint32_t *)&ipv6_val.dst_addr[i * 4] =
+ input->flow.ipv6_flow.dst_ip[i];
+ }
+ if (input->flow.ipv6_flow.tc) {
+ ipv6_mask.vtc_flow = ((uint32_t)masks->ipv6_mask.tc<<12);
+ ipv6_val.vtc_flow = input->flow.ipv6_flow.tc << 12;
+ }
+ if (input->flow.ipv6_flow.hop_limits) {
+ ipv6_mask.hop_limits = 0xff;
+ ipv6_val.hop_limits = input->flow.ipv6_flow.hop_limits;
+ }
+
+ enic_set_layer(gp, FILTER_GENERIC_1_IPV6, FILTER_GENERIC_1_L3,
+ &ipv6_mask, &ipv6_val, sizeof(struct ipv6_hdr));
+ }
+}
+
int enic_fdir_del_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
{
int32_t pos;
@@ -77,11 +372,23 @@ int enic_fdir_del_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
case -EINVAL:
case -ENOENT:
enic->fdir.stats.f_remove++;
+#ifdef TREX_PATCH
+ return pos;
+#else
return -EINVAL;
+#endif
default:
/* The entry is present in the table */
key = enic->fdir.nodes[pos];
+#ifdef TREX_PATCH
+ switch (params->soft_id) {
+ case 100:
+ // remove promisc when we delete 'receive all' filter
+ vnic_dev_packet_filter(enic->vdev, 1, 1, 1, 0, 1);
+ break;
+ }
+#endif
/* Delete the filter */
vnic_dev_classifier(enic->vdev, CLSF_DEL,
&key->fltr_id, NULL);
@@ -97,7 +404,7 @@ int enic_fdir_del_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
int enic_fdir_add_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
{
struct enic_fdir_node *key;
- struct filter fltr = {0};
+ struct filter_v2 fltr;
int32_t pos;
u8 do_free = 0;
u16 old_fltr_id = 0;
@@ -105,9 +412,9 @@ int enic_fdir_add_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
u16 flex_bytes;
u16 queue;
- flowtype_supported = (
- (RTE_ETH_FLOW_NONFRAG_IPV4_TCP == params->input.flow_type) ||
- (RTE_ETH_FLOW_NONFRAG_IPV4_UDP == params->input.flow_type));
+ memset(&fltr, 0, sizeof(fltr));
+ flowtype_supported = enic->fdir.types_mask
+ & (1 << params->input.flow_type);
flex_bytes = ((params->input.flow_ext.flexbytes[1] << 8 & 0xFF00) |
(params->input.flow_ext.flexbytes[0] & 0xFF));
@@ -120,7 +427,12 @@ int enic_fdir_add_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
return -ENOTSUP;
}
- queue = params->action.rx_queue;
+ /* Get the enicpmd RQ from the DPDK Rx queue */
+ queue = enic_sop_rq(params->action.rx_queue);
+
+ if (!enic->rq[queue].in_use)
+ return -EINVAL;
+
/* See if the key is already there in the table */
pos = rte_hash_del_key(enic->fdir.hash, params);
switch (pos) {
@@ -183,22 +495,19 @@ int enic_fdir_add_fltr(struct enic *enic, struct rte_eth_fdir_filter *params)
key->filter = *params;
key->rq_index = queue;
- fltr.type = FILTER_IPV4_5TUPLE;
- fltr.u.ipv4.src_addr = rte_be_to_cpu_32(
- params->input.flow.ip4_flow.src_ip);
- fltr.u.ipv4.dst_addr = rte_be_to_cpu_32(
- params->input.flow.ip4_flow.dst_ip);
- fltr.u.ipv4.src_port = rte_be_to_cpu_16(
- params->input.flow.udp4_flow.src_port);
- fltr.u.ipv4.dst_port = rte_be_to_cpu_16(
- params->input.flow.udp4_flow.dst_port);
-
- if (RTE_ETH_FLOW_NONFRAG_IPV4_TCP == params->input.flow_type)
- fltr.u.ipv4.protocol = PROTO_TCP;
- else
- fltr.u.ipv4.protocol = PROTO_UDP;
-
- fltr.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
+#ifdef TREX_PATCH
+ switch (params->soft_id) {
+ case 100:
+ vnic_dev_packet_filter(enic->vdev, 1, 1, 1, 1, 1);
+ copy_fltr_recv_all(&fltr, &params->input, &enic->rte_dev->data->dev_conf.fdir_conf.mask);
+ break;
+ default:
+#endif
+ enic->fdir.copy_fltr_fn(&fltr, &params->input,
+ &enic->rte_dev->data->dev_conf.fdir_conf.mask);
+#ifdef TREX_PATCH
+ }
+#endif
if (!vnic_dev_classifier(enic->vdev, CLSF_ADD, &queue, &fltr)) {
key->fltr_id = queue;
@@ -238,6 +547,7 @@ void enic_clsf_destroy(struct enic *enic)
vnic_dev_classifier(enic->vdev, CLSF_DEL,
&key->fltr_id, NULL);
rte_free(key);
+ enic->fdir.nodes[index] = NULL;
}
}
diff --git a/src/dpdk/drivers/net/enic/enic_ethdev.c b/src/dpdk/drivers/net/enic/enic_ethdev.c
index 47b07c92..6a86e23f 100644
--- a/src/dpdk/drivers/net/enic/enic_ethdev.c
+++ b/src/dpdk/drivers/net/enic/enic_ethdev.c
@@ -95,10 +95,12 @@ enicpmd_fdir_ctrl_func(struct rte_eth_dev *eth_dev,
break;
case RTE_ETH_FILTER_FLUSH:
- case RTE_ETH_FILTER_INFO:
dev_warning(enic, "unsupported operation %u", filter_op);
ret = -ENOTSUP;
break;
+ case RTE_ETH_FILTER_INFO:
+ enic_fdir_info_get(enic, (struct rte_eth_fdir_info *)arg);
+ break;
default:
dev_err(enic, "unknown operation %u", filter_op);
ret = -EINVAL;
@@ -433,6 +435,9 @@ static void enicpmd_dev_stats_reset(struct rte_eth_dev *eth_dev)
enic_dev_stats_clear(enic);
}
+
+
+
static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
struct rte_eth_dev_info *device_info)
{
@@ -459,6 +464,8 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
device_info->default_rxconf = (struct rte_eth_rxconf) {
.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
};
+
+ device_info->speed_capa = ETH_LINK_SPEED_40G;
}
static const uint32_t *enicpmd_dev_supported_ptypes_get(struct rte_eth_dev *dev)
diff --git a/src/dpdk/drivers/net/enic/enic_main.c b/src/dpdk/drivers/net/enic/enic_main.c
index b4ca3710..473bfc3c 100644
--- a/src/dpdk/drivers/net/enic/enic_main.c
+++ b/src/dpdk/drivers/net/enic/enic_main.c
@@ -166,6 +166,7 @@ void enic_dev_stats_get(struct enic *enic, struct rte_eth_stats *r_stats)
return;
}
+
/* The number of truncated packets can only be calculated by
* subtracting a hardware counter from error packets received by
* the driver. Note: this causes transient inaccuracies in the
@@ -180,7 +181,7 @@ void enic_dev_stats_get(struct enic *enic, struct rte_eth_stats *r_stats)
r_stats->ipackets = stats->rx.rx_frames_ok - rx_truncated;
r_stats->opackets = stats->tx.tx_frames_ok;
- r_stats->ibytes = stats->rx.rx_bytes_ok;
+ r_stats->ibytes = stats->rx.rx_unicast_bytes_ok+stats->rx.rx_multicast_bytes_ok+stats->rx.rx_broadcast_bytes_ok;
r_stats->obytes = stats->tx.tx_bytes_ok;
r_stats->ierrors = stats->rx.rx_errors + stats->rx.rx_drop;
@@ -1122,6 +1123,9 @@ static int enic_dev_init(struct enic *enic)
return err;
}
+ /* Get the supported filters */
+ enic_fdir_info(enic);
+
eth_dev->data->mac_addrs = rte_zmalloc("enic_mac_addr", ETH_ALEN, 0);
if (!eth_dev->data->mac_addrs) {
dev_err(enic, "mac addr storage alloc failed, aborting.\n");
diff --git a/src/dpdk/drivers/net/enic/enic_res.c b/src/dpdk/drivers/net/enic/enic_res.c
index 84c5d336..8a230a16 100644
--- a/src/dpdk/drivers/net/enic/enic_res.c
+++ b/src/dpdk/drivers/net/enic/enic_res.c
@@ -62,6 +62,7 @@ int enic_get_vnic_config(struct enic *enic)
return err;
}
+
#define GET_CONFIG(m) \
do { \
err = vnic_dev_spec(enic->vdev, \
@@ -98,6 +99,10 @@ int enic_get_vnic_config(struct enic *enic)
enic->rte_dev->data->mtu = min_t(u16, enic->max_mtu,
max_t(u16, ENIC_MIN_MTU, c->mtu));
+ enic->adv_filters = vnic_dev_capable_adv_filters(enic->vdev);
+ dev_info(enic, "Advanced Filters %savailable\n", ((enic->adv_filters)
+ ? "" : "not "));
+
c->wq_desc_count =
min_t(u32, ENIC_MAX_WQ_DESCS,
max_t(u32, ENIC_MIN_WQ_DESCS,
diff --git a/src/dpdk/drivers/net/ixgbe/ixgbe_ethdev.c b/src/dpdk/drivers/net/ixgbe/ixgbe_ethdev.c
index d478a159..72963a89 100644
--- a/src/dpdk/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/src/dpdk/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -5784,13 +5784,17 @@ ixgbe_add_del_ethertype_filter(struct rte_eth_dev *dev,
if (filter->queue >= IXGBE_MAX_RX_QUEUE_NUM)
return -EINVAL;
-
+#define TREX_PATCH
+#ifndef TREX_PATCH
+ // no real reason to block this.
+ // We configure rules using FDIR and ethertype that point to same queue, so there are no race condition issues.
if (filter->ether_type == ETHER_TYPE_IPv4 ||
filter->ether_type == ETHER_TYPE_IPv6) {
PMD_DRV_LOG(ERR, "unsupported ether_type(0x%04x) in"
" ethertype filter.", filter->ether_type);
return -EINVAL;
}
+#endif
if (filter->flags & RTE_ETHTYPE_FLAGS_MAC) {
PMD_DRV_LOG(ERR, "mac compare is unsupported.");
diff --git a/src/dpdk/drivers/net/mlx5/mlx5.c b/src/dpdk/drivers/net/mlx5/mlx5.c
index d96a9aff..303b917b 100644
--- a/src/dpdk/drivers/net/mlx5/mlx5.c
+++ b/src/dpdk/drivers/net/mlx5/mlx5.c
@@ -181,6 +181,9 @@ mlx5_dev_close(struct rte_eth_dev *dev)
}
if (priv->reta_idx != NULL)
rte_free(priv->reta_idx);
+
+ mlx5_stats_free(dev);
+
priv_unlock(priv);
memset(priv, 0, sizeof(*priv));
}
@@ -366,6 +369,13 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
unsigned int mps;
int idx;
int i;
+ static int ibv_was_init=0;
+
+ if (ibv_was_init==0) {
+ ibv_fork_init();
+ ibv_was_init=1;
+ }
+
(void)pci_drv;
assert(pci_drv == &mlx5_driver.pci_drv);
@@ -511,7 +521,16 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
priv->mtu = ETHER_MTU;
priv->mps = mps; /* Enable MPW by default if supported. */
priv->cqe_comp = 1; /* Enable compression by default. */
+
+
err = mlx5_args(priv, pci_dev->devargs);
+
+ /* TREX PATCH */
+ /* set for maximum performance default */
+ priv->txq_inline =128;
+ priv->txqs_inline =4;
+
+
if (err) {
ERROR("failed to process device arguments: %s",
strerror(err));
@@ -751,7 +770,6 @@ rte_mlx5_pmd_init(const char *name, const char *args)
* using this PMD, which is not supported in forked processes.
*/
setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
- ibv_fork_init();
rte_eal_pci_register(&mlx5_driver.pci_drv);
return 0;
}
diff --git a/src/dpdk/drivers/net/mlx5/mlx5.h b/src/dpdk/drivers/net/mlx5/mlx5.h
index 3a866098..68bad904 100644
--- a/src/dpdk/drivers/net/mlx5/mlx5.h
+++ b/src/dpdk/drivers/net/mlx5/mlx5.h
@@ -84,6 +84,34 @@ enum {
PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF = 0x1016,
};
+struct mlx5_stats_priv {
+
+ struct rte_eth_stats m_shadow;
+ uint32_t n_stats; /* number of counters */
+
+ void * et_stats ;/* point to ethtool counter struct ethtool_stats*/
+
+ /* index into ethtool */
+ uint16_t inx_rx_vport_unicast_bytes;
+ uint16_t inx_rx_vport_multicast_bytes;
+ uint16_t inx_rx_vport_broadcast_bytes;
+ uint16_t inx_rx_vport_unicast_packets;
+ uint16_t inx_rx_vport_multicast_packets;
+ uint16_t inx_rx_vport_broadcast_packets;
+ uint16_t inx_tx_vport_unicast_bytes;
+ uint16_t inx_tx_vport_multicast_bytes;
+ uint16_t inx_tx_vport_broadcast_bytes;
+ uint16_t inx_tx_vport_unicast_packets;
+ uint16_t inx_tx_vport_multicast_packets;
+ uint16_t inx_tx_vport_broadcast_packets;
+ uint16_t inx_rx_wqe_err;
+ uint16_t inx_rx_crc_errors_phy;
+ uint16_t inx_rx_in_range_len_errors_phy;
+ uint16_t inx_rx_symbol_err_phy;
+ uint16_t inx_tx_errors_phy;
+};
+
+
struct priv {
struct rte_eth_dev *dev; /* Ethernet device. */
struct ibv_context *ctx; /* Verbs context. */
@@ -135,6 +163,7 @@ struct priv {
unsigned int reta_idx_n; /* RETA index size. */
struct fdir_filter_list *fdir_filter_list; /* Flow director rules. */
rte_spinlock_t lock; /* Lock for control functions. */
+ struct mlx5_stats_priv m_stats;
};
/* Local storage for secondary process data. */
@@ -243,6 +272,8 @@ void mlx5_allmulticast_disable(struct rte_eth_dev *);
void mlx5_stats_get(struct rte_eth_dev *, struct rte_eth_stats *);
void mlx5_stats_reset(struct rte_eth_dev *);
+void mlx5_stats_free(struct rte_eth_dev *dev);
+
/* mlx5_vlan.c */
diff --git a/src/dpdk/drivers/net/mlx5/mlx5_autoconf.h b/src/dpdk/drivers/net/mlx5/mlx5_autoconf.h
new file mode 100644
index 00000000..9fdfff84
--- /dev/null
+++ b/src/dpdk/drivers/net/mlx5/mlx5_autoconf.h
@@ -0,0 +1,8 @@
+#ifndef HAVE_VERBS_IBV_EXP_CQ_COMPRESSED_CQE
+#define HAVE_VERBS_IBV_EXP_CQ_COMPRESSED_CQE 1
+#endif /* HAVE_VERBS_IBV_EXP_CQ_COMPRESSED_CQE */
+
+#ifndef HAVE_VERBS_MLX5_ETH_VLAN_INLINE_HEADER_SIZE
+#define HAVE_VERBS_MLX5_ETH_VLAN_INLINE_HEADER_SIZE 1
+#endif /* HAVE_VERBS_MLX5_ETH_VLAN_INLINE_HEADER_SIZE */
+
diff --git a/src/dpdk/drivers/net/mlx5/mlx5_fdir.c b/src/dpdk/drivers/net/mlx5/mlx5_fdir.c
index 73eb00ec..4ba3bb9f 100644
--- a/src/dpdk/drivers/net/mlx5/mlx5_fdir.c
+++ b/src/dpdk/drivers/net/mlx5/mlx5_fdir.c
@@ -37,12 +37,14 @@
#include <string.h>
#include <errno.h>
+#define TREX_PATCH
+
/* Verbs header. */
/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
#ifdef PEDANTIC
#pragma GCC diagnostic ignored "-pedantic"
#endif
-#include <infiniband/verbs.h>
+#include <infiniband/verbs_exp.h>
#ifdef PEDANTIC
#pragma GCC diagnostic error "-pedantic"
#endif
@@ -67,6 +69,10 @@ struct fdir_flow_desc {
uint16_t src_port;
uint32_t src_ip[4];
uint32_t dst_ip[4];
+ uint8_t tos;
+ uint8_t ip_id;
+ uint8_t proto;
+
uint8_t mac[6];
uint16_t vlan_tag;
enum hash_rxq_type type;
@@ -102,6 +108,7 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
desc->vlan_tag = fdir_filter->input.flow_ext.vlan_tci;
/* Set MAC address. */
+#ifndef TREX_PATCH
if (mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
rte_memcpy(desc->mac,
fdir_filter->input.flow.mac_vlan_flow.mac_addr.
@@ -110,6 +117,13 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
desc->type = HASH_RXQ_ETH;
return;
}
+#else
+ if (fdir_filter->input.flow.ip4_flow.ip_id == 2) {
+ desc->type = HASH_RXQ_ETH;
+ desc->ip_id = fdir_filter->input.flow.ip4_flow.ip_id;
+ return;
+ }
+#endif
/* Set mode */
switch (fdir_filter->input.flow_type) {
@@ -141,9 +155,13 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
desc->src_port = fdir_filter->input.flow.udp4_flow.src_port;
desc->dst_port = fdir_filter->input.flow.udp4_flow.dst_port;
+
case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
desc->src_ip[0] = fdir_filter->input.flow.ip4_flow.src_ip;
desc->dst_ip[0] = fdir_filter->input.flow.ip4_flow.dst_ip;
+ desc->tos = fdir_filter->input.flow.ip4_flow.ttl; /* TTL is mapped to TOS TREX_PATCH */
+ desc->ip_id = fdir_filter->input.flow.ip4_flow.ip_id;
+ desc->proto = fdir_filter->input.flow.ip4_flow.proto;
break;
case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
@@ -157,12 +175,17 @@ fdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
rte_memcpy(desc->dst_ip,
fdir_filter->input.flow.ipv6_flow.dst_ip,
sizeof(desc->dst_ip));
+ desc->tos = (uint8_t)fdir_filter->input.flow.ipv6_flow.hop_limits; /* TTL is mapped to TOS - TREX_PATCH */
+ desc->ip_id = (uint8_t)fdir_filter->input.flow.ipv6_flow.flow_label;
+ desc->proto = fdir_filter->input.flow.ipv6_flow.proto;
+
break;
default:
break;
}
}
+
/**
* Check if two flow descriptors overlap according to configured mask.
*
@@ -197,6 +220,12 @@ priv_fdir_overlap(const struct priv *priv,
((desc1->dst_port & mask->dst_port_mask) !=
(desc2->dst_port & mask->dst_port_mask)))
return 0;
+
+ if ( (desc1->tos != desc2->tos) ||
+ (desc1->ip_id != desc2->ip_id) ||
+ (desc1->proto != desc2->proto) )
+ return 0;
+
switch (desc1->type) {
case HASH_RXQ_IPV4:
case HASH_RXQ_UDPV4:
@@ -204,8 +233,9 @@ priv_fdir_overlap(const struct priv *priv,
if (((desc1->src_ip[0] & mask->ipv4_mask.src_ip) !=
(desc2->src_ip[0] & mask->ipv4_mask.src_ip)) ||
((desc1->dst_ip[0] & mask->ipv4_mask.dst_ip) !=
- (desc2->dst_ip[0] & mask->ipv4_mask.dst_ip)))
+ (desc2->dst_ip[0] & mask->ipv4_mask.dst_ip)))
return 0;
+
break;
case HASH_RXQ_IPV6:
case HASH_RXQ_UDPV6:
@@ -251,8 +281,8 @@ priv_fdir_flow_add(struct priv *priv,
struct ibv_exp_flow_attr *attr = &data->attr;
uintptr_t spec_offset = (uintptr_t)&data->spec;
struct ibv_exp_flow_spec_eth *spec_eth;
- struct ibv_exp_flow_spec_ipv4 *spec_ipv4;
- struct ibv_exp_flow_spec_ipv6 *spec_ipv6;
+ struct ibv_exp_flow_spec_ipv4_ext *spec_ipv4;
+ struct ibv_exp_flow_spec_ipv6_ext *spec_ipv6;
struct ibv_exp_flow_spec_tcp_udp *spec_tcp_udp;
struct mlx5_fdir_filter *iter_fdir_filter;
unsigned int i;
@@ -264,8 +294,10 @@ priv_fdir_flow_add(struct priv *priv,
(iter_fdir_filter->flow != NULL) &&
(priv_fdir_overlap(priv,
&mlx5_fdir_filter->desc,
- &iter_fdir_filter->desc)))
- return EEXIST;
+ &iter_fdir_filter->desc))){
+ ERROR("overlap rules, please check your rules");
+ return EEXIST;
+ }
/*
* No padding must be inserted by the compiler between attr and spec.
@@ -288,6 +320,7 @@ priv_fdir_flow_add(struct priv *priv,
/* Update priority */
attr->priority = 2;
+#ifndef TREX_PATCH
if (fdir_mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
/* MAC Address */
for (i = 0; i != RTE_DIM(spec_eth->mask.dst_mac); ++i) {
@@ -297,6 +330,14 @@ priv_fdir_flow_add(struct priv *priv,
}
goto create_flow;
}
+#else
+ // empty mask means "match everything". This rule will match all packets, no matter what is the ether type
+ if (desc->ip_id == 2) {
+ spec_eth->val.ether_type = 0x0806;
+ spec_eth->mask.ether_type = 0x0000;
+ goto create_flow;
+ }
+#endif
switch (desc->type) {
case HASH_RXQ_IPV4:
@@ -305,10 +346,10 @@ priv_fdir_flow_add(struct priv *priv,
spec_offset += spec_eth->size;
/* Set IP spec */
- spec_ipv4 = (struct ibv_exp_flow_spec_ipv4 *)spec_offset;
+ spec_ipv4 = (struct ibv_exp_flow_spec_ipv4_ext *)spec_offset;
/* The second specification must be IP. */
- assert(spec_ipv4->type == IBV_EXP_FLOW_SPEC_IPV4);
+ assert(spec_ipv4->type == IBV_EXP_FLOW_SPEC_IPV4_EXT);
assert(spec_ipv4->size == sizeof(*spec_ipv4));
spec_ipv4->val.src_ip =
@@ -318,6 +359,21 @@ priv_fdir_flow_add(struct priv *priv,
spec_ipv4->mask.src_ip = mask->ipv4_mask.src_ip;
spec_ipv4->mask.dst_ip = mask->ipv4_mask.dst_ip;
+ /* PROTO */
+ spec_ipv4->val.proto = desc->proto & mask->ipv4_mask.proto;
+ spec_ipv4->mask.proto = mask->ipv4_mask.proto;
+
+#ifdef TREX_PATCH
+ /* TOS */
+ if (desc->ip_id == 1) {
+ spec_ipv4->mask.tos = 0x1;
+ spec_ipv4->val.tos = 0x1;
+ } else {
+ spec_ipv4->mask.tos = 0x0;
+ spec_ipv4->val.tos = 0x0;
+ }
+ // spec_ipv4->val.tos = desc->tos & spec_ipv4->mask.tos;// & mask->ipv4_mask.tos;
+#endif
/* Update priority */
attr->priority = 1;
@@ -332,10 +388,10 @@ priv_fdir_flow_add(struct priv *priv,
spec_offset += spec_eth->size;
/* Set IP spec */
- spec_ipv6 = (struct ibv_exp_flow_spec_ipv6 *)spec_offset;
+ spec_ipv6 = (struct ibv_exp_flow_spec_ipv6_ext *)spec_offset;
/* The second specification must be IP. */
- assert(spec_ipv6->type == IBV_EXP_FLOW_SPEC_IPV6);
+ assert(spec_ipv6->type == IBV_EXP_FLOW_SPEC_IPV6_EXT);
assert(spec_ipv6->size == sizeof(*spec_ipv6));
for (i = 0; i != RTE_DIM(desc->src_ip); ++i) {
@@ -351,6 +407,20 @@ priv_fdir_flow_add(struct priv *priv,
mask->ipv6_mask.dst_ip,
sizeof(spec_ipv6->mask.dst_ip));
+ spec_ipv6->val.next_hdr = desc->proto & mask->ipv6_mask.proto;
+ spec_ipv6->mask.next_hdr = mask->ipv6_mask.proto;
+
+#ifdef TREX_PATCH
+ /* TOS */
+ if (desc->ip_id == 1) {
+ spec_ipv6->mask.traffic_class = 0x1;
+ spec_ipv6->val.traffic_class = 0x1;
+ } else {
+ spec_ipv6->mask.traffic_class = 0;
+ spec_ipv6->val.traffic_class = 0;
+ }
+#endif
+
/* Update priority */
attr->priority = 1;
@@ -722,8 +792,10 @@ priv_fdir_filter_add(struct priv *priv,
/* Duplicate filters are currently unsupported. */
mlx5_fdir_filter = priv_find_filter_in_list(priv, fdir_filter);
if (mlx5_fdir_filter != NULL) {
+#ifndef TREX_PATCH
ERROR("filter already exists");
- return EINVAL;
+#endif
+ return EEXIST;
}
/* Create new flow director filter. */
@@ -847,9 +919,11 @@ priv_fdir_filter_delete(struct priv *priv,
return 0;
}
+#ifndef TREX_PATCH
ERROR("%p: flow director delete failed, cannot find filter",
(void *)priv);
- return EINVAL;
+#endif
+ return ENOENT;
}
/**
diff --git a/src/dpdk/drivers/net/mlx5/mlx5_rxq.c b/src/dpdk/drivers/net/mlx5/mlx5_rxq.c
index 29c137cd..6be01d39 100644
--- a/src/dpdk/drivers/net/mlx5/mlx5_rxq.c
+++ b/src/dpdk/drivers/net/mlx5/mlx5_rxq.c
@@ -102,7 +102,7 @@ const struct hash_rxq_init hash_rxq_init[] = {
ETH_RSS_FRAG_IPV4),
.flow_priority = 1,
.flow_spec.ipv4 = {
- .type = IBV_EXP_FLOW_SPEC_IPV4,
+ .type = IBV_EXP_FLOW_SPEC_IPV4_EXT,
.size = sizeof(hash_rxq_init[0].flow_spec.ipv4),
},
.underlayer = &hash_rxq_init[HASH_RXQ_ETH],
@@ -140,7 +140,7 @@ const struct hash_rxq_init hash_rxq_init[] = {
ETH_RSS_FRAG_IPV6),
.flow_priority = 1,
.flow_spec.ipv6 = {
- .type = IBV_EXP_FLOW_SPEC_IPV6,
+ .type = IBV_EXP_FLOW_SPEC_IPV6_EXT,
.size = sizeof(hash_rxq_init[0].flow_spec.ipv6),
},
.underlayer = &hash_rxq_init[HASH_RXQ_ETH],
diff --git a/src/dpdk/drivers/net/mlx5/mlx5_rxtx.c b/src/dpdk/drivers/net/mlx5/mlx5_rxtx.c
index fce3381a..c0bcfd03 100644
--- a/src/dpdk/drivers/net/mlx5/mlx5_rxtx.c
+++ b/src/dpdk/drivers/net/mlx5/mlx5_rxtx.c
@@ -908,7 +908,7 @@ mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
mpw->wqe->mpw.eseg.rsvd2 = 0;
mpw->wqe->mpw.ctrl.data[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
(txq->wqe_ci << 8) |
- MLX5_OPCODE_LSO_MPW);
+ MLX5_OPCODE_TSO);
mpw->wqe->mpw.ctrl.data[2] = 0;
mpw->wqe->mpw.ctrl.data[3] = 0;
mpw->data.dseg[0] = &mpw->wqe->mpw.dseg[0];
@@ -1107,7 +1107,7 @@ mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
mpw->wqe = &(*txq->wqes)[idx];
mpw->wqe->mpw_inl.ctrl.data[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
(txq->wqe_ci << 8) |
- MLX5_OPCODE_LSO_MPW);
+ MLX5_OPCODE_TSO);
mpw->wqe->mpw_inl.ctrl.data[2] = 0;
mpw->wqe->mpw_inl.ctrl.data[3] = 0;
mpw->wqe->mpw_inl.eseg.mss = htons(length);
diff --git a/src/dpdk/drivers/net/mlx5/mlx5_rxtx.h b/src/dpdk/drivers/net/mlx5/mlx5_rxtx.h
index f6e2cbac..d87dd19b 100644
--- a/src/dpdk/drivers/net/mlx5/mlx5_rxtx.h
+++ b/src/dpdk/drivers/net/mlx5/mlx5_rxtx.h
@@ -173,8 +173,8 @@ struct hash_rxq_init {
uint16_t size;
} hdr;
struct ibv_exp_flow_spec_tcp_udp tcp_udp;
- struct ibv_exp_flow_spec_ipv4 ipv4;
- struct ibv_exp_flow_spec_ipv6 ipv6;
+ struct ibv_exp_flow_spec_ipv4_ext ipv4;
+ struct ibv_exp_flow_spec_ipv6_ext ipv6;
struct ibv_exp_flow_spec_eth eth;
} flow_spec; /* Flow specification template. */
const struct hash_rxq_init *underlayer; /* Pointer to underlayer. */
diff --git a/src/dpdk/drivers/net/mlx5/mlx5_stats.c b/src/dpdk/drivers/net/mlx5/mlx5_stats.c
index 2d3cb519..788ef939 100644
--- a/src/dpdk/drivers/net/mlx5/mlx5_stats.c
+++ b/src/dpdk/drivers/net/mlx5/mlx5_stats.c
@@ -44,6 +44,10 @@
#include "mlx5_rxtx.h"
#include "mlx5_defs.h"
+
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+
/**
* DPDK callback to get device statistics.
*
@@ -52,60 +56,241 @@
* @param[out] stats
* Stats structure output buffer.
*/
+
+
+static void
+mlx5_stats_read_hw(struct rte_eth_dev *dev,
+ struct rte_eth_stats *stats){
+ struct priv *priv = mlx5_get_priv(dev);
+ struct mlx5_stats_priv * lps = &priv->m_stats;
+ unsigned int i;
+
+ struct rte_eth_stats tmp = {0};
+ struct ethtool_stats *et_stats = (struct ethtool_stats *)lps->et_stats;
+ struct ifreq ifr;
+
+ et_stats->cmd = ETHTOOL_GSTATS;
+ et_stats->n_stats = lps->n_stats;
+
+ ifr.ifr_data = (caddr_t) et_stats;
+
+ if (priv_ifreq(priv, SIOCETHTOOL, &ifr) != 0) {
+ WARN("unable to get statistic values for mlnx5 ");
+ }
+
+ tmp.ibytes += et_stats->data[lps->inx_rx_vport_unicast_bytes] +
+ et_stats->data[lps->inx_rx_vport_multicast_bytes] +
+ et_stats->data[lps->inx_rx_vport_broadcast_bytes];
+
+ tmp.ipackets += et_stats->data[lps->inx_rx_vport_unicast_packets] +
+ et_stats->data[lps->inx_rx_vport_multicast_packets] +
+ et_stats->data[lps->inx_rx_vport_broadcast_packets];
+
+ tmp.ierrors += (et_stats->data[lps->inx_rx_wqe_err] +
+ et_stats->data[lps->inx_rx_crc_errors_phy] +
+ et_stats->data[lps->inx_rx_in_range_len_errors_phy] +
+ et_stats->data[lps->inx_rx_symbol_err_phy]);
+
+ tmp.obytes += et_stats->data[lps->inx_tx_vport_unicast_bytes] +
+ et_stats->data[lps->inx_tx_vport_multicast_bytes] +
+ et_stats->data[lps->inx_tx_vport_broadcast_bytes];
+
+ tmp.opackets += (et_stats->data[lps->inx_tx_vport_unicast_packets] +
+ et_stats->data[lps->inx_tx_vport_multicast_packets] +
+ et_stats->data[lps->inx_tx_vport_broadcast_packets]);
+
+ tmp.oerrors += et_stats->data[lps->inx_tx_errors_phy];
+
+ /* SW Rx */
+ for (i = 0; (i != priv->rxqs_n); ++i) {
+ struct rxq *rxq = (*priv->rxqs)[i];
+ if (rxq) {
+ tmp.imissed += rxq->stats.idropped;
+ tmp.rx_nombuf += rxq->stats.rx_nombuf;
+ }
+ }
+
+ /*SW Tx */
+ for (i = 0; (i != priv->txqs_n); ++i) {
+ struct txq *txq = (*priv->txqs)[i];
+ if (txq) {
+ tmp.oerrors += txq->stats.odropped;
+ }
+ }
+
+ *stats =tmp;
+}
+
+void
+mlx5_stats_free(struct rte_eth_dev *dev)
+{
+ struct priv *priv = mlx5_get_priv(dev);
+ struct mlx5_stats_priv * lps = &priv->m_stats;
+
+ if ( lps->et_stats ){
+ free(lps->et_stats);
+ lps->et_stats=0;
+ }
+}
+
+
+static void
+mlx5_stats_init(struct rte_eth_dev *dev)
+{
+ struct priv *priv = mlx5_get_priv(dev);
+ struct mlx5_stats_priv * lps = &priv->m_stats;
+ struct rte_eth_stats tmp = {0};
+
+ unsigned int i;
+ unsigned int idx;
+ char ifname[IF_NAMESIZE];
+ struct ifreq ifr;
+
+ struct ethtool_stats *et_stats = NULL;
+ struct ethtool_drvinfo drvinfo;
+ struct ethtool_gstrings *strings = NULL;
+ unsigned int n_stats, sz_str, sz_stats;
+
+ if (priv_get_ifname(priv, &ifname)) {
+ WARN("unable to get interface name");
+ return;
+ }
+ /* How many statistics are available ? */
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t) &drvinfo;
+ if (priv_ifreq(priv, SIOCETHTOOL, &ifr) != 0) {
+ WARN("unable to get driver info for %s", ifname);
+ return;
+ }
+
+ n_stats = drvinfo.n_stats;
+ if (n_stats < 1) {
+ WARN("no statistics available for %s", ifname);
+ return;
+ }
+ lps->n_stats = n_stats;
+
+ /* Allocate memory to grab stat names and values */
+ sz_str = n_stats * ETH_GSTRING_LEN;
+ sz_stats = n_stats * sizeof(uint64_t);
+ strings = calloc(1, sz_str + sizeof(struct ethtool_gstrings));
+ if (!strings) {
+ WARN("unable to allocate memory for strings");
+ return;
+ }
+
+ et_stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
+ if (!et_stats) {
+ free(strings);
+ WARN("unable to allocate memory for stats");
+ }
+
+ strings->cmd = ETHTOOL_GSTRINGS;
+ strings->string_set = ETH_SS_STATS;
+ strings->len = n_stats;
+ ifr.ifr_data = (caddr_t) strings;
+ if (priv_ifreq(priv, SIOCETHTOOL, &ifr) != 0) {
+ WARN("unable to get statistic names for %s", ifname);
+ free(strings);
+ free(et_stats);
+ return;
+ }
+
+ for (i = 0; (i != n_stats); ++i) {
+
+ const char * curr_string = (const char*) &(strings->data[i * ETH_GSTRING_LEN]);
+
+ if (!strcmp("rx_vport_unicast_bytes", curr_string)) lps->inx_rx_vport_unicast_bytes = i;
+ if (!strcmp("rx_vport_multicast_bytes", curr_string)) lps->inx_rx_vport_multicast_bytes = i;
+ if (!strcmp("rx_vport_broadcast_bytes", curr_string)) lps->inx_rx_vport_broadcast_bytes = i;
+
+ if (!strcmp("rx_vport_unicast_packets", curr_string)) lps->inx_rx_vport_unicast_packets = i;
+ if (!strcmp("rx_vport_multicast_packets", curr_string)) lps->inx_rx_vport_multicast_packets = i;
+ if (!strcmp("rx_vport_broadcast_packets", curr_string)) lps->inx_rx_vport_broadcast_packets = i;
+
+ if (!strcmp("tx_vport_unicast_bytes", curr_string)) lps->inx_tx_vport_unicast_bytes = i;
+ if (!strcmp("tx_vport_multicast_bytes", curr_string)) lps->inx_tx_vport_multicast_bytes = i;
+ if (!strcmp("tx_vport_broadcast_bytes", curr_string)) lps->inx_tx_vport_broadcast_bytes = i;
+
+ if (!strcmp("tx_vport_unicast_packets", curr_string)) lps->inx_tx_vport_unicast_packets = i;
+ if (!strcmp("tx_vport_multicast_packets", curr_string)) lps->inx_tx_vport_multicast_packets = i;
+ if (!strcmp("tx_vport_broadcast_packets", curr_string)) lps->inx_tx_vport_broadcast_packets = i;
+
+ if (!strcmp("rx_wqe_err", curr_string)) lps->inx_rx_wqe_err = i;
+ if (!strcmp("rx_crc_errors_phy", curr_string)) lps->inx_rx_crc_errors_phy = i;
+ if (!strcmp("rx_in_range_len_errors_phy", curr_string)) lps->inx_rx_in_range_len_errors_phy = i;
+ if (!strcmp("rx_symbol_err_phy", curr_string)) lps->inx_rx_symbol_err_phy = i;
+
+ if (!strcmp("tx_errors_phy", curr_string)) lps->inx_tx_errors_phy = i;
+ }
+
+ lps->et_stats =(void *)et_stats;
+
+ if (!lps->inx_rx_vport_unicast_bytes ||
+ !lps->inx_rx_vport_multicast_bytes ||
+ !lps->inx_rx_vport_broadcast_bytes ||
+ !lps->inx_rx_vport_unicast_packets ||
+ !lps->inx_rx_vport_multicast_packets ||
+ !lps->inx_rx_vport_broadcast_packets ||
+ !lps->inx_tx_vport_unicast_bytes ||
+ !lps->inx_tx_vport_multicast_bytes ||
+ !lps->inx_tx_vport_broadcast_bytes ||
+ !lps->inx_tx_vport_unicast_packets ||
+ !lps->inx_tx_vport_multicast_packets ||
+ !lps->inx_tx_vport_broadcast_packets ||
+ !lps->inx_rx_wqe_err ||
+ !lps->inx_rx_crc_errors_phy ||
+ !lps->inx_rx_in_range_len_errors_phy) {
+ WARN("Counters are not recognized %s", ifname);
+ return;
+ }
+
+ mlx5_stats_read_hw(dev,&tmp);
+
+ /* copy yo shadow at first time */
+ lps->m_shadow = tmp;
+
+ free(strings);
+}
+
+
+static void
+mlx5_stats_diff(struct rte_eth_stats *a,
+ struct rte_eth_stats *b,
+ struct rte_eth_stats *c){
+ #define MLX5_DIFF(cnt) { a->cnt = (b->cnt - c->cnt); }
+
+ MLX5_DIFF(ipackets);
+ MLX5_DIFF(opackets);
+ MLX5_DIFF(ibytes);
+ MLX5_DIFF(obytes);
+ MLX5_DIFF(imissed);
+
+ MLX5_DIFF(ierrors);
+ MLX5_DIFF(oerrors);
+ MLX5_DIFF(rx_nombuf);
+}
+
+
void
mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
{
struct priv *priv = mlx5_get_priv(dev);
- struct rte_eth_stats tmp = {0};
- unsigned int i;
- unsigned int idx;
-
- priv_lock(priv);
- /* Add software counters. */
- for (i = 0; (i != priv->rxqs_n); ++i) {
- struct rxq *rxq = (*priv->rxqs)[i];
-
- if (rxq == NULL)
- continue;
- idx = rxq->stats.idx;
- if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
-#ifdef MLX5_PMD_SOFT_COUNTERS
- tmp.q_ipackets[idx] += rxq->stats.ipackets;
- tmp.q_ibytes[idx] += rxq->stats.ibytes;
-#endif
- tmp.q_errors[idx] += (rxq->stats.idropped +
- rxq->stats.rx_nombuf);
- }
-#ifdef MLX5_PMD_SOFT_COUNTERS
- tmp.ipackets += rxq->stats.ipackets;
- tmp.ibytes += rxq->stats.ibytes;
-#endif
- tmp.ierrors += rxq->stats.idropped;
- tmp.rx_nombuf += rxq->stats.rx_nombuf;
- }
- for (i = 0; (i != priv->txqs_n); ++i) {
- struct txq *txq = (*priv->txqs)[i];
-
- if (txq == NULL)
- continue;
- idx = txq->stats.idx;
- if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
-#ifdef MLX5_PMD_SOFT_COUNTERS
- tmp.q_opackets[idx] += txq->stats.opackets;
- tmp.q_obytes[idx] += txq->stats.obytes;
-#endif
- tmp.q_errors[idx] += txq->stats.odropped;
- }
-#ifdef MLX5_PMD_SOFT_COUNTERS
- tmp.opackets += txq->stats.opackets;
- tmp.obytes += txq->stats.obytes;
-#endif
- tmp.oerrors += txq->stats.odropped;
- }
-#ifndef MLX5_PMD_SOFT_COUNTERS
- /* FIXME: retrieve and add hardware counters. */
-#endif
- *stats = tmp;
+
+ struct mlx5_stats_priv * lps = &priv->m_stats;
+ priv_lock(priv);
+
+ if (lps->et_stats == NULL) {
+ mlx5_stats_init(dev);
+ }
+ struct rte_eth_stats tmp = {0};
+
+ mlx5_stats_read_hw(dev,&tmp);
+
+ mlx5_stats_diff(stats,
+ &tmp,
+ &lps->m_shadow);
+
priv_unlock(priv);
}
@@ -119,26 +304,20 @@ void
mlx5_stats_reset(struct rte_eth_dev *dev)
{
struct priv *priv = dev->data->dev_private;
- unsigned int i;
- unsigned int idx;
-
- priv_lock(priv);
- for (i = 0; (i != priv->rxqs_n); ++i) {
- if ((*priv->rxqs)[i] == NULL)
- continue;
- idx = (*priv->rxqs)[i]->stats.idx;
- (*priv->rxqs)[i]->stats =
- (struct mlx5_rxq_stats){ .idx = idx };
- }
- for (i = 0; (i != priv->txqs_n); ++i) {
- if ((*priv->txqs)[i] == NULL)
- continue;
- idx = (*priv->txqs)[i]->stats.idx;
- (*priv->txqs)[i]->stats =
- (struct mlx5_txq_stats){ .idx = idx };
- }
-#ifndef MLX5_PMD_SOFT_COUNTERS
- /* FIXME: reset hardware counters. */
-#endif
+ struct mlx5_stats_priv * lps = &priv->m_stats;
+
+ priv_lock(priv);
+
+ if (lps->et_stats == NULL) {
+ mlx5_stats_init(dev);
+ }
+ struct rte_eth_stats tmp = {0};
+
+
+ mlx5_stats_read_hw(dev,&tmp);
+
+ /* copy to shadow */
+ lps->m_shadow = tmp;
+
priv_unlock(priv);
}
diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp
index 84be590f..92cbca6e 100644
--- a/src/flow_stat.cpp
+++ b/src/flow_stat.cpp
@@ -461,6 +461,7 @@ CFlowStatRuleMgr::CFlowStatRuleMgr() {
memset(m_rx_cant_count_err, 0, sizeof(m_rx_cant_count_err));
memset(m_tx_cant_count_err, 0, sizeof(m_tx_cant_count_err));
m_num_ports = 0; // need to call create to init
+ m_mode = FLOW_STAT_MODE_NORMAL;
}
CFlowStatRuleMgr::~CFlowStatRuleMgr() {
@@ -802,11 +803,14 @@ 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));
+ #if 0
// wait to make sure that message is acknowledged. RX core might be in deep sleep mode, and we want to
// start transmitting packets only after it is working, otherwise, packets will get lost.
if (m_rx_core) { // in simulation, m_rx_core will be NULL
@@ -819,6 +823,8 @@ 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)
@@ -966,13 +972,24 @@ 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) {
- msg = new TrexStatelessRxStartMsg();
+ 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 TrexStatelessRxStopMsg();
+ msg = new TrexStatelessRxDisableLatency();
+ m_ring_to_rx->Enqueue((CGenNode *)msg);
}
- m_ring_to_rx->Enqueue((CGenNode *)msg);
}
// return false if no counters changed since last run. true otherwise
diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp
index 7335a6a2..4a6722e6 100644
--- a/src/flow_stat_parser.cpp
+++ b/src/flow_stat_parser.cpp
@@ -27,6 +27,7 @@
#include "common/Network/Packet/TcpHeader.h"
#include "pkt_gen.h"
#include "flow_stat_parser.h"
+#include "bp_sim.h"
void CFlowStatParser::reset() {
m_start = 0;
@@ -120,12 +121,15 @@ int CFlowStatParser::get_ip_id(uint32_t &ip_id) {
int CFlowStatParser::set_ip_id(uint32_t new_id) {
if (m_ipv4) {
// Updating checksum, not recalculating, so if someone put bad checksum on purpose, it will stay bad
+ m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getFirstWord()), PKT_NTOHS(m_ipv4->getFirstWord() |TOS_TTL_RESERVE_DUPLICATE));
m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getId()), PKT_NTOHS(new_id));
m_ipv4->setId(new_id);
+ m_ipv4->setTOS(m_ipv4->getTOS()|TOS_TTL_RESERVE_DUPLICATE);
return 0;
}
if (m_ipv6) {
+ m_ipv6->setTrafficClass(m_ipv6->getTrafficClass()|TOS_TTL_RESERVE_DUPLICATE);
m_ipv6->setFlowLabel(new_id);
return 0;
}
diff --git a/src/gtest/client_cfg_test.cpp b/src/gtest/client_cfg_test.cpp
new file mode 100644
index 00000000..4e93f3c5
--- /dev/null
+++ b/src/gtest/client_cfg_test.cpp
@@ -0,0 +1,186 @@
+/*
+ Ido Barnea
+
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016-2016 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.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include <stdio.h>
+#include "../bp_sim.h"
+#include <common/gtest.h>
+#include <common/basic_utils.h>
+
+class basic_client_cfg : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+ public:
+};
+
+TEST_F(basic_client_cfg, test1) {
+ uint32_t ip_start = 0x10010101;
+ uint32_t ip_end = 0x100101ff;
+ uint32_t next_hop_init = 0x01010101;
+ uint32_t next_hop_resp = 0x02020202;
+ uint16_t vlan_init = 5;
+ uint16_t vlan_resp = 7;
+ uint32_t dual_if_mask = 0x01000000;
+ uint32_t test_count = 2;
+ ClientCfgDB cfg_db;
+ ClientCfgDB test_db;
+ ClientCfgEntry cfg_ent;
+ ClientCfgExt cfg_ext;
+ std::vector<ClientCfgCompactEntry *> ent_list;
+ struct CTupleGenPoolYaml c_pool;
+
+ // Create tuple gen, so we can have ip->port translation
+ CTupleGenYamlInfo tg_yam_info;
+ struct CTupleGenPoolYaml s_pool;
+ s_pool.m_ip_start = ip_start;
+ s_pool.m_ip_end = ip_end;
+ s_pool.m_dual_interface_mask = dual_if_mask;
+ tg_yam_info.m_client_pool.push_back(s_pool);
+
+ CGlobalInfo::m_options.m_expected_portd = 4;
+ printf("Expected ports %d\n", CGlobalInfo::m_options.m_expected_portd);
+
+ std::string tmp_file_name = "client_cfg_gtest_GENERATED.yaml";
+ FILE *fd = fopen(tmp_file_name.c_str(), "w");
+
+ if (fd == NULL) {
+ fprintf(stderr, "Failed opening %s file for write\n", tmp_file_name.c_str());
+ }
+
+ // We create config file with 3 groups (Should match 6 ports).
+ cfg_ext.m_initiator.set_next_hop(next_hop_init);
+ cfg_ext.m_responder.set_next_hop(next_hop_resp);
+ cfg_ext.m_initiator.set_vlan(vlan_init);
+ cfg_ext.m_responder.set_vlan(vlan_resp);
+
+ cfg_ent.set_params(ip_start, ip_end, test_count);
+ cfg_ent.set_cfg(cfg_ext);
+
+ // first group
+ cfg_db.set_vlan(true);
+ cfg_db.add_group(ip_start, cfg_ent);
+
+ //second group
+ cfg_ent.set_params(ip_start + dual_if_mask, ip_end + dual_if_mask
+ , test_count);
+ cfg_db.add_group(ip_start + dual_if_mask, cfg_ent);
+
+ // third group
+ cfg_ent.set_params(ip_start + 2 * dual_if_mask, ip_end + 2 * dual_if_mask
+ , test_count);
+ cfg_db.add_group(ip_start + dual_if_mask * 2, cfg_ent);
+
+ cfg_db.dump(fd);
+ fclose(fd);
+ test_db.load_yaml_file(tmp_file_name);
+ test_db.set_tuple_gen_info(&tg_yam_info);
+ test_db.get_entry_list(ent_list);
+
+
+ // We expect ports for first two groups to be found.
+ // This group addresses should not appear in the list, since
+ // we simulate system with only 4 ports
+ int i = 0;
+ for (std::vector<ClientCfgCompactEntry *>::iterator
+ it = ent_list.begin(); it != ent_list.end(); it++) {
+ uint8_t port = (*it)->get_port();
+ uint16_t vlan = (*it)->get_vlan();
+ uint32_t count = (*it)->get_count();
+ uint32_t dst_ip = (*it)->get_dst_ip();
+
+ assert(count == test_count);
+ switch(i) {
+ case 0:
+ case 2:
+ assert(port == i);
+ assert(vlan == vlan_init);
+ assert(dst_ip == next_hop_init);
+ break;
+ case 1:
+ case 3:
+ assert(port == i);
+ assert(vlan == vlan_resp);
+ assert(dst_ip == next_hop_resp);
+ break;
+ default:
+ fprintf(stderr, "Test failed. Too many entries returned\n");
+ exit(1);
+ }
+ i++;
+ delete *it;
+ }
+
+ // Simulate the pre test phase, and hand results to client config
+ CManyIPInfo many_ip;
+ MacAddress mac0, mac1, mac2, mac3;
+ mac0.set(0x0, 0x1, 0x2, 0x3, 0x4, 0);
+ mac1.set(0x0, 0x1, 0x2, 0x3, 0x4, 0x1);
+ mac2.set(0x0, 0x1, 0x2, 0x3, 0x4, 0x2);
+ mac3.set(0x0, 0x1, 0x2, 0x3, 0x4, 0x3);
+ COneIPv4Info ip0_1(next_hop_init, vlan_init, mac0, 0);
+ COneIPv4Info ip0_2(next_hop_init + 1, vlan_init, mac1, 0);
+ COneIPv4Info ip1_1(next_hop_resp, vlan_resp, mac2, 1);
+ COneIPv4Info ip1_2(next_hop_resp + 1, vlan_resp, mac3, 1);
+
+ many_ip.insert(ip0_1);
+ many_ip.insert(ip0_2);
+ many_ip.insert(ip1_1);
+ many_ip.insert(ip1_2);
+
+ test_db.set_resolved_macs(many_ip);
+
+ ClientCfgBase cfg0;
+
+ ClientCfgEntry *ent0 = test_db.lookup(ip_start);
+ ClientCfgEntry *ent1 = test_db.lookup(ip_start + dual_if_mask);
+
+ assert (ent0 != NULL);
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac0.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac1.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac2.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent0->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac3.GetConstBuffer(), ETHER_ADDR_LEN));
+
+ assert(ent1 != NULL);
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac0.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_initiator.get_dst_mac_addr()
+ , mac1.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac2.GetConstBuffer(), ETHER_ADDR_LEN));
+ ent1->assign(cfg0);
+ assert (!memcmp(cfg0.m_responder.get_dst_mac_addr()
+ , mac3.GetConstBuffer(), ETHER_ADDR_LEN));
+
+}
+
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
index 09942c57..2593261f 100644
--- a/src/gtest/trex_stateless_gtest.cpp
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -4340,6 +4340,7 @@ TEST_F(basic_stl, pcap_remote_basic) {
0,
"exp/remote_test.cap",
10,
+ 0,
1,
1,
-1,
@@ -4363,6 +4364,7 @@ TEST_F(basic_stl, pcap_remote_loop) {
0,
"exp/remote_test.cap",
1,
+ 0,
1,
3,
-1,
@@ -4385,6 +4387,7 @@ TEST_F(basic_stl, pcap_remote_duration) {
0,
"exp/remote_test.cap",
100000,
+ 0,
1,
0,
0.5,
@@ -4407,6 +4410,7 @@ TEST_F(basic_stl, pcap_remote_dual) {
0,
"exp/remote_test_dual.erf",
10000,
+ 0,
1,
0,
0.5,
diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h
index 631f9a3e..5723503c 100644
--- a/src/internal_api/trex_platform_api.h
+++ b/src/internal_api/trex_platform_api.h
@@ -28,6 +28,7 @@ limitations under the License.
#include <string.h>
#include "flow_stat_parser.h"
#include "trex_defs.h"
+#include "trex_stateless_rx_defs.h"
#include "trex_port_attr.h"
#include <json/json.h>
@@ -112,19 +113,13 @@ public:
IF_STAT_RX_BYTES_COUNT = 8, // Card support counting rx bytes
};
- struct mac_cfg_st {
- uint8_t hw_macaddr[6];
- uint8_t src_macaddr[6];
- uint8_t dst_macaddr[6];
- };
-
/**
* interface static info
*
*/
struct intf_info_st {
std::string driver_name;
- mac_cfg_st mac_info;
+ uint8_t hw_macaddr[6];
std::string pci_addr;
int numa_node;
bool has_crc;
@@ -234,7 +229,7 @@ public:
info.has_crc = true;
info.numa_node = 0;
- memset(&info.mac_info, 0, sizeof(info.mac_info));
+ memset(&info.hw_macaddr, 0, sizeof(info.hw_macaddr));
}
virtual void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const {
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 16fc2203..f8f365c8 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -96,6 +96,7 @@ extern "C" {
#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
@@ -147,7 +148,7 @@ public:
}
virtual int configure_rx_filter_rules(CPhyEthIF * _if)=0;
virtual int add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint16_t l3, uint8_t l4
- , uint8_t ipv6_next_h, uint16_t id) {return -1;};
+ , uint8_t ipv6_next_h, uint16_t id) {return 0;}
virtual bool is_hardware_support_drop_queue(){
return(false);
}
@@ -168,14 +169,24 @@ public:
virtual CFlowStatParser *get_flow_stat_parser();
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on)=0;
virtual TRexPortAttr * create_port_attr(uint8_t port_id) = 0;
+ virtual uint8_t get_num_crc_fix_bytes() {return 0;}
- /* Does this NIC type support automatic packet dropping in case of a link down?
+ /* Does this NIC type support automatic packet dropping in case of a link down?
in case it is supported the packets will be dropped, else there would be a back pressure to tx queues
- this interface is used as a workaround to let TRex work without link in stateless mode, driver that
+ this interface is used as a workaround to let TRex work without link in stateless mode, driver that
does not support that will be failed at init time because it will cause watchdog due to watchdog hang */
virtual bool drop_packets_incase_of_linkdown() {
return (false);
}
+
+ /* 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);
+ }
+
};
@@ -277,6 +288,18 @@ public:
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on) {return 0;}
};
+class CTRexExtendedDriverBaseE1000 : public CTRexExtendedDriverBase1GVm {
+ CTRexExtendedDriverBaseE1000() {
+ // E1000 driver is only relevant in VM in our case
+ CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true);
+ }
+public:
+ static CTRexExtendedDriverBase * create() {
+ return ( new CTRexExtendedDriverBaseE1000() );
+ }
+ // e1000 driver handing us packets with ethernet CRC, so we need to chop them
+ virtual uint8_t get_num_crc_fix_bytes() {return 4;}
+};
class CTRexExtendedDriverBase10G : public CTRexExtendedDriverBase {
public:
@@ -316,7 +339,8 @@ public:
| TrexPlatformApi::IF_STAT_PAYLOAD;
}
virtual CFlowStatParser *get_flow_stat_parser();
- virtual int set_rcv_all(CPhyEthIF * _if, bool set_on) {return 0;}
+ int add_del_eth_filter(CPhyEthIF * _if, bool is_add, uint16_t ethertype);
+ virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
};
class CTRexExtendedDriverBase40G : public CTRexExtendedDriverBase10G {
@@ -367,7 +391,7 @@ public:
private:
virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint8_t ttl
- , uint16_t ip_id, uint16_t l4_proto, int queue, uint16_t stat_idx);
+ , uint16_t ip_id, uint8_t l4_proto, int queue, uint16_t stat_idx);
virtual int add_del_eth_type_rule(uint8_t port_id, enum rte_filter_op op, uint16_t eth_type);
virtual int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
@@ -379,7 +403,7 @@ private:
uint8_t m_if_per_card;
};
-class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase40G {
+class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase {
public:
CTRexExtendedDriverBaseVIC(){
}
@@ -393,15 +417,101 @@ public:
}
virtual bool is_hardware_filter_is_supported(){
- return (false);
+ return (true);
+ }
+ virtual void update_global_config_fdir(port_cfg_t * cfg){
}
- virtual int verify_fw_ver(int i) {return 0;}
+
+ virtual bool is_hardware_support_drop_queue(){
+ return(true);
+ }
+
+ void clear_extended_stats(CPhyEthIF * _if);
+
+ void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
+
+
+ virtual int get_min_sample_rate(void){
+ return (RX_CHECK_MIX_SAMPLE_RATE);
+ }
+
+ virtual int verify_fw_ver(int i);
virtual void update_configuration(port_cfg_t * cfg);
+
+ virtual int configure_rx_filter_rules(CPhyEthIF * _if);
+ virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len);
+ virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max);
+ virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
+ virtual int get_rx_stat_capabilities() {
+ return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
+ }
+ virtual CFlowStatParser *get_flow_stat_parser();
+ virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
+ virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
+
+private:
+
+ virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint16_t id
+ , uint8_t l4_proto, uint8_t tos, int queue);
+ virtual int add_del_eth_type_rule(uint8_t port_id, enum rte_filter_op op, uint16_t eth_type);
+ virtual int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
+
};
+class CTRexExtendedDriverBaseMlnx5G : public CTRexExtendedDriverBase10G {
+public:
+ CTRexExtendedDriverBaseMlnx5G(){
+ }
+
+ TRexPortAttr * create_port_attr(uint8_t port_id) {
+ // disabling flow control on 40G using DPDK API causes the interface to malfunction
+ return new DpdkTRexPortAttr(port_id, false, false);
+ }
+
+ static CTRexExtendedDriverBase * create(){
+ return ( new CTRexExtendedDriverBaseMlnx5G() );
+ }
+
+ virtual void update_global_config_fdir(port_cfg_t * cfg){
+ }
+
+ virtual void update_configuration(port_cfg_t * cfg);
+
+ virtual int configure_rx_filter_rules(CPhyEthIF * _if);
+ virtual bool is_hardware_filter_is_supported(){
+ return (true);
+ }
+
+ virtual bool is_hardware_support_drop_queue(){
+ return(true);
+ }
+ virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
+ virtual void clear_extended_stats(CPhyEthIF * _if);
+ virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len);
+ virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max);
+ virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
+ virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
+ virtual int get_rx_stat_capabilities() {
+ return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
+ }
+ virtual int wait_for_stable_link();
+ // disabling flow control on 40G using DPDK API causes the interface to malfunction
+ virtual bool flow_control_disable_supported(){return false;}
+ 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);
+ virtual int add_del_rx_filter_rules(CPhyEthIF * _if, bool set_on);
+};
typedef CTRexExtendedDriverBase * (*create_object_t) (void);
@@ -453,9 +563,11 @@ private:
register_driver(std::string("rte_igb_pmd"),CTRexExtendedDriverBase1G::create);
register_driver(std::string("rte_i40e_pmd"),CTRexExtendedDriverBase40G::create);
register_driver(std::string("rte_enic_pmd"),CTRexExtendedDriverBaseVIC::create);
+ register_driver(std::string("librte_pmd_mlx5"),CTRexExtendedDriverBaseMlnx5G::create);
+
/* virtual devices */
- register_driver(std::string("rte_em_pmd"),CTRexExtendedDriverBase1GVm::create);
+ register_driver(std::string("rte_em_pmd"),CTRexExtendedDriverBaseE1000::create);
register_driver(std::string("rte_vmxnet3_pmd"),CTRexExtendedDriverBase1GVm::create);
register_driver(std::string("rte_virtio_pmd"),CTRexExtendedDriverBase1GVm::create);
@@ -746,6 +858,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
bool latency_was_set=false;
(void)latency_was_set;
char ** rgpszArg = NULL;
+ bool opt_vlan_was_set = false;
int a=0;
int node_dump=0;
@@ -836,9 +949,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->preview.set_disable_flow_control_setting(true);
break;
case OPT_VLAN:
- if ( get_is_stateless() ) {
- po->preview.set_vlan_mode_enable(true);
- }
+ opt_vlan_was_set = true;
break;
case OPT_LIMT_NUM_OF_PORTS :
po->m_expected_portd =atoi(args.OptionArg());
@@ -872,7 +983,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
}
}
if (po->m_run_mode != CParserOption::RUN_MODE_INVALID) {
- parse_err("Please specify single run mode");
+ parse_err("Please specify single run mode (-i for stateless, or -f <file> for stateful");
}
po->m_run_mode = CParserOption::RUN_MODE_DUMP_INFO;
break;
@@ -969,16 +1080,16 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
if ((po->m_run_mode == CParserOption::RUN_MODE_INVALID) ) {
- parse_err("Please provide single run mode (e.g. batch or interactive)");
+ parse_err("Please provide single run mode. -f <file> for stateful or -i for stateless (interactive)");
}
if (CGlobalInfo::is_learn_mode() && po->preview.get_ipv6_mode_enable()) {
- parse_err("--learn mode is not supported with --ipv6, beacuse there is not such thing NAT66 ( ipv6-ipv6) \n" \
- "if you think it is important,open a defect \n");
+ parse_err("--learn mode is not supported with --ipv6, beacuse there is no such thing as NAT66 (ipv6 to ipv6 translation) \n" \
+ "If you think it is important, please open a defect or write to TRex mailing list\n");
}
if (po->preview.get_is_rx_check_enable() || po->is_latency_enabled() || CGlobalInfo::is_learn_mode()
- || (CGlobalInfo::m_options.m_arp_ref_per != 0)) {
+ || (CGlobalInfo::m_options.m_arp_ref_per != 0) || get_vm_one_queue_enable()) {
po->set_rx_enabled();
}
@@ -991,7 +1102,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
uint32_t cores=po->preview.getCores();
if ( cores > ((BP_MAX_CORES)/2-1) ) {
- printf(" ERROR maximum supported cores are : %d \n",((BP_MAX_CORES)/2-1));
+ fprintf(stderr, " Error: maximum supported core number is: %d \n",((BP_MAX_CORES)/2-1));
return -1;
}
@@ -1000,7 +1111,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
/* only first time read the configuration file */
if ( po->platform_cfg_file.length() >0 ) {
if ( node_dump ){
- printf("Loading platform configuration file from %s \n",po->platform_cfg_file.c_str());
+ printf("Using configuration file %s \n",po->platform_cfg_file.c_str());
}
global_platform_cfg_info.load_from_yaml_file(po->platform_cfg_file);
if ( node_dump ){
@@ -1008,7 +1119,9 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
}
}else{
if ( utl_is_file_exists("/etc/trex_cfg.yaml") ){
- printf("found configuration file at /etc/trex_cfg.yaml \n");
+ if ( node_dump ){
+ printf("Using configuration file /etc/trex_cfg.yaml \n");
+ }
global_platform_cfg_info.load_from_yaml_file("/etc/trex_cfg.yaml");
if ( node_dump ){
global_platform_cfg_info.Dump(stdout);
@@ -1018,20 +1131,26 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
}
if ( get_is_stateless() ) {
+ if ( opt_vlan_was_set ) {
+ po->preview.set_vlan_mode_enable(true);
+ }
+ if (CGlobalInfo::m_options.client_cfg_file != "") {
+ parse_err("Client config file is not supported with interactive (stateless) mode ");
+ }
if ( po->m_duration ) {
- parse_err("Duration is not supported with interactive mode ");
+ parse_err("Duration is not supported with interactive (stateless) mode ");
}
if ( po->preview.get_is_rx_check_enable() ) {
- parse_err("Rx check is not supported with interactive mode ");
+ parse_err("Rx check is not supported with interactive (stateless) mode ");
}
if ( (po->is_latency_enabled()) || (po->preview.getOnlyLatency()) ){
- parse_err("Latency check is not supported with interactive mode ");
+ parse_err("Latency check is not supported with interactive (stateless) mode ");
}
if ( po->preview.getSingleCore() ){
- parse_err("Single core is not supported with interactive mode ");
+ parse_err("Single core is not supported with interactive (stateless) mode ");
}
}
@@ -1519,6 +1638,7 @@ int DpdkTRexPortAttr::set_led(bool on){
int DpdkTRexPortAttr::get_flow_ctrl(int &mode) {
int ret = rte_eth_dev_flow_ctrl_get(m_port_id, &fc_conf_tmp);
if (ret) {
+ mode = -1;
return ret;
}
mode = (int) fc_conf_tmp.mode;
@@ -1615,12 +1735,19 @@ bool DpdkTRexPortAttr::update_link_status_nowait(){
rte_eth_link new_link;
bool changed = false;
rte_eth_link_get_nowait(m_port_id, &new_link);
+
if (new_link.link_speed != m_link.link_speed ||
new_link.link_duplex != m_link.link_duplex ||
new_link.link_autoneg != m_link.link_autoneg ||
new_link.link_status != m_link.link_status) {
changed = true;
+
+ /* in case of link status change - notify the dest object */
+ if (new_link.link_status != m_link.link_status) {
+ get_dest().on_link_down();
+ }
}
+
m_link = new_link;
return changed;
}
@@ -1662,7 +1789,7 @@ bool DpdkTRexPortAttr::get_promiscuous(){
}
-void DpdkTRexPortAttr::macaddr_get(struct ether_addr *mac_addr){
+void DpdkTRexPortAttr::get_hw_src_mac(struct ether_addr *mac_addr){
rte_eth_macaddr_get(m_port_id , mac_addr);
}
@@ -1853,10 +1980,9 @@ public:
virtual int send_node(CGenNode * node);
virtual void send_one_pkt(pkt_dir_t dir, rte_mbuf_t *m);
virtual int flush_tx_queue(void);
- __attribute__ ((noinline)) void handle_rx_queue();
__attribute__ ((noinline)) void handle_slowpath_features(CGenNode *node, rte_mbuf_t *m, uint8_t *p, pkt_dir_t dir);
- void apply_client_cfg(const ClientCfg *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p);
+ void apply_client_cfg(const ClientCfgBase *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p);
bool process_rx_pkt(pkt_dir_t dir,rte_mbuf_t * m);
@@ -1929,46 +2055,6 @@ bool CCoreEthIF::Create(uint8_t core_id,
return (true);
}
-// This function is only relevant if we are in VM. In this case, we only have one rx queue. Can't have
-// rules to drop queue 0 packets, and pass queue 1 packets to RX core, like in other cases.
-// We receive all packets in the same core that transmitted, and handle them to RX core.
-void CCoreEthIF::handle_rx_queue(void) {
- if ( likely( ! get_vm_one_queue_enable() ) ) {
- return;
- }
-
- pkt_dir_t dir;
- bool is_rx = get_is_rx_thread_enabled();
- for (dir=CLIENT_SIDE; dir<CS_NUM; dir++) {
- CCorePerPort * lp_port=&m_ports[dir];
- CPhyEthIF * lp=lp_port->m_port;
-
- rte_mbuf_t * rx_pkts[32];
- int j=0;
-
- while (true) {
- j++;
- uint16_t cnt =lp->rx_burst(0,rx_pkts,32);
- if ( cnt ) {
- int i;
- for (i=0; i<(int)cnt;i++) {
- rte_mbuf_t * m=rx_pkts[i];
- if ( is_rx ){
- if (!process_rx_pkt(dir,m)){
- rte_pktmbuf_free(m);
- }
- }else{
- rte_pktmbuf_free(m);
- }
- }
- }
- if ((cnt<5) || j>10 ) {
- break;
- }
- }
- }
-}
-
int CCoreEthIF::flush_tx_queue(void){
/* flush both sides */
pkt_dir_t dir;
@@ -1981,8 +2067,6 @@ int CCoreEthIF::flush_tx_queue(void){
}
}
- handle_rx_queue();
-
return 0;
}
@@ -2247,12 +2331,12 @@ int CCoreEthIFStateless::handle_slow_path_node(CGenNode * no) {
return (-1);
}
-void CCoreEthIF::apply_client_cfg(const ClientCfg *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p) {
+void CCoreEthIF::apply_client_cfg(const ClientCfgBase *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p) {
assert(cfg);
/* take the right direction config */
- const ClientCfgDir &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
+ const ClientCfgDirBase &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
/* dst mac */
if (cfg_dir.has_dst_mac_addr()) {
@@ -2472,10 +2556,11 @@ private:
class CLatencyVmPort : public CPortLatencyHWBase {
public:
void Create(uint8_t port_index,CNodeRing * ring,
- CLatencyManager * mgr){
+ 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){
@@ -2502,17 +2587,23 @@ public:
return (-1);
}
- virtual rte_mbuf_t * rx(){
- return (0);
+ virtual rte_mbuf_t * rx() {
+ rte_mbuf_t * rx_pkts[1];
+ uint16_t cnt = m_port->rx_burst(0, rx_pkts, 1);
+ if (cnt) {
+ return (rx_pkts[0]);
+ } else {
+ return (0);
+ }
}
- virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts,
- uint16_t nb_pkts){
- return (0);
+ virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, uint16_t nb_pkts) {
+ uint16_t cnt = m_port->rx_burst(0, rx_pkts, nb_pkts);
+ return (cnt);
}
-
private:
+ CPhyEthIF * m_port;
uint8_t m_dir;
CNodeRing * m_ring_to_dp; /* ring dp -> latency thread */
CLatencyManager * m_mgr;
@@ -2538,6 +2629,8 @@ public:
float m_total_rx_pps;
float m_cpu_util;
+ bool m_link_up = true;
+ bool m_link_was_down = false;
};
class CGlobalStats {
@@ -2808,8 +2901,11 @@ void CGlobalStats::Dump(FILE *fd,DumpFormat mode){
fprintf (fd," --------------- \n");
for (i=0; i<(int)port_to_show; i++) {
CPerPortStats * lp=&m_port[i];
- fprintf(fd,"port : %d \n",(int)i);
- fprintf(fd,"------------\n");
+ fprintf(fd,"port : %d ",(int)i);
+ if ( ! lp->m_link_up ) {
+ fprintf(fd," (link DOWN)");
+ }
+ fprintf(fd,"\n------------\n");
#define GS_DP_A4(f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)lp->f)
#define GS_DP_A(f) if (lp->f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)lp->f)
GS_DP_A4(opackets);
@@ -2823,7 +2919,13 @@ void CGlobalStats::Dump(FILE *fd,DumpFormat mode){
}else{
fprintf(fd," %10s ","ports");
for (i=0; i<(int)port_to_show; i++) {
- fprintf(fd,"| %15d ",i);
+ CPerPortStats * lp=&m_port[i];
+ if ( lp->m_link_up ) {
+ fprintf(fd,"| %15d ",i);
+ } else {
+ std::string port_with_state = "(link DOWN) " + std::to_string(i);
+ fprintf(fd,"| %15s ",port_with_state.c_str());
+ }
}
fprintf(fd,"\n");
fprintf(fd," -----------------------------------------------------------------------------------------\n");
@@ -3015,14 +3117,16 @@ public:
void dump_config(FILE *fd);
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 */
uint32_t m_max_cores; /* current number of cores , include master and latency ==> ( master)1+c*(m_max_ports>>1)+1( latency ) */
uint32_t m_cores_mul; /* how cores multipler given c=4 ==> m_cores_mul */
- uint32_t m_max_queues_per_port;
- uint32_t m_cores_to_dual_ports; /* number of ports that will handle dual ports */
- uint16_t m_latency_tx_queue_id;
+ uint32_t m_max_queues_per_port; // Number of TX queues per port
+ uint32_t m_cores_to_dual_ports; /* number of TX cores allocated for each port pair */
+ uint16_t m_rx_core_tx_q_id; /* TX q used by rx core */
// statistic
CPPSMeasure m_cps;
float m_expected_pps;
@@ -3067,64 +3171,195 @@ void CGlobalTRex::pre_test() {
CPretest pretest(m_max_ports);
bool resolve_needed = false;
uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
+ bool need_grat_arp[TREX_MAX_PORTS];
+
+ if (CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
+ std::vector<ClientCfgCompactEntry *> conf;
+ m_fl.get_client_cfg_ip_list(conf);
+
+ // If we got src MAC for port in global config, take it, otherwise use src MAC from DPDK
+ uint8_t port_macs[m_max_ports][ETHER_ADDR_LEN];
+ for (int port_id = 0; port_id < m_max_ports; port_id++) {
+ memcpy(port_macs[port_id], CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, ETHER_ADDR_LEN);
+ }
+
+ for (std::vector<ClientCfgCompactEntry *>::iterator it = conf.begin(); it != conf.end(); it++) {
+ uint8_t port = (*it)->get_port();
+ uint16_t vlan = (*it)->get_vlan();
+ uint32_t count = (*it)->get_count();
+ uint32_t dst_ip = (*it)->get_dst_ip();
+ uint32_t src_ip = (*it)->get_src_ip();
+
+ for (int i = 0; i < count; i++) {
+ //??? handle ipv6;
+ if ((*it)->is_ipv4()) {
+ pretest.add_next_hop(port, dst_ip + i, vlan);
+ }
+ }
+ if (!src_ip) {
+ src_ip = CGlobalInfo::m_options.m_ip_cfg[port].get_ip();
+ if (!src_ip) {
+ fprintf(stderr, "No matching src ip for port: %d ip:%s vlan: %d\n"
+ , port, ip_to_str(dst_ip).c_str(), vlan);
+ fprintf(stderr, "You must specify src_ip in client config file or in TRex config file\n");
+ exit(1);
+ }
+ }
+ pretest.add_ip(port, src_ip, vlan, port_macs[port]);
+ COneIPv4Info ipv4(src_ip, vlan, port_macs[port], port);
+ m_mg.add_grat_arp_src(ipv4);
+
+ delete *it;
+ }
+ if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
+ fprintf(stdout, "*******Pretest for client cfg********\n");
+ pretest.dump(stdout);
+ }
+ } else {
+ for (int port_id = 0; port_id < m_max_ports; port_id++) {
+ if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
+ resolve_needed = true;
+ } 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);
+
+ if (resolve_needed) {
+ pretest.add_next_hop(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw()
+ , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan());
+ }
+ }
+ }
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);
- if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
- resolve_needed = true;
- } else {
- resolve_needed = false;
- }
- if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
- rte_eth_macaddr_get(port_id,
- (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
- CGlobalInfo::m_options.m_ip_cfg[port_id].set_grat_arp_needed(true);
- } else {
- // If we got src MAC from config file, do not send gratuitous ARP for it (for compatibility with old behaviour)
- CGlobalInfo::m_options.m_ip_cfg[port_id].set_grat_arp_needed(false);
- }
- pretest.set_port_params(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id]
- , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src
- , resolve_needed);
}
+
pretest.send_grat_arp_all();
bool ret;
int count = 0;
+ bool resolve_failed = false;
do {
ret = pretest.resolve_all();
count++;
} while ((ret != true) && (count < 10));
+ if (ret != true) {
+ resolve_failed = true;
+ }
- if ( CGlobalInfo::m_options.preview.getVMode() > 0) {
+ if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
+ fprintf(stdout, "*******Pretest after resolving ********\n");
pretest.dump(stdout);
}
- uint8_t mac[ETHER_ADDR_LEN];
- for (int port_id = 0; port_id < m_max_ports; port_id++) {
- if (! memcmp(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
- // we don't have dest MAC. Get it from what we resolved.
- uint32_t ip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
- if (! pretest.get_mac(port_id, ip, mac)) {
- fprintf(stderr, "Failed resolving dest MAC for default gateway:%d.%d.%d.%d on port %d\n"
- , (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF, port_id);
- exit(1);
+
+ if (CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
+ CManyIPInfo pretest_result;
+ pretest.get_results(pretest_result);
+ if (resolve_failed) {
+ fprintf(stderr, "Resolution of following IPs failed. Exiting.\n");
+ for (const COneIPInfo *ip=pretest_result.get_next(); ip != NULL;
+ ip = pretest_result.get_next()) {
+ if (ip->resolve_needed()) {
+ ip->dump(stderr, " ");
+ }
}
- memcpy(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, mac, ETHER_ADDR_LEN);
- // if port is connected in loopback, no need to send gratuitous ARP. It will only confuse our ingress counters.
- if (pretest.is_loopback(port_id))
- CGlobalInfo::m_options.m_ip_cfg[port_id].set_grat_arp_needed(false);
+ exit(1);
+ }
+ m_fl.set_client_config_resolved_macs(pretest_result);
+ if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
+ m_fl.dump_client_config(stdout);
}
- // update statistics baseline, so we can ignore what happened in pre test phase
- CPhyEthIF *pif = &m_ports[port_id];
- CPreTestStats pre_stats = pretest.get_stats(port_id);
- pif->set_ignore_stats_base(pre_stats);
+ bool port_found[TREX_MAX_PORTS];
+ for (int port_id = 0; port_id < m_max_ports; port_id++) {
+ port_found[port_id] = false;
+ }
+ // If client config enabled, we don't resolve MACs from trex_cfg.yaml. For latency (-l)
+ // We need to able to send packets from RX core, so need to configure MAC/vlan for each port.
+ for (const COneIPInfo *ip=pretest_result.get_next(); ip != NULL; ip = pretest_result.get_next()) {
+ // Use first MAC/vlan we see on each port
+ uint8_t port_id = ip->get_port();
+ uint16_t vlan = ip->get_vlan();
+ if ( ! port_found[port_id]) {
+ port_found[port_id] = true;
+ ip->get_mac(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest);
+ CGlobalInfo::m_options.m_ip_cfg[port_id].set_vlan(vlan);
+ }
+ }
+ } else {
+ uint8_t mac[ETHER_ADDR_LEN];
+ for (int port_id = 0; port_id < m_max_ports; port_id++) {
+ if (! memcmp(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
+ // we don't have dest MAC. Get it from what we resolved.
+ uint32_t ip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
+ uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan();
+
+ if (!pretest.get_mac(port_id, ip, vlan, mac)) {
+ fprintf(stderr, "Failed resolving dest MAC for default gateway:%d.%d.%d.%d on port %d\n"
+ , (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF, port_id);
+
+ if (get_is_stateless()) {
+ continue;
+ } else {
+ exit(1);
+ }
+ }
- // Configure port back to normal mode. Only relevant packets handled by software.
- CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, false);
+
+
+ memcpy(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, mac, ETHER_ADDR_LEN);
+ // if port is connected in loopback, no need to send gratuitous ARP. It will only confuse our ingress counters.
+ if (need_grat_arp[port_id] && (! pretest.is_loopback(port_id))) {
+ COneIPv4Info ipv4(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
+ , port_id);
+ m_mg.add_grat_arp_src(ipv4);
+ }
+ }
+
+ // update statistics baseline, so we can ignore what happened in pre test phase
+ 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);
+
+ }
+ }
+
+ /* 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;
+
+ /* L3 mode */
+ if (src_ipv4 && dg) {
+ if (memcmp(dst_mac, empty_mac, 6) == 0) {
+ m_trex_stateless->get_port_by_id(port_id)->set_l3_mode(src_ipv4, dg);
+ } else {
+ m_trex_stateless->get_port_by_id(port_id)->set_l3_mode(src_ipv4, dg, dst_mac);
+ }
+
+ /* L2 mode */
+ } else {
+ m_trex_stateless->get_port_by_id(port_id)->set_l2_mode(dst_mac);
+ }
+ }
}
+
+
}
/**
@@ -3191,12 +3426,14 @@ bool CGlobalTRex::is_all_links_are_up(bool dump){
void CGlobalTRex::try_stop_all_cores(){
TrexStatelessDpQuit * dp_msg= new TrexStatelessDpQuit();
- TrexStatelessRxQuit * rx_msg= new TrexStatelessRxQuit();
send_message_all_dp(dp_msg);
+ delete dp_msg;
+
if (get_is_stateless()) {
+ TrexStatelessRxQuit * rx_msg= new TrexStatelessRxQuit();
send_message_to_rx(rx_msg);
}
- delete dp_msg;
+
// no need to delete rx_msg. Deleted by receiver
bool all_core_finished = false;
int i;
@@ -3246,6 +3483,7 @@ int CGlobalTRex::ixgbe_rx_queue_flush(){
}
+// init stateful rx core
void CGlobalTRex::ixgbe_configure_mg(void) {
int i;
CLatencyManagerCfg mg_cfg;
@@ -3268,13 +3506,13 @@ void CGlobalTRex::ixgbe_configure_mg(void) {
if ( get_vm_one_queue_enable() ) {
/* vm mode, indirect queues */
for (i=0; i<m_max_ports; i++) {
-
+ CPhyEthIF * _if = &m_ports[i];
CMessagingManager * rx_dp=CMsgIns::Ins()->getRxDp();
uint8_t thread_id = (i>>1);
CNodeRing * r = rx_dp->getRingCpToDp(thread_id);
- m_latency_vm_vports[i].Create((uint8_t)i,r,&m_mg);
+ m_latency_vm_vports[i].Create((uint8_t)i, r, &m_mg, _if);
mg_cfg.m_ports[i] =&m_latency_vm_vports[i];
}
@@ -3283,7 +3521,7 @@ void CGlobalTRex::ixgbe_configure_mg(void) {
for (i=0; i<m_max_ports; i++) {
CPhyEthIF * _if=&m_ports[i];
_if->dump_stats(stdout);
- m_latency_vports[i].Create(_if,m_latency_tx_queue_id,1);
+ m_latency_vports[i].Create(_if, m_rx_core_tx_q_id, 1);
mg_cfg.m_ports[i] =&m_latency_vports[i];
}
@@ -3300,20 +3538,22 @@ void CGlobalTRex::rx_sl_configure(void) {
int i;
rx_sl_cfg.m_max_ports = m_max_ports;
+ rx_sl_cfg.m_num_crc_fix_bytes = get_ex_drv()->get_num_crc_fix_bytes();
if ( get_vm_one_queue_enable() ) {
/* vm mode, indirect queues */
for (i=0; i < m_max_ports; i++) {
+ CPhyEthIF * _if = &m_ports[i];
CMessagingManager * rx_dp = CMsgIns::Ins()->getRxDp();
uint8_t thread_id = (i >> 1);
CNodeRing * r = rx_dp->getRingCpToDp(thread_id);
- m_latency_vm_vports[i].Create((uint8_t)i, r, &m_mg);
+ m_latency_vm_vports[i].Create(i, r, &m_mg, _if);
rx_sl_cfg.m_ports[i] = &m_latency_vm_vports[i];
}
} else {
for (i = 0; i < m_max_ports; i++) {
CPhyEthIF * _if = &m_ports[i];
- m_latency_vports[i].Create(_if, m_latency_tx_queue_id, 1);
+ m_latency_vports[i].Create(_if, m_rx_core_tx_q_id, 1);
rx_sl_cfg.m_ports[i] = &m_latency_vports[i];
}
}
@@ -3324,88 +3564,85 @@ 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);
- /* last TX queue if for latency check */
- if ( get_vm_one_queue_enable() ) {
- /* one tx one rx */
+ uint16_t rx_rss = get_ex_drv()->enable_rss_drop_workaround();
+ if ( get_vm_one_queue_enable() ) {
/* VMXNET3 does claim to support 16K but somehow does not work */
/* reduce to 2000 */
m_port_cfg.m_port_conf.rxmode.max_rx_pkt_len = 2000;
-
- _if->configure(1,
- 1,
- &m_port_cfg.m_port_conf);
-
- /* will not be used */
- m_latency_tx_queue_id= m_cores_to_dual_ports;
-
- 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);
-
-
-
+ /* 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);
- _if->rx_queue_setup(0,
- RTE_TEST_RX_DESC_VM_DEFAULT,
- socket_id,
- &m_port_cfg.m_rx_conf,
+ _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.
+ // TX queues: 1 for each core handling the port pair + 1 for latency pkts + 1 for use by RX core
+
+ uint16_t rx_queues;
- int qid;
- for ( qid=0; qid<(m_max_queues_per_port); qid++) {
- _if->tx_queue_setup((uint16_t)qid,
- RTE_TEST_TX_DESC_VM_DEFAULT ,
- socket_id,
- &m_port_cfg.m_tx_conf);
-
+ if (rx_rss==0) {
+ rx_queues=2;
+ }else{
+ rx_queues=rx_rss;
}
- }else{
- _if->configure(2,
- m_cores_to_dual_ports+1,
- &m_port_cfg.m_port_conf);
-
- /* the latency queue for latency measurement packets */
- m_latency_tx_queue_id= m_cores_to_dual_ports;
+ _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;
- 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);
+ 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,
+ socket_id,
+ &m_port_cfg.m_rx_conf,
+ CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
- /* drop queue */
- _if->rx_queue_setup(0,
- 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);
+ }
- /* set the filter queue */
- _if->set_rx_queue(1);
- /* latency measurement ring is 1 */
- _if->rx_queue_setup(1,
+ _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);
- int qid;
- for ( qid=0; qid<(m_max_queues_per_port+1); qid++) {
+ 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->stats_clear();
-
_if->start();
_if->configure_rx_duplicate_rules();
@@ -3430,8 +3667,7 @@ int CGlobalTRex::ixgbe_start(void){
printf(" WARNING : there is no link on one of the ports, driver support auto drop in case of link down - continue\n");
}else{
dump_links_status(stdout);
- rte_exit(EXIT_FAILURE, " "
- " one of the link is down \n");
+ rte_exit(EXIT_FAILURE, " One of the links is down \n");
}
}
} else {
@@ -3444,9 +3680,7 @@ int CGlobalTRex::ixgbe_start(void){
if (! get_is_stateless()) {
ixgbe_configure_mg();
- } else {
- rx_sl_configure();
- }
+ }
/* core 0 - control
@@ -3462,7 +3696,7 @@ int CGlobalTRex::ixgbe_start(void){
if ( get_vm_one_queue_enable() ) {
lat_q_id = 0;
} else {
- lat_q_id = get_cores_tx() / get_base_num_cores();
+ lat_q_id = get_cores_tx() / get_base_num_cores() + 1;
}
for (i=0; i<get_cores_tx(); i++) {
int j=(i+1);
@@ -3487,6 +3721,7 @@ int CGlobalTRex::ixgbe_start(void){
}
fprintf(stdout," -------------------------------\n");
+ fprintf(stdout, "RX core uses TX queue number %d on all ports\n", m_rx_core_tx_q_id);
CCoreEthIF::DumpIfCfgHeader(stdout);
for (i=0; i<get_cores_tx(); i++) {
m_cores_vif[i+1]->DumpIfCfg(stdout);
@@ -3584,13 +3819,22 @@ bool CGlobalTRex::Create(){
cfg.m_publisher = &m_zmq_publisher;
m_trex_stateless = new TrexStateless(cfg);
+
+ rx_sl_configure();
}
return (true);
}
void CGlobalTRex::Delete(){
+
m_zmq_publisher.Delete();
+ m_fl.Delete();
+
+ if (m_trex_stateless) {
+ delete m_trex_stateless;
+ m_trex_stateless = NULL;
+ }
}
@@ -3713,12 +3957,12 @@ int CGlobalTRex::queues_prob_init(){
m_cores_to_dual_ports = 2;
*/
- /* number of queue - 1 per core for dual ports*/
- m_max_queues_per_port = m_cores_to_dual_ports;
+ // One q for each core allowed to send on this port + 1 for latency q (Used in stateless) + 1 for RX core.
+ m_max_queues_per_port = m_cores_to_dual_ports + 2;
if (m_max_queues_per_port > BP_MAX_TX_QUEUE) {
rte_exit(EXIT_FAILURE,
- "maximum number of queue should be maximum %d \n",BP_MAX_TX_QUEUE);
+ "Error: Number of TX queues exceeds %d. Try running with lower -c <val> \n",BP_MAX_TX_QUEUE);
}
assert(m_max_queues_per_port>0);
@@ -3740,6 +3984,16 @@ void CGlobalTRex::dump_links_status(FILE *fd){
}
}
+bool CGlobalTRex::lookup_port_by_mac(const uint8_t *mac, uint8_t &port_id) {
+ for (int i = 0; i < m_max_ports; i++) {
+ if (memcmp(m_ports[i].get_port_attr()->get_src_mac(), mac, 6) == 0) {
+ port_id = i;
+ return true;
+ }
+ }
+
+ return false;
+}
void CGlobalTRex::dump_post_test_stats(FILE *fd){
uint64_t pkt_out=0;
@@ -3789,6 +4043,11 @@ void CGlobalTRex::dump_post_test_stats(FILE *fd){
}
else
fprintf (fd, " Total-pkt-drop : %llu pkts \n", (unsigned long long) (pkt_out - pkt_in));
+ for (i=0; i<m_max_ports; i++) {
+ if ( m_stats.m_port[i].m_link_was_down ) {
+ fprintf (fd, " WARNING: Link was down at port %d during test (at least for some time)!\n", i);
+ }
+ }
fprintf (fd," Total-tx-bytes : %llu bytes \n", (unsigned long long)pkt_out_bytes);
fprintf (fd," Total-tx-sw-bytes : %llu bytes \n", (unsigned long long)sw_pkt_out_bytes);
fprintf (fd," Total-rx-bytes : %llu byte \n", (unsigned long long)pkt_in_bytes);
@@ -3904,6 +4163,8 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){
stp->m_total_tx_pps = _if->get_last_tx_pps_rate();
stp->m_total_rx_bps = _if->get_last_rx_rate()*_1Mb_DOUBLE;
stp->m_total_rx_pps = _if->get_last_rx_pps_rate();
+ stp->m_link_up = _if->get_port_attr()->is_link_up();
+ stp->m_link_was_down |= ! _if->get_port_attr()->is_link_up();
stats.m_total_tx_pkts += st.opackets;
stats.m_total_rx_pkts += st.ipackets;
@@ -4189,16 +4450,7 @@ CGlobalTRex:: publish_async_port_attr_changed(uint8_t port_id) {
data["port_id"] = port_id;
TRexPortAttr * _attr = m_ports[port_id].get_port_attr();
- /* attributes */
- data["attr"]["speed"] = _attr->get_link_speed();
- data["attr"]["promiscuous"]["enabled"] = _attr->get_promiscuous();
- data["attr"]["link"]["up"] = _attr->is_link_up();
- int mode;
- int ret = _attr->get_flow_ctrl(mode);
- if (ret != 0) {
- mode = -1;
- }
- data["attr"]["fc"]["mode"] = mode;
+ _attr->to_json(data["attr"]);
m_zmq_publisher.publish_event(TrexPublisher::EVENT_PORT_ATTR_CHANGED, data);
}
@@ -4270,18 +4522,20 @@ CGlobalTRex::handle_slow_path() {
m_mg.update();
if ( m_io_modes.m_g_mode == CTrexGlobalIoMode::gNORMAL ) {
- switch (m_io_modes.m_l_mode) {
- case CTrexGlobalIoMode::lDISABLE:
- fprintf(stdout,"\n+Latency stats disabled \n");
- break;
- case CTrexGlobalIoMode::lENABLE:
- fprintf(stdout,"\n-Latency stats enabled \n");
- m_mg.DumpShort(stdout);
- break;
- case CTrexGlobalIoMode::lENABLE_Extended:
- fprintf(stdout,"\n-Latency stats extended \n");
- m_mg.Dump(stdout);
- break;
+ if (CGlobalInfo::m_options.m_latency_rate != 0) {
+ switch (m_io_modes.m_l_mode) {
+ case CTrexGlobalIoMode::lDISABLE:
+ fprintf(stdout, "\n+Latency stats disabled \n");
+ break;
+ case CTrexGlobalIoMode::lENABLE:
+ fprintf(stdout, "\n-Latency stats enabled \n");
+ m_mg.DumpShort(stdout);
+ break;
+ case CTrexGlobalIoMode::lENABLE_Extended:
+ fprintf(stdout, "\n-Latency stats extended \n");
+ m_mg.Dump(stdout);
+ break;
+ }
}
if ( get_is_rx_check_mode() ) {
@@ -4400,8 +4654,11 @@ void CGlobalTRex::shutdown() {
for (int i = 0; i < m_max_ports; i++) {
m_ports[i].stop();
}
+
if (m_mark_for_shutdown != SHUTDOWN_TEST_ENDED) {
/* we should stop latency and exit to stop agents */
+ Delete();
+ utl_termio_reset();
exit(-1);
}
}
@@ -4565,7 +4822,6 @@ int CGlobalTRex::stop_master(){
dump_stats(stdout,CGlobalStats::dmpSTANDARD);
dump_post_test_stats(stdout);
- m_fl.Delete();
return (0);
}
@@ -4626,6 +4882,8 @@ int CGlobalTRex::start_master_statefull() {
exit(-1);
}
CGlobalInfo::m_options.preview.set_client_cfg_enable(true);
+ m_fl.set_client_config_tuple_gen_info(&m_fl.m_yaml_info.m_tuple_gen);
+ pre_test();
}
/* verify options */
@@ -4680,10 +4938,67 @@ int CGlobalTRex::start_master_statefull() {
////////////////////////////////////////////
static CGlobalTRex g_trex;
+
+void CPhyEthIF::configure_rss_redirect_table(uint16_t numer_of_queues,
+ uint16_t skip_queue){
+
+
+ struct rte_eth_dev_info dev_info;
+
+ 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++) {
+ uint16_t q;
+ while (true) {
+ q=(i+skip)%numer_of_queues;
+ if (q!=skip_queue) {
+ break;
+ }
+ skip+=1;
+ }
+ reta_conf[j].reta[i]=q;
+ // printf(" %d %d %d \n",j,i,q);
+ }
+ }
+ 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++) {
+ 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;
- g_trex.m_mg.get_ignore_stats(m_port_id, ign_stats, true);
+
+ 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();
@@ -4703,6 +5018,13 @@ bool CPhyEthIF::Create(uint8_t portid) {
m_last_tx_pps = 0.0;
m_port_attr = g_trex.m_drv->create_port_attr(portid);
+ /* set src MAC addr */
+ uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
+ if (! memcmp( CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
+ rte_eth_macaddr_get(m_port_id,
+ (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src);
+ }
+
return true;
}
@@ -5355,7 +5677,10 @@ int main_test(int argc , char * argv[]){
}
}
- g_trex.pre_test();
+ // in case of client config, we already run pretest
+ if (! CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
+ g_trex.pre_test();
+ }
// after doing all needed ARP resolution, we need to flush queues, and stop our drop queue
g_trex.ixgbe_rx_queue_flush();
@@ -5779,6 +6104,7 @@ void CTRexExtendedDriverBase10G::update_configuration(port_cfg_t * cfg){
}
int CTRexExtendedDriverBase10G::configure_rx_filter_rules(CPhyEthIF * _if) {
+ set_rcv_all(_if, false);
if ( get_is_stateless() ) {
return configure_rx_filter_rules_stateless(_if);
} else {
@@ -5809,7 +6135,7 @@ int CTRexExtendedDriverBase10G::configure_rx_filter_rules_stateless(CPhyEthIF *
res = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, RTE_ETH_FILTER_ADD, &fdir_filter);
if (res != 0) {
- rte_exit(EXIT_FAILURE, " ERROR rte_eth_dev_filter_ctrl : %d\n",res);
+ rte_exit(EXIT_FAILURE, "Error: rte_eth_dev_filter_ctrl in configure_rx_filter_rules_stateless: %d\n",res);
}
}
@@ -5878,12 +6204,51 @@ int CTRexExtendedDriverBase10G::configure_rx_filter_rules_statefull(CPhyEthIF *
res = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, RTE_ETH_FILTER_ADD, &fdir_filter);
if (res != 0) {
- rte_exit(EXIT_FAILURE, " ERROR rte_eth_dev_filter_ctrl : %d\n",res);
+ rte_exit(EXIT_FAILURE, "Error: rte_eth_dev_filter_ctrl in configure_rx_filter_rules_statefull: %d\n",res);
}
}
return (0);
}
+int CTRexExtendedDriverBase10G::add_del_eth_filter(CPhyEthIF * _if, bool is_add, uint16_t ethertype) {
+ int res = 0;
+ uint8_t port_id=_if->get_rte_port_id();
+ struct rte_eth_ethertype_filter filter;
+ enum rte_filter_op op;
+
+ memset(&filter, 0, sizeof(filter));
+ filter.ether_type = ethertype;
+ res = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_ETHERTYPE, RTE_ETH_FILTER_GET, &filter);
+
+ if (is_add && (res >= 0))
+ return 0;
+ if ((! is_add) && (res == -ENOENT))
+ return 0;
+
+ if (is_add) {
+ op = RTE_ETH_FILTER_ADD;
+ } else {
+ op = RTE_ETH_FILTER_DELETE;
+ }
+
+ filter.queue = 1;
+ res = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_ETHERTYPE, op, &filter);
+ if (res != 0) {
+ printf("Error: %s L2 filter for ethertype 0x%04x returned %d\n", is_add ? "Adding":"Deleting", ethertype, res);
+ exit(1);
+ }
+ return 0;
+}
+
+int CTRexExtendedDriverBase10G::set_rcv_all(CPhyEthIF * _if, bool set_on) {
+ int res = 0;
+ res = add_del_eth_filter(_if, set_on, ETHER_TYPE_ARP);
+ res |= add_del_eth_filter(_if, set_on, ETHER_TYPE_IPv4);
+ res |= add_del_eth_filter(_if, set_on, ETHER_TYPE_IPv6);
+
+ return res;
+}
+
void CTRexExtendedDriverBase10G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){
int i;
@@ -5937,12 +6302,6 @@ void CTRexExtendedDriverBase40G::clear_extended_stats(CPhyEthIF * _if){
rte_eth_stats_reset(_if->get_port_id());
}
-void CTRexExtendedDriverBaseVIC::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->m_port_conf.rxmode.max_rx_pkt_len =9*1000-10;
-}
void CTRexExtendedDriverBase40G::update_configuration(port_cfg_t * cfg){
cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH;
@@ -5954,7 +6313,7 @@ void CTRexExtendedDriverBase40G::update_configuration(port_cfg_t * cfg){
// What is the type of the rule the respective hw_id counter counts.
struct fdir_hw_id_params_t {
uint16_t rule_type;
- uint16_t l4_proto;
+ uint8_t l4_proto;
};
static struct fdir_hw_id_params_t fdir_hw_id_rule_params[512];
@@ -5963,7 +6322,7 @@ static struct fdir_hw_id_params_t fdir_hw_id_rule_params[512];
// ttl is used in statefull mode, and ip_id in stateless. We configure the driver registers so that only one of them applies.
// 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, uint16_t l4_proto, int queue, uint16_t stat_idx) {
+ , uint16_t ip_id, uint8_t l4_proto, int queue, uint16_t stat_idx) {
int ret=rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
static int filter_soft_id = 0;
@@ -6114,11 +6473,11 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if) {
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 0
, FLOW_STAT_PAYLOAD_IP_ID, IPPROTO_ICMP, MAIN_DPDK_RX_Q, FDIR_PAYLOAD_RULES_HW_ID);
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, 0
- , FLOW_STAT_PAYLOAD_IP_ID, 0, MAIN_DPDK_RX_Q, 0);
+ , FLOW_STAT_PAYLOAD_IP_ID, 0, MAIN_DPDK_RX_Q, FDIR_PAYLOAD_RULES_HW_ID);
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_TCP, 0
- , FLOW_STAT_PAYLOAD_IP_ID, 0, MAIN_DPDK_RX_Q, 0);
+ , FLOW_STAT_PAYLOAD_IP_ID, 0, MAIN_DPDK_RX_Q, FDIR_PAYLOAD_RULES_HW_ID);
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 0
- , FLOW_STAT_PAYLOAD_IP_ID, 0, MAIN_DPDK_RX_Q, 0);
+ , FLOW_STAT_PAYLOAD_IP_ID, 0, MAIN_DPDK_RX_Q, FDIR_PAYLOAD_RULES_HW_ID);
rte_eth_fdir_stats_reset(_if->get_port_id(), NULL, FDIR_TEMP_HW_ID, 1);
return 0; // Other rules are configured dynamically in stateless
@@ -6301,6 +6660,405 @@ int CTRexExtendedDriverBase40G::set_rcv_all(CPhyEthIF * _if, bool set_on) {
}
/////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////
+/* MLX5 */
+
+void CTRexExtendedDriverBaseMlnx5G::clear_extended_stats(CPhyEthIF * _if){
+ rte_eth_stats_reset(_if->get_port_id());
+}
+
+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();
+ /* update mask */
+ cfg->m_port_conf.fdir_conf.mask.ipv4_mask.proto=0xff;
+ cfg->m_port_conf.fdir_conf.mask.ipv4_mask.tos=0x01;
+ cfg->m_port_conf.fdir_conf.mask.ipv6_mask.proto=0xff;
+ cfg->m_port_conf.fdir_conf.mask.ipv6_mask.tc=0x01;
+
+ /* enable RSS */
+ cfg->m_port_conf.rxmode.mq_mode =ETH_MQ_RX_RSS;
+ cfg->m_port_conf.rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP;
+
+}
+
+/*
+ In case of MLX5 driver, the rule is not really added according to givern parameters.
+ ip_id == 1 means add rule on TOS (or traffic_class) field.
+ ip_id == 2 means add rule to receive all packets.
+ */
+void CTRexExtendedDriverBaseMlnx5G::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) {
+ int ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
+ static int filter_soft_id = 0;
+
+ if ( ret != 0 ) {
+ rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_supported err=%d, port=%u \n", ret, port_id);
+ }
+
+ struct rte_eth_fdir_filter filter;
+
+ memset(&filter,0,sizeof(struct rte_eth_fdir_filter));
+
+#if 0
+ printf("MLNX add_del_rules::%s rules: port:%d type:%d ip_id:%x l4:%d q:%d\n"
+ , (op == RTE_ETH_FILTER_ADD) ? "add" : "del"
+ , port_id, type, ip_id, l4_proto, queue);
+#endif
+
+ filter.action.rx_queue = queue;
+ filter.action.behavior = RTE_ETH_FDIR_ACCEPT;
+ filter.action.report_status = RTE_ETH_FDIR_NO_REPORT_STATUS;
+ filter.soft_id = filter_soft_id++;
+ filter.input.flow_type = type;
+
+ switch (type) {
+ case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
+ filter.input.flow.ip4_flow.ip_id = ip_id;
+ if (l4_proto != 0)
+ filter.input.flow.ip4_flow.proto = l4_proto;
+ break;
+ case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
+ case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
+ case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
+ filter.input.flow.ipv6_flow.flow_label = ip_id;
+ filter.input.flow.ipv6_flow.proto = l4_proto;
+ break;
+ }
+
+ ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, op, (void*)&filter);
+ if ( ret != 0 ) {
+ if (((op == RTE_ETH_FILTER_ADD) && (ret == EEXIST)) || ((op == RTE_ETH_FILTER_DELETE) && (ret == ENOENT)))
+ return;
+
+ rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_ctrl: err=%d, port=%u\n",
+ ret, port_id);
+ }
+}
+
+int CTRexExtendedDriverBaseMlnx5G::set_rcv_all(CPhyEthIF * _if, bool set_on) {
+ uint8_t port_id=_if->get_rte_port_id();
+
+ if (set_on) {
+ add_del_rx_filter_rules(_if, false);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 2, 17, MAIN_DPDK_RX_Q);
+ } else {
+ add_del_rules(RTE_ETH_FILTER_DELETE, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 2, 17, MAIN_DPDK_RX_Q);
+ add_del_rx_filter_rules(_if, true);
+ }
+
+ return 0;
+
+}
+
+int CTRexExtendedDriverBaseMlnx5G::add_del_rx_filter_rules(CPhyEthIF * _if, bool set_on) {
+ uint32_t port_id = _if->get_port_id();
+ enum rte_filter_op op;
+
+ if (set_on) {
+ op = RTE_ETH_FILTER_ADD;
+ } else {
+ op = RTE_ETH_FILTER_DELETE;
+ }
+
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 1, 17, MAIN_DPDK_RX_Q);
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, 1, 6, MAIN_DPDK_RX_Q);
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 1, 1, MAIN_DPDK_RX_Q); /*ICMP*/
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 1, 132, MAIN_DPDK_RX_Q); /*SCTP*/
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, 1, 17, MAIN_DPDK_RX_Q);
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_TCP, 1, 6, MAIN_DPDK_RX_Q);
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 1, 1, MAIN_DPDK_RX_Q); /*ICMP*/
+ add_del_rules(op, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 1, 132, MAIN_DPDK_RX_Q); /*SCTP*/
+
+ return 0;
+}
+
+int CTRexExtendedDriverBaseMlnx5G::configure_rx_filter_rules(CPhyEthIF * _if) {
+ set_rcv_all(_if, false);
+ return add_del_rx_filter_rules(_if, true);
+}
+
+void CTRexExtendedDriverBaseMlnx5G::reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) {
+ for (int i =0; i < len; i++) {
+ stats[i] = 0;
+ }
+}
+
+int CTRexExtendedDriverBaseMlnx5G::get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts
+ ,uint32_t *bytes, uint32_t *prev_bytes, int min, int max) {
+ /* not supported yet */
+ return 0;
+}
+
+int CTRexExtendedDriverBaseMlnx5G::dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd)
+{
+ uint32_t port_id = _if->get_port_id();
+ struct rte_eth_fdir_stats stat;
+ int ret;
+
+ ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, RTE_ETH_FILTER_STATS, (void*)&stat);
+ if (ret == 0) {
+ if (fd)
+ fprintf(fd, "Num filters on guarant poll:%d, best effort poll:%d\n", stat.guarant_cnt, stat.best_cnt);
+ return (stat.guarant_cnt + stat.best_cnt);
+ } else {
+ if (fd)
+ fprintf(fd, "Failed reading fdir statistics\n");
+ return -1;
+ }
+}
+
+void CTRexExtendedDriverBaseMlnx5G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){
+
+ struct rte_eth_stats stats1;
+ struct rte_eth_stats *prev_stats = &stats->m_prev_stats;
+ rte_eth_stats_get(_if->get_port_id(), &stats1);
+
+ stats->ipackets += stats1.ipackets - prev_stats->ipackets;
+ stats->ibytes += stats1.ibytes - prev_stats->ibytes +
+ + (stats1.ipackets << 2) - (prev_stats->ipackets << 2);
+ stats->opackets += stats1.opackets - prev_stats->opackets;
+ stats->obytes += stats1.obytes - prev_stats->obytes
+ + (stats1.opackets << 2) - (prev_stats->opackets << 2);
+ stats->f_ipackets += 0;
+ stats->f_ibytes += 0;
+ stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf
+ - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf;
+ stats->oerrors += stats1.oerrors - prev_stats->oerrors;
+ stats->imcasts += 0;
+ stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf;
+
+ prev_stats->ipackets = stats1.ipackets;
+ prev_stats->ibytes = stats1.ibytes;
+ prev_stats->opackets = stats1.opackets;
+ prev_stats->obytes = stats1.obytes;
+ prev_stats->imissed = stats1.imissed;
+ prev_stats->oerrors = stats1.oerrors;
+ prev_stats->ierrors = stats1.ierrors;
+ prev_stats->rx_nombuf = stats1.rx_nombuf;
+}
+
+int CTRexExtendedDriverBaseMlnx5G::wait_for_stable_link(){
+ delay(20);
+ return (0);
+}
+
+CFlowStatParser *CTRexExtendedDriverBaseMlnx5G::get_flow_stat_parser() {
+ CFlowStatParser *parser = new CFlowStatParser();
+ assert (parser);
+ return parser;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////
+/* VIC */
+
+void CTRexExtendedDriverBaseVIC::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->m_port_conf.rxmode.max_rx_pkt_len =9*1000-10;
+ cfg->m_port_conf.fdir_conf.mask.ipv4_mask.tos = 0x01;
+ cfg->m_port_conf.fdir_conf.mask.ipv6_mask.tc = 0x01;
+}
+
+void CTRexExtendedDriverBaseVIC::add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type
+ , uint16_t id, uint8_t l4_proto, uint8_t tos, int queue) {
+ int ret=rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
+
+ if ( ret != 0 ){
+ rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_supported "
+ "err=%d, port=%u \n",
+ ret, port_id);
+ }
+
+ struct rte_eth_fdir_filter filter;
+
+ memset(&filter,0,sizeof(struct rte_eth_fdir_filter));
+
+#if 0
+ printf("VIC add_del_rules::%s rules: port:%d type:%d id:%d l4:%d tod:%d, q:%d\n"
+ , (op == RTE_ETH_FILTER_ADD) ? "add" : "del"
+ , port_id, type, id, l4_proto, tos, queue);
+#endif
+
+ filter.action.rx_queue = queue;
+ filter.action.behavior = RTE_ETH_FDIR_ACCEPT;
+ filter.action.report_status = RTE_ETH_FDIR_NO_REPORT_STATUS;
+ filter.soft_id = id;
+ filter.input.flow_type = type;
+
+ switch (type) {
+ case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
+ filter.input.flow.ip4_flow.tos = tos;
+ filter.input.flow.ip4_flow.proto = l4_proto;
+ break;
+ case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
+ case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
+ case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
+ filter.input.flow.ipv6_flow.tc = tos;
+ filter.input.flow.ipv6_flow.proto = l4_proto;
+ break;
+ }
+
+ ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, op, (void*)&filter);
+ if ( ret != 0 ) {
+ if (((op == RTE_ETH_FILTER_ADD) && (ret == -EEXIST)) || ((op == RTE_ETH_FILTER_DELETE) && (ret == -ENOENT)))
+ return;
+
+ rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_ctrl: err=%d, port=%u\n",
+ ret, port_id);
+ }
+}
+
+int CTRexExtendedDriverBaseVIC::add_del_eth_type_rule(uint8_t port_id, enum rte_filter_op op, uint16_t eth_type) {
+ int ret;
+ struct rte_eth_ethertype_filter filter;
+
+ memset(&filter, 0, sizeof(filter));
+ filter.ether_type = eth_type;
+ filter.flags = 0;
+ filter.queue = MAIN_DPDK_RX_Q;
+ ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_ETHERTYPE, op, (void *) &filter);
+
+ return ret;
+}
+
+int CTRexExtendedDriverBaseVIC::configure_rx_filter_rules_statefull(CPhyEthIF * _if) {
+ uint32_t port_id = _if->get_port_id();
+
+ set_rcv_all(_if, false);
+
+ // Rules to direct all IP packets with tos lsb bit 1 to RX Q.
+ // IPv4
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 1, 17, 0x1, MAIN_DPDK_RX_Q);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, 1, 6, 0x1, MAIN_DPDK_RX_Q);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, 1, 132, 0x1, MAIN_DPDK_RX_Q); /*SCTP*/
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 1, 1, 0x1, MAIN_DPDK_RX_Q); /*ICMP*/
+ // Ipv6
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, 1, 6, 0x1, MAIN_DPDK_RX_Q);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, 1, 17, 0x1, MAIN_DPDK_RX_Q);
+
+ // 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);
+
+ return 0;
+}
+
+
+int CTRexExtendedDriverBaseVIC::set_rcv_all(CPhyEthIF * _if, bool set_on) {
+ uint8_t port_id = _if->get_rte_port_id();
+
+ // soft ID 100 tells VIC driver to add rule for all ether types.
+ // Added with highest priority (implicitly in the driver), so if it exists, it applies before all other rules
+ if (set_on) {
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 100, 30, 0, MAIN_DPDK_RX_Q);
+ } else {
+ add_del_rules(RTE_ETH_FILTER_DELETE, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, 100, 30, 0, MAIN_DPDK_RX_Q);
+ }
+
+ return 0;
+
+}
+
+void CTRexExtendedDriverBaseVIC::clear_extended_stats(CPhyEthIF * _if){
+ rte_eth_stats_reset(_if->get_port_id());
+}
+
+void CTRexExtendedDriverBaseVIC::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats) {
+ struct rte_eth_stats stats1;
+ struct rte_eth_stats *prev_stats = &stats->m_prev_stats;
+ rte_eth_stats_get(_if->get_port_id(), &stats1);
+
+ stats->ipackets += stats1.ipackets - prev_stats->ipackets;
+ stats->ibytes += stats1.ibytes - prev_stats->ibytes
+ - ((stats1.ipackets << 2) - (prev_stats->ipackets << 2));
+ stats->opackets += stats1.opackets - prev_stats->opackets;
+ stats->obytes += stats1.obytes - prev_stats->obytes;
+ stats->f_ipackets += 0;
+ stats->f_ibytes += 0;
+ stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf
+ - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf;
+ stats->oerrors += stats1.oerrors - prev_stats->oerrors;
+ stats->imcasts += 0;
+ stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf;
+
+ prev_stats->ipackets = stats1.ipackets;
+ prev_stats->ibytes = stats1.ibytes;
+ prev_stats->opackets = stats1.opackets;
+ prev_stats->obytes = stats1.obytes;
+ prev_stats->imissed = stats1.imissed;
+ prev_stats->oerrors = stats1.oerrors;
+ prev_stats->ierrors = stats1.ierrors;
+ prev_stats->rx_nombuf = stats1.rx_nombuf;
+}
+
+int CTRexExtendedDriverBaseVIC::verify_fw_ver(int port_id) {
+
+ 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 ){
+ if ( fdir_info.flow_types_mask[0] & (1<< RTE_ETH_FLOW_NONFRAG_IPV4_OTHER) ) {
+ /* support new features */
+ if (CGlobalInfo::m_options.preview.getVMode() >= 1) {
+ printf("VIC port %d: FW support advanced filtering \n", port_id);
+ }
+ return (0);
+ }
+ }
+
+ printf("Error: VIC firmware should upgrade to support advanced filtering \n");
+ printf(" Please refer to %s for upgrade instructions\n",
+ "https://trex-tgn.cisco.com/trex/doc/trex_manual.html");
+ exit(1);
+}
+
+int CTRexExtendedDriverBaseVIC::configure_rx_filter_rules(CPhyEthIF * _if) {
+
+ if (get_is_stateless()) {
+ /* both stateless and stateful work in the same way, might changed in the future TOS */
+ return configure_rx_filter_rules_statefull(_if);
+ } else {
+ return configure_rx_filter_rules_statefull(_if);
+ }
+}
+
+void CTRexExtendedDriverBaseVIC::reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) {
+}
+
+int CTRexExtendedDriverBaseVIC::get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts
+ ,uint32_t *bytes, uint32_t *prev_bytes, int min, int max) {
+ printf(" NOT supported yet \n");
+ return 0;
+}
+
+// if fd != NULL, dump fdir stats of _if
+// return num of filters
+int CTRexExtendedDriverBaseVIC::dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd)
+{
+ //printf(" NOT supported yet \n");
+ return (0);
+}
+
+CFlowStatParser *CTRexExtendedDriverBaseVIC::get_flow_stat_parser() {
+ CFlowStatParser *parser = new CFlowStatParser();
+ assert (parser);
+ return parser;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
void CTRexExtendedDriverBase1GVm::update_configuration(port_cfg_t * cfg){
@@ -6495,19 +7253,10 @@ TrexDpdkPlatformApi::get_interface_info(uint8_t interface_id, intf_info_st &info
/* mac INFO */
/* hardware */
- g_trex.m_ports[interface_id].get_port_attr()->macaddr_get(&rte_mac_addr);
+ g_trex.m_ports[interface_id].get_port_attr()->get_hw_src_mac(&rte_mac_addr);
assert(ETHER_ADDR_LEN == 6);
- /* software */
- uint8_t sw_macaddr[12];
- memcpy(sw_macaddr, CGlobalInfo::m_options.get_dst_src_mac_addr(interface_id), 12);
-
- for (int i = 0; i < 6; i++) {
- info.mac_info.hw_macaddr[i] = rte_mac_addr.addr_bytes[i];
- info.mac_info.dst_macaddr[i] = sw_macaddr[i];
- info.mac_info.src_macaddr[i] = sw_macaddr[6 + i];
-
- }
+ memcpy(info.hw_macaddr, rte_mac_addr.addr_bytes, 6);
info.numa_node = g_trex.m_ports[interface_id].m_dev_info.pci_dev->numa_node;
struct rte_pci_addr *loc = &g_trex.m_ports[interface_id].m_dev_info.pci_dev->addr;
@@ -6613,6 +7362,30 @@ TRexPortAttr *TrexDpdkPlatformApi::getPortAttrObj(uint8_t port_id) const {
return g_trex.m_ports[port_id].get_port_attr();
}
+
+int DpdkTRexPortAttr::set_rx_filter_mode(rx_filter_mode_e rx_filter_mode) {
+
+ if (rx_filter_mode == m_rx_filter_mode) {
+ return (0);
+ }
+
+ 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);
+ if (rc != 0) {
+ return (rc);
+ }
+
+ m_rx_filter_mode = rx_filter_mode;
+
+ return (0);
+}
+
+bool DpdkTRexPortAttr::is_loopback() const {
+ uint8_t port_id;
+ return g_trex.lookup_port_by_mac(m_dest.get_dest_mac(), port_id);
+}
+
/**
* marks the control plane for a total server shutdown
*
@@ -6621,3 +7394,4 @@ TRexPortAttr *TrexDpdkPlatformApi::getPortAttrObj(uint8_t port_id) const {
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 6402d106..25b19471 100644
--- a/src/main_dpdk.h
+++ b/src/main_dpdk.h
@@ -109,6 +109,9 @@ class CPhyEthIF {
void dump_stats(FILE *fd);
void set_ignore_stats_base(CPreTestStats &pre_stats);
void update_counters();
+ void configure_rss_redirect_table(uint16_t numer_of_queues,
+ uint16_t skip_queue);
+
void stats_clear();
uint8_t get_port_id(){
return (m_port_id);
diff --git a/src/pal/linux_dpdk/x86_64-default-linuxapp-gcc/include/rte_config.h b/src/pal/linux_dpdk/x86_64-default-linuxapp-gcc/include/rte_config.h
index fdb5b994..25f8b4fe 100755
--- a/src/pal/linux_dpdk/x86_64-default-linuxapp-gcc/include/rte_config.h
+++ b/src/pal/linux_dpdk/x86_64-default-linuxapp-gcc/include/rte_config.h
@@ -70,3 +70,11 @@
#undef RTE_TEST_PMD_RECORD_BURST_STATS
#undef RTE_LIBRTE_GCOV
#undef RTE_INSECURE_FUNCTION_WARNING
+
+
+//#undef RTE_LIBRTE_MLX5_PMD
+//#define RTE_LIBRTE_MLX5_PMD 1
+//#undef RTE_LIBRTE_MLX5_TX_MP_CACHE
+//#define RTE_LIBRTE_MLX5_TX_MP_CACHE 8
+//#define MLX5_FDIR_SUPPORT 1
+
diff --git a/src/pkt_gen.cpp b/src/pkt_gen.cpp
index eb9a26f9..656b1b06 100644
--- a/src/pkt_gen.cpp
+++ b/src/pkt_gen.cpp
@@ -30,7 +30,7 @@
#include <common/Network/Packet/Arp.h>
#include "rx_check_header.h"
#include "pkt_gen.h"
-
+#include "bp_sim.h"
// For use in tests
char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags
, uint16_t max_payload, int &pkt_size) {
@@ -52,7 +52,7 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t
}
uint8_t ip_header[] = {
- 0x45,0x02,0x00,0x30,
+ 0x45,0x03,0x00,0x30,
0x00,0x00,0x40,0x00,
0xff,0x01,0xbd,0x04,
0x10,0x0,0x0,0x1, //SIP
@@ -60,7 +60,7 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t
// 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it.
};
uint8_t ipv6_header[] = {
- 0x60,0x00,0xff,0x30, // traffic class + flow label
+ 0x60,0x10,0xff,0x30, // traffic class + flow label
0x00,0x00,0x40,0x00, // payload len + next header + hop limit
0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //SIP
0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //DIP
@@ -222,10 +222,22 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t
switch(l3_type) {
case EthernetHeader::Protocol::IP:
ip->setTimeToLive(ttl);
+ if (flags & DPF_TOS_1) {
+ ip->setTOS(TOS_TTL_RESERVE_DUPLICATE);
+ }else{
+ ip->setTOS(0x2);
+ }
+
ip->updateCheckSum();
break;
case EthernetHeader::Protocol::IPv6:
ipv6->setHopLimit(ttl);
+ if (flags & DPF_TOS_1) {
+ ipv6->setTrafficClass(TOS_TTL_RESERVE_DUPLICATE);
+ }else{
+ ipv6->setTrafficClass(0x2);
+ }
+
break;
}
diff --git a/src/pkt_gen.h b/src/pkt_gen.h
index 309e02b9..8dcba624 100644
--- a/src/pkt_gen.h
+++ b/src/pkt_gen.h
@@ -37,7 +37,8 @@ enum {
enum {
DPF_VLAN = 0x1,
DPF_QINQ = 0X2,
- DPF_RXCHECK = 0x4
+ DPF_RXCHECK = 0x4,
+ DPF_TOS_1 = 0x8,
};
class CTestPktGen {
diff --git a/src/pre_test.cpp b/src/pre_test.cpp
index 130d076d..7127645d 100644
--- a/src/pre_test.cpp
+++ b/src/pre_test.cpp
@@ -29,80 +29,371 @@
#include "pkt_gen.h"
#include "pre_test.h"
-void CPretestPortInfo::set_params(CPerPortIPCfg port_cfg, const uint8_t *src_mac, bool resolve_needed) {
- m_ip = port_cfg.get_ip();
- m_def_gw = port_cfg.get_def_gw();
- m_vlan = port_cfg.get_vlan();
- memcpy(&m_src_mac, src_mac, sizeof(m_src_mac));
- if (resolve_needed) {
- m_state = CPretestPortInfo::RESOLVE_NEEDED;
- } else {
- m_state = CPretestPortInfo::RESOLVE_NOT_NEEDED;
+CPretestOnePortInfo::CPretestOnePortInfo() {
+ m_state = RESOLVE_NOT_NEEDED;
+ m_is_loopback = false;
+ m_stats.clear();
+}
+
+CPretestOnePortInfo::~CPretestOnePortInfo() {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ delete *it;
+ }
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ delete *it;
}
}
-void CPretestPortInfo::set_dst_mac(const uint8_t *dst_mac) {
- memcpy(&m_dst_mac, dst_mac, sizeof(m_dst_mac));
- m_state = CPretestPortInfo::RESOLVE_DONE;
+void CPretestOnePortInfo::add_src(uint32_t ip, uint16_t vlan, MacAddress mac) {
+ COneIPv4Info *one_ip = new COneIPv4Info(ip, vlan, mac);
+ assert(one_ip);
+ m_src_info.push_back(one_ip);
}
-void CPretestPortInfo::dump(FILE *fd) {
- if (m_state == INIT_NEEDED) {
- return;
- }
+void CPretestOnePortInfo::add_dst(uint32_t ip, uint16_t vlan) {
+ MacAddress default_mac;
+ COneIPv4Info *one_ip = new COneIPv4Info(ip, vlan, default_mac);
+ assert(one_ip);
+ m_dst_info.push_back(one_ip);
+ m_state = RESOLVE_NEEDED;
+}
- uint32_t ip = htonl(m_ip);
+void CPretestOnePortInfo::add_src(uint16_t ip[8], uint16_t vlan, MacAddress mac) {
+ COneIPv6Info *one_ip = new COneIPv6Info(ip, vlan, mac);
+ assert(one_ip);
+ m_src_info.push_back(one_ip);
+}
- fprintf(fd, " ip:%d.%d.%d.%d", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
- ip = htonl(m_def_gw);
- fprintf(fd, " default gw:%d.%d.%d.%d\n", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
+void CPretestOnePortInfo::add_dst(uint16_t ip[8], uint16_t vlan) {
+ MacAddress default_mac;
+ COneIPv6Info *one_ip = new COneIPv6Info(ip, vlan, default_mac);
+ assert(one_ip);
+ m_dst_info.push_back(one_ip);
+ m_state = RESOLVE_NEEDED;
+}
- printf(" src MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", m_src_mac[0], m_src_mac[1], m_src_mac[2], m_src_mac[3]
- , m_src_mac[4], m_src_mac[5]);
- printf( " dst MAC: ");
- if (m_state == RESOLVE_DONE) {
- printf("%02x:%02x:%02x:%02x:%02x:%02x\n", m_dst_mac[0], m_dst_mac[1], m_dst_mac[2], m_dst_mac[3]
- , m_dst_mac[4], m_dst_mac[5]);
- } else {
- printf("Not resolved\n");
+void CPretestOnePortInfo::dump(FILE *fd, char *offset) {
+ std::string new_offset = std::string(offset) + " ";
+
+ if (m_is_loopback) {
+ fprintf(fd, "%sPort connected in loopback\n", offset);
+ }
+ fprintf(fd, "%sSources:\n", offset);
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ (*it)->dump(fd, new_offset.c_str());
+ }
+ fprintf(fd, "%sDestinations:\n", offset);
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ (*it)->dump(fd, new_offset.c_str());
}
}
/*
- put in mac relevant dest MAC for port/ip pair.
- return false if no relevant info exists, true otherwise.
+ * Get appropriate source for given vlan and ip version.
*/
-bool CPretest::get_mac(uint16_t port_id, uint32_t ip, uint8_t *mac) {
- assert(port_id < TREX_MAX_PORTS);
+COneIPInfo *CPretestOnePortInfo::get_src(uint16_t vlan, uint8_t ip_ver) {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ if ((ip_ver == (*it)->ip_ver()) && (vlan == (*it)->get_vlan()))
+ return (*it);
+ }
+
+ return NULL;
+}
+
+COneIPv4Info *CPretestOnePortInfo::find_ip(uint32_t ip, uint16_t vlan) {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ if (((*it)->ip_ver() == COneIPInfo::IP4_VER) && ((*it)->get_vlan() == vlan) && (((COneIPv4Info *)(*it))->get_ip() == ip))
+ return (COneIPv4Info *) *it;
+ }
+
+ return NULL;
+}
+
+COneIPv4Info *CPretestOnePortInfo::find_next_hop(uint32_t ip, uint16_t vlan) {
+
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ if (((*it)->ip_ver() == COneIPInfo::IP4_VER) && ((*it)->get_vlan() == vlan) && (((COneIPv4Info *)(*it))->get_ip() == ip))
+ return (COneIPv4Info *) *it;
+ }
+
+ return NULL;
+}
+
+COneIPv6Info *CPretestOnePortInfo::find_ipv6(uint16_t ip[8], uint16_t vlan) {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ if (((*it)->ip_ver() == COneIPInfo::IP6_VER) && ((*it)->get_vlan() == vlan)
+ && (! memcmp((uint8_t *) ((COneIPv6Info *) (*it))->get_ipv6(), (uint8_t *)ip, 2*8 /* ???*/ ) ) )
+ return (COneIPv6Info *) *it;
+ }
+
+ return NULL;
+}
+
+bool CPretestOnePortInfo::get_mac(COneIPInfo *ip, uint8_t *mac) {
+ MacAddress defaultmac;
+
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ if (ip->ip_ver() != (*it)->ip_ver())
+ continue;
- if (m_port_info[port_id].m_state != CPretestPortInfo::RESOLVE_DONE) {
+ switch(ip->ip_ver()) {
+ case 4:
+ if (*((COneIPv4Info *) (*it)) != *((COneIPv4Info *) ip))
+ continue;
+ break;
+ case 6:
+ if (*((COneIPv6Info *) (*it)) != *((COneIPv6Info *) ip))
+ continue;
+ break;
+ default:
+ assert(0);
+ }
+
+ (*it)->get_mac(mac);
+ if (! memcmp(mac, defaultmac.GetConstBuffer(), ETHER_ADDR_LEN)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CPretestOnePortInfo::get_mac(uint32_t ip, uint16_t vlan, uint8_t *mac) {
+ COneIPv4Info one_ip(ip, vlan);
+
+ return get_mac(&one_ip, mac);
+}
+
+bool CPretestOnePortInfo::get_mac(uint16_t ip[8], uint16_t vlan, uint8_t *mac) {
+ COneIPv6Info one_ip(ip, vlan);
+
+ return get_mac(&one_ip, mac);
+}
+
+// return true if there are still any addresses to resolve on this port
+bool CPretestOnePortInfo::resolve_needed() {
+ if (m_state == RESOLVE_NOT_NEEDED)
return false;
+
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ if ((*it)->resolve_needed())
+ return true;
}
- memcpy(mac, &m_port_info[port_id].m_dst_mac, sizeof(m_port_info[port_id].m_dst_mac));
+ m_state = RESOLVE_NOT_NEEDED;
+ return false;
+}
+
+void CPretestOnePortInfo::send_arp_req_all() {
+ for (std::vector<COneIPInfo *>::iterator it = m_dst_info.begin(); it != m_dst_info.end(); ++it) {
+ rte_mbuf_t *m[1];
+ int num_sent;
+ int verbose = CGlobalInfo::m_options.preview.getVMode();
- return true;
+ m[0] = CGlobalInfo::pktmbuf_alloc_small_by_port(m_port_id);
+ if ( unlikely(m[0] == 0) ) {
+ fprintf(stderr, "ERROR: Could not allocate mbuf for sending ARP to port:%d\n", m_port_id);
+ exit(1);
+ }
+
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m[0], (*it)->get_arp_req_len());
+ // We need source on the same VLAN of the dest in order to send
+ COneIPInfo *sip = get_src((*it)->get_vlan(), (*it)->ip_ver());
+ if (sip == NULL) {
+ fprintf(stderr, "Failed finding matching source for - ");
+ (*it)->dump(stderr);
+ exit(1);
+ }
+ (*it)->fill_arp_req_buf(p, m_port_id, sip);
+
+ if (verbose >= 3) {
+ fprintf(stdout, "TX ARP request on port %d - " , m_port_id);
+ (*it)->dump(stdout, "");
+ }
+
+ num_sent = rte_eth_tx_burst(m_port_id, 0, m, 1);
+ if (num_sent < 1) {
+ fprintf(stderr, "Failed sending ARP to port:%d\n", m_port_id);
+ exit(1);
+ } else {
+ m_stats.m_tx_arp++;
+ }
+ }
+}
+
+void CPretestOnePortInfo::send_grat_arp_all() {
+ for (std::vector<COneIPInfo *>::iterator it = m_src_info.begin(); it != m_src_info.end(); ++it) {
+ rte_mbuf_t *m[1];
+ int num_sent;
+ int verbose = CGlobalInfo::m_options.preview.getVMode();
+
+ m[0] = CGlobalInfo::pktmbuf_alloc_small_by_port(m_port_id);
+ if ( unlikely(m[0] == 0) ) {
+ fprintf(stderr, "ERROR: Could not allocate mbuf for sending grat ARP on port:%d\n", m_port_id);
+ exit(1);
+ }
+
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m[0], (*it)->get_grat_arp_len());
+ (*it)->fill_grat_arp_buf(p);
+
+
+ if (verbose >= 3) {
+ fprintf(stdout, "TX grat ARP on port %d - " , m_port_id);
+ (*it)->dump(stdout, "");
+ }
+
+ num_sent = rte_eth_tx_burst(m_port_id, 0, m, 1);
+ if (num_sent < 1) {
+ fprintf(stderr, "Failed sending grat ARP on port:%d\n", m_port_id);
+ exit(1);
+ } else {
+ m_stats.m_tx_arp++;
+ }
+ }
+}
+
+// IPv4 functions
+void CPretest::add_ip(uint16_t port, uint32_t ip, uint16_t vlan, MacAddress src_mac) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_src(ip, vlan, src_mac);
+}
+
+void CPretest::add_ip(uint16_t port, uint32_t ip, MacAddress src_mac) {
+ assert(port < m_max_ports);
+ add_ip(port, ip, 0, src_mac);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint32_t ip, uint16_t vlan) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_dst(ip, vlan);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint32_t ip) {
+ assert(port < m_max_ports);
+ add_next_hop(port, ip, 0);
+}
+
+// IPv6 functions
+void CPretest::add_ip(uint16_t port, uint16_t ip[8], uint16_t vlan, MacAddress src_mac) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_src(ip, vlan, src_mac);
+}
+
+void CPretest::add_ip(uint16_t port, uint16_t ip[8], MacAddress src_mac) {
+ assert(port < m_max_ports);
+ add_ip(port, ip, 0, src_mac);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint16_t ip[8], uint16_t vlan) {
+ assert(port < m_max_ports);
+ m_port_info[port].add_dst(ip, vlan);
+}
+
+void CPretest::add_next_hop(uint16_t port, uint16_t ip[8]) {
+ assert(port < m_max_ports);
+ add_next_hop(port, ip, 0);
+}
+
+// put in mac, the relevant mac address for the tupple port_id, ip, vlan
+bool CPretest::get_mac(uint16_t port_id, uint32_t ip, uint16_t vlan, uint8_t *mac) {
+ assert(port_id < m_max_ports);
+
+ return m_port_info[port_id].get_mac(ip, vlan, mac);
+}
+
+// IPv6 version of above
+bool CPretest::get_mac(uint16_t port_id, uint16_t ip[8], uint16_t vlan, uint8_t *mac) {
+ assert(port_id < m_max_ports);
+
+ return m_port_info[port_id].get_mac(ip, vlan, mac);
}
CPreTestStats CPretest::get_stats(uint16_t port_id) {
- assert(port_id < TREX_MAX_PORTS);
+ assert(port_id < m_max_ports);
- return m_port_info[port_id].m_stats;
+ return m_port_info[port_id].get_stats();
}
bool CPretest::is_loopback(uint16_t port) {
- assert(port < TREX_MAX_PORTS);
+ assert(port < m_max_ports);
+
+ return m_port_info[port].is_loopback();
+}
+
+bool CPretest::resolve_all() {
+ uint16_t port;
+
+ // send ARP request on all ports
+ for (port = 0; port < m_max_ports; port++) {
+ m_port_info[port].send_arp_req_all();
+ }
+
+ int max_tries = 1000;
+ int i;
+ for (i = 0; i < max_tries; i++) {
+ bool all_resolved = true;
+ for (port = 0; port < m_max_ports; port++) {
+ if (m_port_info[port].resolve_needed()) {
+ // We need to stop reading packets only if all ports are resolved.
+ // 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);
+ }
+ if (all_resolved) {
+ break;
+ } else {
+ delay(1);
+ }
+ }
- return m_port_info[port].m_is_loopback;
+ if (i == max_tries) {
+ return false;
+ } else {
+ return true;
+ }
+
+ return true;
}
-void CPretest::set_port_params(uint16_t port_id, const CPerPortIPCfg &port_cfg, const uint8_t *src_mac, bool resolve_needed) {
- if (port_id >= m_max_ports)
- return;
+void CPretest::send_arp_req_all() {
+ for (uint16_t port = 0; port < m_max_ports; port++) {
+ m_port_info[port].send_arp_req_all();
+ }
+}
- m_port_info[port_id].set_params(port_cfg, src_mac, resolve_needed);
+void CPretest::send_grat_arp_all() {
+ for (uint16_t port = 0; port < m_max_ports; port++) {
+ m_port_info[port].send_grat_arp_all();
+ }
}
+bool CPretest::is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp, uint16_t &vlan_tag) {
+ EthernetHeader *m_ether = (EthernetHeader *)p;
+ vlan_tag = 0;
+
+ if ((pkt_size < sizeof(EthernetHeader)) ||
+ ((m_ether->getNextProtocol() != EthernetHeader::Protocol::ARP)
+ && (m_ether->getNextProtocol() != EthernetHeader::Protocol::VLAN)))
+ return false;
+
+ if (m_ether->getNextProtocol() == EthernetHeader::Protocol::ARP) {
+ arp = (ArpHdr *)(p + 14);
+ } else {
+ if (m_ether->getVlanProtocol() != EthernetHeader::Protocol::ARP) {
+ return false;
+ } else {
+ vlan_tag = m_ether->getVlanTag();
+ arp = (ArpHdr *)(p + 18);
+ }
+ }
+
+ return true;
+}
int CPretest::handle_rx(int port_id, int queue_id) {
rte_mbuf_t * rx_pkts[32];
@@ -121,72 +412,89 @@ int CPretest::handle_rx(int port_id, int queue_id) {
int pkt_size = rte_pktmbuf_pkt_len(m);
uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *);
ArpHdr *arp;
- CPretestPortInfo *port = &m_port_info[port_id];
- if (is_arp(p, pkt_size, arp)) {
- m_port_info[port_id].m_stats.m_rx_arp++;
+ uint16_t vlan_tag;
+ CPretestOnePortInfo *port = &m_port_info[port_id];
+ if (is_arp(p, pkt_size, arp, vlan_tag)) {
+ port->m_stats.m_rx_arp++;
if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REQUEST)) {
if (verbose >= 3) {
- fprintf(stdout, "RX ARP request on port %d queue %d sip:0x%08x tip:0x%08x\n"
- , port_id, queue_id, ntohl(arp->m_arp_sip), ntohl(arp->m_arp_tip));
+ bool is_grat = false;
+ if (arp->m_arp_sip == arp->m_arp_tip) {
+ is_grat = true;
+ }
+ fprintf(stdout, "RX %s on port %d queue %d sip:%s tip:%s vlan:%d\n"
+ , is_grat ? "grat ARP" : "ARP request"
+ , port_id, queue_id
+ , ip_to_str(ntohl(arp->m_arp_sip)).c_str()
+ , ip_to_str(ntohl(arp->m_arp_tip)).c_str()
+ , vlan_tag);
}
// is this request for our IP?
- if (ntohl(arp->m_arp_tip) == port->m_ip) {
+ COneIPv4Info *src_addr;
+ COneIPv4Info *rcv_addr;
+ if ((src_addr = port->find_ip(ntohl(arp->m_arp_tip), vlan_tag))) {
// If our request(i.e. we are connected in loopback)
// , do a shortcut, and write info directly to asking port
uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9};
if (! memcmp((uint8_t *)&arp->m_arp_tha.data, magic, 5)) {
uint8_t sent_port_id = arp->m_arp_tha.data[5];
if ((sent_port_id < m_max_ports) &&
- (m_port_info[sent_port_id].m_def_gw == port->m_ip)) {
- memcpy(m_port_info[sent_port_id].m_dst_mac, port->m_src_mac, ETHER_ADDR_LEN);
- m_port_info[sent_port_id].m_state = CPretestPortInfo::RESOLVE_DONE;
+ (rcv_addr = m_port_info[sent_port_id].find_next_hop(ntohl(arp->m_arp_tip), vlan_tag))) {
+ uint8_t mac[ETHER_ADDR_LEN];
+ src_addr->get_mac(mac);
+ rcv_addr->set_mac(mac);
+ port->m_is_loopback = true;
m_port_info[sent_port_id].m_is_loopback = true;
}
} else {
// Not our request. Answer.
+ uint8_t src_mac[ETHER_ADDR_LEN];
free_pkt = false; // We use the same mbuf to send response. Don't free it twice.
arp->m_arp_op = htons(ArpHdr::ARP_HDR_OP_REPLY);
uint32_t tmp_ip = arp->m_arp_sip;
arp->m_arp_sip = arp->m_arp_tip;
arp->m_arp_tip = tmp_ip;
memcpy((uint8_t *)&arp->m_arp_tha, (uint8_t *)&arp->m_arp_sha, ETHER_ADDR_LEN);
- memcpy((uint8_t *)&arp->m_arp_sha, port->m_src_mac, ETHER_ADDR_LEN);
+ src_addr->get_mac(src_mac);
+ memcpy((uint8_t *)&arp->m_arp_sha, src_mac, ETHER_ADDR_LEN);
EthernetHeader *m_ether = (EthernetHeader *)p;
memcpy((uint8_t *)&m_ether->myDestination, (uint8_t *)&m_ether->mySource, ETHER_ADDR_LEN);
- memcpy((uint8_t *)&m_ether->mySource, (uint8_t *)port->m_src_mac, ETHER_ADDR_LEN);
+ memcpy((uint8_t *)&m_ether->mySource, src_mac, ETHER_ADDR_LEN);
int num_sent = rte_eth_tx_burst(port_id, 0, &m, 1);
if (num_sent < 1) {
fprintf(stderr, "Failed sending ARP reply to port:%d\n", port_id);
rte_pktmbuf_free(m);
} else {
- fprintf(stdout, "TX ARP reply on port:%d sip:0x%08x, tip:0x%08x\n"
- , port_id ,htonl(arp->m_arp_sip), htonl(arp->m_arp_tip));
+ if (verbose >= 3) {
+ fprintf(stdout, "TX ARP reply on port:%d sip:%s, tip:%s\n"
+ , port_id
+ , ip_to_str(ntohl(arp->m_arp_sip)).c_str()
+ , ip_to_str(ntohl(arp->m_arp_tip)).c_str());
+
+ }
m_port_info[port_id].m_stats.m_tx_arp++;
}
}
} else {
- // ARP request not to our IP.
- if ((ntohl(arp->m_arp_tip) == port->m_def_gw) && (ntohl(arp->m_arp_sip) == port->m_def_gw)) {
- // sip and tip equals def_gw, meaning we got gratitues ARP.
- port->set_dst_mac((uint8_t *)&arp->m_arp_sha);
+ // ARP request not to our IP. Check if this is gratitues ARP for something we need.
+ if ((arp->m_arp_tip == arp->m_arp_sip)
+ && (rcv_addr = port->find_next_hop(ntohl(arp->m_arp_tip), vlan_tag))) {
+ rcv_addr->set_mac((uint8_t *)&arp->m_arp_sha);
}
}
} else {
if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REPLY)) {
if (verbose >= 3) {
- bool is_grat = false;
- if (arp->m_arp_sip == arp->m_arp_tip) {
- is_grat = true;
- }
- fprintf(stdout, "RX %s on port %d queue %d sip:0x%08x tip:0x%08x\n"
- , is_grat ? "grat ARP" : "ARP reply"
+ fprintf(stdout, "RX ARP reply on port %d queue %d sip:%s tip:%s\n"
, port_id, queue_id
- , ntohl(arp->m_arp_sip)
- , ntohl(arp->m_arp_tip));
+ , ip_to_str(ntohl(arp->m_arp_sip)).c_str()
+ , ip_to_str(ntohl(arp->m_arp_tip)).c_str());
}
+
// If this is response to our request, update our tables
- if (port->m_def_gw == ntohl(arp->m_arp_sip)) {
- port->set_dst_mac((uint8_t *)&arp->m_arp_sha);
+ COneIPv4Info *addr;
+ if ((addr = port->find_next_hop(ntohl(arp->m_arp_sip), vlan_tag))) {
+ addr->set_mac((uint8_t *)&arp->m_arp_sha);
}
}
}
@@ -199,160 +507,87 @@ int CPretest::handle_rx(int port_id, int queue_id) {
return 0;
}
-/*
- Try to resolve def_gw address on all ports marked as needed.
- Return false if failed to resolve on one of the ports
- */
-bool CPretest::resolve_all() {
- uint16_t port;
-
- // send ARP request on all ports
- for (port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) {
- send_arp_req(port, false);
- }
- }
-
- int max_tries = 1000;
- int i;
- for (i = 0; i < max_tries; i++) {
- bool all_resolved = true;
- for (port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) {
- // We need to stop reading packets only if all ports are resolved.
- // If we are on loopback, We might get requests on port even after it is in RESOLVE_DONE state
- all_resolved = false;
+void CPretest::get_results(CManyIPInfo &resolved_ips) {
+ for (int port = 0; port < m_max_ports; port++) {
+ for (std::vector<COneIPInfo *>::iterator it = m_port_info[port].m_dst_info.begin()
+ ; it != m_port_info[port].m_dst_info.end(); ++it) {
+ uint8_t ip_type = (*it)->ip_ver();
+ (*it)->set_port(port);
+ switch(ip_type) {
+ case COneIPInfo::IP4_VER:
+ resolved_ips.insert(*(COneIPv4Info *)(*it));
+ break;
+#if 0
+ //??? fix for ipv6
+ case COneIPInfo::IP6_VER:
+ ipv6_tmp = (uint8_t *)((COneIPv6Info *)(*it))->get_ipv6();
+ memcpy((uint8_t *)ipv6, (uint8_t *)ipv6_tmp, 16);
+ v6_list.insert(std::pair<std::pair<uint16_t[8], uint16_t>, COneIPv6Info>
+ (std::pair<uint16_t[8], uint16_t>(ipv6, vlan), *(COneIPv6Info *)(*it)));
+ break;
+#endif
+ default:
+ break;
}
- handle_rx(port, MAIN_DPDK_DATA_Q);
- if (! CGlobalInfo::m_options.preview.get_vm_one_queue_enable())
- handle_rx(port, MAIN_DPDK_RX_Q);
- }
- if (all_resolved) {
- break;
- } else {
- delay(1);
}
}
-
- if (i == max_tries) {
- return false;
- } else {
- return true;
- }
}
void CPretest::dump(FILE *fd) {
+ fprintf(fd, "Pre test info start ===================\n");
for (int port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state != CPretestPortInfo::INIT_NEEDED) {
- fprintf(fd, "port %d:\n", port);
- m_port_info[port].dump(fd);
- }
- }
-}
-
-// Send ARP request for our default gateway on port
-// If is_grat is true - send gratuitous ARP.
-void CPretest::send_arp_req(uint16_t port_id, bool is_grat) {
- rte_mbuf_t *m[1];
- int num_sent;
- int verbose = CGlobalInfo::m_options.preview.getVMode();
-
- m[0] = CGlobalInfo::pktmbuf_alloc_small(0);
- if ( unlikely(m[0] == 0) ) {
- fprintf(stderr, "ERROR: Could not allocate mbuf for sending ARP to port:%d\n", port_id);
- exit(1);
- }
-
- uint32_t tip;
- uint8_t *p = (uint8_t *)rte_pktmbuf_append(m[0], 60); // ARP packet is shorter than 60
- uint32_t sip = m_port_info[port_id].m_ip;
- uint8_t *src_mac = m_port_info[port_id].m_src_mac;
- uint16_t vlan = m_port_info[port_id].m_vlan;
- if (is_grat) {
- tip = sip;
- } else {
- tip = m_port_info[port_id].m_def_gw;
- }
-
- if (verbose >= 3) {
- fprintf(stdout, "TX %s port:%d sip:0x%08x, tip:0x%08x\n"
- , is_grat ? "grat ARP": "ARP request", port_id ,sip, tip);
- }
-
- CTestPktGen::create_arp_req(p, sip, tip, src_mac, vlan, port_id);
- num_sent = rte_eth_tx_burst(port_id, 0, m, 1);
- if (num_sent < 1) {
- fprintf(stderr, "Failed sending ARP to port:%d\n", port_id);
- exit(1);
- } else {
- m_port_info[port_id].m_stats.m_tx_arp++;
- }
-}
-
-/*
- Send gratuitous ARP on all ports
- */
-void CPretest::send_grat_arp_all() {
- for (uint16_t port = 0; port < m_max_ports; port++) {
- if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) {
- send_arp_req(port, true);
- }
- }
-}
-
-bool CPretest::is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp) {
- EthernetHeader *m_ether = (EthernetHeader *)p;
-
- if ((pkt_size < 60) ||
- ((m_ether->getNextProtocol() != EthernetHeader::Protocol::ARP)
- && (m_ether->getNextProtocol() != EthernetHeader::Protocol::VLAN)))
- return false;
-
- if (m_ether->getNextProtocol() == EthernetHeader::Protocol::ARP) {
- arp = (ArpHdr *)(p + 14);
- } else {
- if (m_ether->getVlanProtocol() != EthernetHeader::Protocol::ARP) {
- return false;
- } else {
- arp = (ArpHdr *)(p + 18);
- }
+ fprintf(fd, "Port %d:\n", port);
+ m_port_info[port].dump(fd, (char *)" ");
}
-
- return true;
+ fprintf(fd, "Pre test info end ===================\n");
}
-// Should be run on setup with two interfaces connected by loopback.
-// Before running, should put ports on receive all mode.
void CPretest::test() {
uint8_t found_mac[ETHER_ADDR_LEN];
uint8_t mac0[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd0};
uint8_t mac1[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd1};
- uint32_t ip0 = 0x0f000003;
- uint32_t ip1 = 0x0f000001;
-
- CPerPortIPCfg port_cfg0;
- CPerPortIPCfg port_cfg1;
- port_cfg0.set_ip(ip0);
- port_cfg0.set_def_gw(ip1);
- port_cfg0.set_vlan(0);
- port_cfg1.set_ip(ip1);
- port_cfg1.set_def_gw(ip0);
- port_cfg1.set_vlan(0);
-
- set_port_params(0, port_cfg0, mac0, true);
- set_port_params(1, port_cfg1, mac1, true);
+ uint8_t mac2[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd2};
+ uint32_t ip0 = 0x0f000002;
+ uint32_t ip01 = 0x0f000003;
+ uint32_t ip1 = 0x0f000001;
+ uint16_t ipv6_0[8] = {0x1234, 0x5678, 0xabcd, 0x0, 0x0, 0x0, 0x1111, 0x2220};
+ uint16_t ipv6_1[8] = {0x1234, 0x5678, 0xabcd, 0x0, 0x0, 0x0, 0x1111, 0x2221};
+ uint16_t vlan=1;
+ uint8_t port_0 = 0;
+ uint8_t port_1 = 3;
+
+ add_ip(port_0, ip0, vlan, mac0);
+ add_ip(port_0, ip01, vlan, mac1);
+ add_ip(port_0, ipv6_0, vlan, mac1);
+ add_next_hop(port_0, ip1, vlan);
+ add_next_hop(port_0, ipv6_1, vlan);
+
+ add_ip(port_1, ip1, vlan, mac2);
+ add_ip(port_1, ipv6_1, vlan, mac2);
+ add_next_hop(port_1, ip0, vlan);
+ add_next_hop(port_1, ip01, vlan);
+ add_next_hop(port_1, ipv6_0, vlan);
+
dump(stdout);
+ send_grat_arp_all();
resolve_all();
dump(stdout);
- get_mac(0, ip1, found_mac);
- if (memcmp(found_mac, mac1, ETHER_ADDR_LEN)) {
- fprintf(stderr, "Test failed: Could not resolve def gw on port 0\n");
+
+ if (!get_mac(port_0, ip1, vlan, found_mac)) {
+ fprintf(stderr, "Test failed: Could not find %x on port %d\n", ip1, port_0);
+ exit(1);
+ }
+ if (memcmp(found_mac, mac2, ETHER_ADDR_LEN)) {
+ fprintf(stderr, "Test failed: dest %x on port %d badly resolved\n", ip1, port_0);
exit(1);
}
- get_mac(1, ip0, found_mac);
+ if (!get_mac(port_1, ip0, vlan, found_mac)) {
+ fprintf(stderr, "Test failed: Could not find %x on port %d\n", ip0, port_1);
+ exit(1);
+ }
if (memcmp(found_mac, mac0, ETHER_ADDR_LEN)) {
- fprintf(stderr, "Test failed: Could not resolve def gw on port 1\n");
+ fprintf(stderr, "Test failed: dest %x on port %d badly resolved\n", ip0, port_1);
exit(1);
}
diff --git a/src/pre_test.h b/src/pre_test.h
index ad7608a6..14b444cf 100644
--- a/src/pre_test.h
+++ b/src/pre_test.h
@@ -24,6 +24,7 @@
#include <iostream>
#include <common/Network/Packet/Arp.h>
+#include <common/Network/Packet/MacAddress.h>
#include "bp_sim.h"
#include "trex_defs.h"
@@ -39,60 +40,80 @@ class CPreTestStats {
}
};
-class CPretestPortInfo {
+class CPretestOnePortInfo {
friend class CPretest;
-
- private:
- enum CPretestPortInfoStates {
- INIT_NEEDED,
+ enum CPretestOnePortInfoStates {
RESOLVE_NEEDED,
- RESOLVE_DONE,
RESOLVE_NOT_NEEDED,
};
- CPretestPortInfo() {
- m_state = INIT_NEEDED;
- m_is_loopback = false;
- m_stats.clear();
- }
- void dump(FILE *fd);
- uint8_t *create_arp_req(uint16_t &pkt_size, uint8_t port, bool is_grat);
- void set_params(CPerPortIPCfg port_cfg, const uint8_t *src_mac, bool resolve_needed);
- void set_dst_mac(const uint8_t *dst_mac);
-
+ public:
+ CPretestOnePortInfo();
+ ~CPretestOnePortInfo();
+ void add_src(uint32_t ip, uint16_t vlan, MacAddress mac);
+ void add_dst(uint32_t ip, uint16_t vlan);
+ void add_src(uint16_t ip[8], uint16_t vlan, MacAddress mac);
+ void add_dst(uint16_t ip[8], uint16_t vlan);
+ bool get_mac(uint32_t ip, uint16_t vlan, uint8_t *mac);
+ bool get_mac(uint16_t ip[8], uint16_t vlan, uint8_t *mac);
+ bool get_mac(COneIPInfo *ip, uint8_t *mac);
+ COneIPInfo *get_src(uint16_t vlan, uint8_t ip_ver);
+ void set_port_id(uint16_t port_id) {m_port_id = port_id;}
+ void dump(FILE *fd, char *offset);
+ bool is_loopback() {return m_is_loopback;}
+ CPreTestStats get_stats() {return m_stats;}
+ bool resolve_needed();
+ void send_grat_arp_all();
+ void send_arp_req_all();
+
+ private:
+ COneIPv4Info *find_ip(uint32_t ip, uint16_t vlan);
+ COneIPv4Info *find_next_hop(uint32_t ip, uint16_t vlan);
+ COneIPv6Info *find_ipv6(uint16_t *ip, uint16_t vlan);
+ bool get_mac(COneIPInfo *ip, uint16_t vlan, uint8_t *mac, uint8_t ip_ver);
+
private:
- uint32_t m_ip;
- uint32_t m_def_gw;
- uint16_t m_vlan;
- uint8_t m_src_mac[6];
- uint8_t m_dst_mac[6];
- enum CPretestPortInfoStates m_state;
bool m_is_loopback;
+ CPretestOnePortInfoStates m_state;
CPreTestStats m_stats;
+ uint16_t m_port_id;
+ std::vector<COneIPInfo *> m_src_info;
+ std::vector<COneIPInfo *> m_dst_info;
};
-
class CPretest {
public:
CPretest(uint16_t max_ports) {
m_max_ports = max_ports;
+ for (int i =0; i < max_ports; i++) {
+ m_port_info[i].set_port_id(i);
+ }
}
- bool get_mac(uint16_t port, uint32_t ip, uint8_t *mac);
+ 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);
+ void add_next_hop(uint16_t port, uint32_t ip, uint16_t vlan);
+ void add_next_hop(uint16_t port, uint32_t ip);
+ void add_ip(uint16_t port, uint16_t ip[8], uint16_t vlan, MacAddress src_mac);
+ void add_ip(uint16_t port, uint16_t ip[8], MacAddress src_mac);
+ void add_next_hop(uint16_t port, uint16_t ip[8], uint16_t vlan);
+ void add_next_hop(uint16_t port, uint16_t ip[8]);
+ bool get_mac(uint16_t port, uint32_t ip, uint16_t vlan, uint8_t *mac);
+ bool get_mac(uint16_t port, uint16_t ip[8], uint16_t vlan, uint8_t *mac);
CPreTestStats get_stats(uint16_t port_id);
bool is_loopback(uint16_t port);
- void set_port_params(uint16_t port_id, const CPerPortIPCfg &port_cfg, const uint8_t *src_mac, bool resolve_needed);
bool resolve_all();
- void send_arp_req(uint16_t port, bool is_grat);
+ void send_arp_req_all();
void send_grat_arp_all();
- bool is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp);
+ bool is_arp(const uint8_t *p, uint16_t pkt_size, ArpHdr *&arp, uint16_t &vlan_tag);
+ void get_results(CManyIPInfo &resolved_ips);
void dump(FILE *fd);
void test();
-
+
private:
int handle_rx(int port, int queue_id);
private:
- CPretestPortInfo m_port_info[TREX_MAX_PORTS];
+ CPretestOnePortInfo m_port_info[TREX_MAX_PORTS];
uint16_t m_max_ports;
};
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
index 109cc1a4..d4854a79 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -27,6 +27,8 @@ limitations under the License.
#include <internal_api/trex_platform_api.h>
+#include "trex_stateless_rx_core.h"
+
#include <fstream>
#include <iostream>
#include <unistd.h>
@@ -289,19 +291,15 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
section["ports"] = Json::arrayValue;
for (int i = 0; i < main->get_port_count(); i++) {
- uint32_t speed;
string driver;
- string hw_macaddr;
- string src_macaddr;
- string dst_macaddr;
string pci_addr;
string description;
supp_speeds_t supp_speeds;
int numa;
TrexStatelessPort *port = main->get_port_by_id(i);
- port->get_properties(driver, speed);
- port->get_macaddr(hw_macaddr, src_macaddr, dst_macaddr);
+
+ port->get_properties(driver);
port->get_pci_info(pci_addr, numa);
main->get_platform_api()->getPortAttrObj(i)->get_description(description);
@@ -311,9 +309,6 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
section["ports"][i]["driver"] = driver;
section["ports"][i]["description"] = description;
- section["ports"][i]["hw_macaddr"] = hw_macaddr;
- section["ports"][i]["src_macaddr"] = src_macaddr;
- section["ports"][i]["dst_macaddr"] = dst_macaddr;
section["ports"][i]["pci_addr"] = pci_addr;
section["ports"][i]["numa"] = numa;
@@ -330,7 +325,6 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
section["ports"][i]["rx"]["caps"].append("rx_bytes");
}
section["ports"][i]["rx"]["counters"] = port->get_rx_count_num();
- section["ports"][i]["speed"] = (uint16_t) speed / 1000;
section["ports"][i]["is_fc_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_fc_change_supported();
section["ports"][i]["is_led_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_led_change_supported();
section["ports"][i]["is_link_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_link_change_supported();
@@ -345,6 +339,24 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
return (TREX_RPC_CMD_OK);
}
+
+int
+TrexRpcCmdSetPortAttr::parse_rx_filter_mode(const Json::Value &msg, uint8_t port_id, Json::Value &result) {
+ const std::string type = parse_choice(msg, "mode", {"hw", "all"}, result);
+
+ rx_filter_mode_e filter_mode;
+ if (type == "hw") {
+ filter_mode = RX_FILTER_MODE_HW;
+ } else if (type == "all") {
+ filter_mode = RX_FILTER_MODE_ALL;
+ } else {
+ /* can't happen - parsed choice */
+ assert(0);
+ }
+
+ return get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_rx_filter_mode(filter_mode);
+}
+
/**
* set port commands
*
@@ -361,46 +373,54 @@ TrexRpcCmdSetPortAttr::_run(const Json::Value &params, Json::Value &result) {
uint8_t port_id = parse_port(params, result);
const Json::Value &attr = parse_object(params, "attr", result);
+
int ret = 0;
- bool changed = false;
+
/* iterate over all attributes in the dict */
for (const std::string &name : attr.getMemberNames()) {
+
if (name == "promiscuous") {
bool enabled = parse_bool(attr[name], "enabled", result);
ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_promiscuous(enabled);
}
+
else if (name == "link_status") {
bool up = parse_bool(attr[name], "up", result);
ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_link_up(up);
}
+
else if (name == "led_status") {
bool on = parse_bool(attr[name], "on", result);
ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_led(on);
- } else if (name == "flow_ctrl_mode") {
+ }
+
+ else if (name == "flow_ctrl_mode") {
int mode = parse_int(attr[name], "mode", result);
ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_flow_ctrl(mode);
- } else {
- generate_execute_err(result, "Not recognized attribute: " + name);
- break;
}
- if (ret != 0){
- if ( ret == -ENOTSUP ) {
- generate_execute_err(result, "Error applying " + name + ": operation is not supported for this NIC.");
- }
- else if (ret) {
- generate_execute_err(result, "Error applying " + name + " attribute, return value: " + to_string(ret));
- }
+
+ else if (name == "rx_filter_mode") {
+ const Json::Value &rx = parse_object(attr, name, result);
+ ret = parse_rx_filter_mode(rx, port_id, result);
+ }
+
+ /* unknown attribute */
+ else {
+ generate_execute_err(result, "unknown attribute type: '" + name + "'");
break;
- } else {
- changed = true;
}
- }
- if (changed) {
- get_stateless_obj()->get_platform_api()->publish_async_port_attr_changed(port_id);
- }
+ /* check error code */
+ if ( ret == -ENOTSUP ) {
+ generate_execute_err(result, "Error applying " + name + ": operation is not supported for this NIC.");
+ } else if (ret) {
+ generate_execute_err(result, "Error applying " + name + " attribute, return value: " + to_string(ret));
+ }
+ }
+
result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
+
}
@@ -568,18 +588,17 @@ TrexRpcCmdGetPortStatus::_run(const Json::Value &params, Json::Value &result) {
result["result"]["owner"] = (port->get_owner().is_free() ? "" : port->get_owner().get_name());
result["result"]["state"] = port->get_state_as_string();
result["result"]["max_stream_id"] = port->get_max_stream_id();
- result["result"]["speed"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_link_speed();
/* attributes */
- result["result"]["attr"]["promiscuous"]["enabled"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_promiscuous();
- result["result"]["attr"]["link"]["up"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->is_link_up();
- int mode;
- int ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_flow_ctrl(mode);
- if (ret != 0) {
- mode = -1;
+ get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->to_json(result["result"]["attr"]);
+
+ /* RX info */
+ try {
+ result["result"]["rx_info"] = port->rx_features_to_json();
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
}
- result["result"]["attr"]["fc"]["mode"] = mode;
-
+
return (TREX_RPC_CMD_OK);
}
@@ -612,7 +631,8 @@ TrexRpcCmdPushRemote::_run(const Json::Value &params, Json::Value &result) {
uint8_t port_id = parse_port(params, result);
std::string pcap_filename = parse_string(params, "pcap_filename", result);
double ipg_usec = parse_double(params, "ipg_usec", result);
- double speedup = parse_double(params, "speedup", result);
+ double min_ipg_sec = usec_to_sec(parse_udouble(params, "min_ipg_usec", result, 0));
+ double speedup = parse_udouble(params, "speedup", result);
uint32_t count = parse_uint32(params, "count", result);
double duration = parse_double(params, "duration", result);
bool is_dual = parse_bool(params, "is_dual", result, false);
@@ -630,7 +650,7 @@ TrexRpcCmdPushRemote::_run(const Json::Value &params, Json::Value &result) {
try {
- port->push_remote(pcap_filename, ipg_usec, speedup, count, duration, is_dual);
+ port->push_remote(pcap_filename, ipg_usec, min_ipg_sec, speedup, count, duration, is_dual);
} catch (const TrexException &ex) {
generate_execute_err(result, ex.what());
}
@@ -640,3 +660,210 @@ TrexRpcCmdPushRemote::_run(const Json::Value &params, Json::Value &result) {
}
+/**
+ * set on/off RX software receive mode
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdSetRxFeature::_run(const Json::Value &params, Json::Value &result) {
+
+ uint8_t port_id = parse_port(params, result);
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+
+ /* decide which feature is being set */
+ const std::string type = parse_choice(params, "type", {"capture", "queue", "server"}, result);
+
+ if (type == "capture") {
+ parse_capture_msg(params, port, result);
+ } else if (type == "queue") {
+ parse_queue_msg(params, port, result);
+ } else if (type == "server") {
+ parse_server_msg(params, port, result);
+ } else {
+ assert(0);
+ }
+
+ result["result"] = Json::objectValue;
+ return (TREX_RPC_CMD_OK);
+
+}
+
+void
+TrexRpcCmdSetRxFeature::parse_capture_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result) {
+
+ bool enabled = parse_bool(msg, "enabled", result);
+
+ if (enabled) {
+
+ std::string pcap_filename = parse_string(msg, "pcap_filename", result);
+ uint64_t limit = parse_uint32(msg, "limit", result);
+
+ if (limit == 0) {
+ generate_parse_err(result, "limit cannot be zero");
+ }
+
+ try {
+ port->start_rx_capture(pcap_filename, limit);
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+ } else {
+
+ try {
+ port->stop_rx_capture();
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+ }
+
+}
+
+void
+TrexRpcCmdSetRxFeature::parse_queue_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result) {
+ bool enabled = parse_bool(msg, "enabled", result);
+
+ if (enabled) {
+
+ uint64_t size = parse_uint32(msg, "size", result);
+
+ if (size == 0) {
+ generate_parse_err(result, "queue size cannot be zero");
+ }
+
+ try {
+ port->start_rx_queue(size);
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+ } else {
+
+ try {
+ port->stop_rx_queue();
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+ }
+
+}
+
+void
+TrexRpcCmdSetRxFeature::parse_server_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result) {
+}
+
+
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetRxQueuePkts::_run(const Json::Value &params, Json::Value &result) {
+
+ uint8_t port_id = parse_port(params, result);
+
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+
+ try {
+ const RXPacketBuffer *pkt_buffer = port->get_rx_queue_pkts();
+ if (pkt_buffer) {
+ result["result"]["pkts"] = pkt_buffer->to_json();
+ delete pkt_buffer;
+
+ } else {
+ result["result"]["pkts"] = Json::arrayValue;
+ }
+
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+
+ return (TREX_RPC_CMD_OK);
+}
+
+
+/**
+ * configures a port in L2 mode
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdSetL2::_run(const Json::Value &params, Json::Value &result) {
+ uint8_t port_id = parse_port(params, result);
+
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+
+ const std::string dst_mac_str = parse_string(params, "dst_mac", result);
+
+ uint8_t dst_mac[6];
+ if (!utl_str_to_macaddr(dst_mac_str, dst_mac)) {
+ std::stringstream ss;
+ ss << "'invalid MAC address: '" << dst_mac_str << "'";
+ generate_parse_err(result, ss.str());
+ }
+
+ try {
+ port->set_l2_mode(dst_mac);
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * configures a port in L3 mode
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdSetL3::_run(const Json::Value &params, Json::Value &result) {
+ uint8_t port_id = parse_port(params, result);
+
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+
+ const std::string src_ipv4_str = parse_string(params, "src_addr", result);
+ const std::string dst_ipv4_str = parse_string(params, "dst_addr", result);
+
+ uint32_t src_ipv4;
+ if (!utl_ipv4_to_uint32(src_ipv4_str.c_str(), src_ipv4)) {
+ std::stringstream ss;
+ ss << "invalid source IPv4 address: '" << src_ipv4_str << "'";
+ generate_parse_err(result, ss.str());
+ }
+
+ uint32_t dst_ipv4;
+ if (!utl_ipv4_to_uint32(dst_ipv4_str.c_str(), dst_ipv4)) {
+ std::stringstream ss;
+ ss << "invalid destination IPv4 address: '" << dst_ipv4_str << "'";
+ generate_parse_err(result, ss.str());
+ }
+
+
+
+ /* did we get a resolved MAC as well ? */
+ if (params["resolved_mac"] != Json::Value::null) {
+ const std::string resolved_mac = parse_string(params, "resolved_mac", result);
+
+ uint8_t mac[6];
+ if (!utl_str_to_macaddr(resolved_mac, mac)) {
+ std::stringstream ss;
+ ss << "'invalid MAC address: '" << resolved_mac << "'";
+ generate_parse_err(result, ss.str());
+ }
+
+ try {
+ port->set_l3_mode(src_ipv4, dst_ipv4, mac);
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+ } else {
+ try {
+ port->set_l3_mode(src_ipv4, dst_ipv4);
+ } catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+ }
+
+ return (TREX_RPC_CMD_OK);
+
+}
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index c950e011..3f73a5d7 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -40,7 +40,7 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
uint8_t port_id = parse_port(params, result);
- uint32_t stream_id = parse_int(params, "stream_id", result);
+ uint32_t stream_id = parse_uint32(params, "stream_id", result);
const Json::Value &section = parse_object(params, "stream", result);
@@ -62,7 +62,7 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
stream->m_random_seed = parse_uint32(section, "random_seed", result,0); /* default is zero */
/* inter stream gap */
- stream->m_isg_usec = parse_double(section, "isg", result);
+ stream->m_isg_usec = parse_udouble(section, "isg", result);
stream->m_next_stream_id = parse_int(section, "next_stream_id", result);
@@ -114,7 +114,7 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
generate_parse_err(result, "RX stats is not supported on this interface");
}
- stream->m_rx_check.m_pg_id = parse_int(rx, "stream_id", result);
+ stream->m_rx_check.m_pg_id = parse_uint32(rx, "stream_id", result);
std::string type = parse_string(rx, "rule_type", result);
if (type == "latency") {
stream->m_rx_check.m_rule_type = TrexPlatformApi::IF_STAT_PAYLOAD;
@@ -155,7 +155,7 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value &section, uint8_t por
} else if (type == "single_burst") {
- uint32_t total_pkts = parse_int(mode, "total_pkts", result);
+ uint32_t total_pkts = parse_uint32(mode, "total_pkts", result);
stream.reset(new TrexStream(TrexStream::stSINGLE_BURST, port_id, stream_id));
stream->set_single_burst(total_pkts);
@@ -163,9 +163,9 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value &section, uint8_t por
} else if (type == "multi_burst") {
- double ibg_usec = parse_double(mode, "ibg", result);
- uint32_t num_bursts = parse_int(mode, "count", result);
- uint32_t pkts_per_burst = parse_int(mode, "pkts_per_burst", result);
+ double ibg_usec = parse_udouble(mode, "ibg", result);
+ uint32_t num_bursts = parse_uint32(mode, "count", result);
+ uint32_t pkts_per_burst = parse_uint32(mode, "pkts_per_burst", result);
stream.reset(new TrexStream(TrexStream::stMULTI_BURST,port_id, stream_id ));
stream->set_multi_burst(pkts_per_burst,num_bursts,ibg_usec);
@@ -186,12 +186,7 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value &section, uint8_t por
void
TrexRpcCmdAddStream::parse_rate(const Json::Value &rate, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
- double value = parse_double(rate, "value", result);
- if (value <= 0) {
- std::stringstream ss;
- ss << "rate value must be a positive number - got: '" << value << "'";
- generate_parse_err(result, ss.str());
- }
+ double value = parse_udouble(rate, "value", result);
auto rate_types = {"pps", "bps_L1", "bps_L2", "percentage"};
std::string rate_type = parse_choice(rate, "type", rate_types, result);
@@ -533,7 +528,7 @@ TrexRpcCmdRemoveStream::_run(const Json::Value &params, Json::Value &result) {
uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
- uint32_t stream_id = parse_int(params, "stream_id", result);
+ uint32_t stream_id = parse_uint32(params, "stream_id", result);
TrexStream *stream = port->get_stream_by_id(stream_id);
if (!stream) {
@@ -615,7 +610,7 @@ TrexRpcCmdGetStream::_run(const Json::Value &params, Json::Value &result) {
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
bool get_pkt = parse_bool(params, "get_pkt", result);
- uint32_t stream_id = parse_int(params, "stream_id", result);
+ uint32_t stream_id = parse_uint32(params, "stream_id", result);
TrexStream *stream = port->get_stream_by_id(stream_id);
@@ -660,9 +655,9 @@ TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
std::string type = parse_choice(mul_obj, "type", TrexPortMultiplier::g_types, result);
std::string op = parse_string(mul_obj, "op", result);
- double value = parse_double(mul_obj, "value", result);
+ double value = parse_udouble(mul_obj, "value", result);
- if ( value <=0 ){
+ if ( value == 0 ){
generate_parse_err(result, "multiplier can't be zero");
}
@@ -670,6 +665,7 @@ TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
generate_parse_err(result, "start message can only specify absolute speed rate");
}
+ dsec_t ts = now_sec();
TrexPortMultiplier mul(type, op, value);
try {
@@ -680,7 +676,8 @@ TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
}
result["result"]["multiplier"] = port->get_multiplier();
-
+ result["result"]["ts"] = ts;
+
return (TREX_RPC_CMD_OK);
}
diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h
index 5fde1d0c..6639be7b 100644
--- a/src/rpc-server/commands/trex_rpc_cmds.h
+++ b/src/rpc-server/commands/trex_rpc_cmds.h
@@ -27,6 +27,7 @@ limitations under the License.
#include <memory>
class TrexStream;
+class TrexStatelessPort;
/* all the RPC commands decl. goes here */
@@ -89,10 +90,15 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdRelease, "release", 1, true, APIClass:
*/
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStats, "get_port_stats", 1, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStatus, "get_port_status", 1, false, APIClass::API_CLASS_TYPE_CORE);
-TREX_RPC_CMD_DEFINE(TrexRpcCmdSetPortAttr, "set_port_attr", 2, true, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortXStatsValues, "get_port_xstats_values", 1, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortXStatsNames, "get_port_xstats_names", 1, false, APIClass::API_CLASS_TYPE_CORE);
+TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdSetPortAttr, "set_port_attr", 2, true, APIClass::API_CLASS_TYPE_CORE,
+
+ int parse_rx_filter_mode(const Json::Value &msg, uint8_t port_id, Json::Value &result);
+);
+
+
/**
* stream cmds
*/
@@ -144,5 +150,16 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdPushRemote, "push_remote", 6, true, APIClass::API_
TREX_RPC_CMD_DEFINE(TrexRpcCmdShutdown, "shutdown", 2, false, APIClass::API_CLASS_TYPE_CORE);
+TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdSetRxFeature, "set_rx_feature", 3, false, APIClass::API_CLASS_TYPE_CORE,
+ void parse_capture_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result);
+ void parse_queue_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result);
+ void parse_server_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result);
+
+);
+
+TREX_RPC_CMD_DEFINE(TrexRpcCmdSetL2, "set_l2", 2, false, APIClass::API_CLASS_TYPE_CORE);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdSetL3, "set_l3", 3, false, APIClass::API_CLASS_TYPE_CORE);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetRxQueuePkts, "get_rx_queue_pkts", 2, false, APIClass::API_CLASS_TYPE_CORE);
+
#endif /* __TREX_RPC_CMD_H__ */
diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp
index 265d426b..6c56a59f 100644
--- a/src/rpc-server/trex_rpc_cmd.cpp
+++ b/src/rpc-server/trex_rpc_cmd.cpp
@@ -153,6 +153,8 @@ TrexRpcCommand::type_to_str(field_type_e type) {
return "int";
case FIELD_TYPE_DOUBLE:
return "double";
+ case FIELD_TYPE_UDOUBLE:
+ return "unsigned double";
case FIELD_TYPE_OBJ:
return "object";
case FIELD_TYPE_STR:
@@ -176,7 +178,7 @@ TrexRpcCommand::json_type_to_name(const Json::Value &value) {
case Json::uintValue:
return "uint";
case Json::realValue:
- return "real";
+ return "double";
case Json::stringValue:
return "string";
case Json::booleanValue:
@@ -223,31 +225,41 @@ TrexRpcCommand::check_field_type(const Json::Value &parent, const std::string &n
void
TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::string &name, field_type_e type, Json::Value &result) {
- std::stringstream ss;
+ std::string specific_err;
/* first check if field exists */
if (field == Json::Value::null) {
- ss << "field '" << name << "' is missing";
- generate_parse_err(result, ss.str());
+ specific_err = "field '" + name + "' is missing";
+ generate_parse_err(result, specific_err);
}
bool rc = true;
+ specific_err = "is '" + std::string(json_type_to_name(field)) + "', expecting '" + std::string(type_to_str(type)) + "'";
switch (type) {
case FIELD_TYPE_BYTE:
- if ( (!field.isUInt()) || (field.asInt() > 0xFF)) {
+ if (!field.isUInt64()) {
+ rc = false;
+ } else if (field.asUInt64() > 0xFF) {
+ specific_err = "has size bigger than uint8.";
rc = false;
}
break;
case FIELD_TYPE_UINT16:
- if ( (!field.isUInt()) || (field.asInt() > 0xFFFF)) {
+ if (!field.isUInt64()) {
+ rc = false;
+ } else if (field.asUInt64() > 0xFFFF) {
+ specific_err = "has size bigger than uint16.";
rc = false;
}
break;
case FIELD_TYPE_UINT32:
- if ( (!field.isUInt()) || (field.asUInt() > 0xFFFFFFFF)) {
+ if (!field.isUInt64()) {
+ rc = false;
+ } else if (field.asUInt64() > 0xFFFFFFFF) {
+ specific_err = "has size bigger than uint32.";
rc = false;
}
break;
@@ -276,6 +288,15 @@ TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::str
}
break;
+ case FIELD_TYPE_UDOUBLE:
+ if (!field.isDouble()) {
+ rc = false;
+ } else if (field.asDouble() < 0) {
+ specific_err = "has negative value.";
+ rc = false;
+ }
+ break;
+
case FIELD_TYPE_OBJ:
if (!field.isObject()) {
rc = false;
@@ -300,8 +321,7 @@ TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::str
}
if (!rc) {
- ss << "error at offset: " << field.getOffsetStart() << " - '" << name << "' is '" << json_type_to_name(field) << "', expecting '" << type_to_str(type) << "'";
- generate_parse_err(result, ss.str());
+ generate_parse_err(result, "error at offset: " + std::to_string(field.getOffsetStart()) + " - '" + name + "' " + specific_err);
}
}
diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h
index de0f5b58..2536f69c 100644
--- a/src/rpc-server/trex_rpc_cmd_api.h
+++ b/src/rpc-server/trex_rpc_cmd_api.h
@@ -114,6 +114,7 @@ protected:
FIELD_TYPE_UINT64,
FIELD_TYPE_INT,
FIELD_TYPE_DOUBLE,
+ FIELD_TYPE_UDOUBLE,
FIELD_TYPE_BOOL,
FIELD_TYPE_STR,
FIELD_TYPE_OBJ,
@@ -184,6 +185,11 @@ protected:
return parent[param].asDouble();
}
+ template<typename T> double parse_udouble(const Json::Value &parent, const T &param, Json::Value &result) {
+ check_field_type(parent, param, FIELD_TYPE_UDOUBLE, result);
+ return parent[param].asDouble();
+ }
+
template<typename T> bool parse_bool(const Json::Value &parent, const T &param, Json::Value &result) {
check_field_type(parent, param, FIELD_TYPE_BOOL, result);
return parent[param].asBool();
@@ -256,6 +262,20 @@ protected:
return parse_double(parent, param, result);
}
+ template<typename T> double parse_udouble(const Json::Value &parent, const T &param, Json::Value &result, double def) {
+ /* if not exists - default */
+ if (parent[param] == Json::Value::null) {
+ if (def < 0) {
+ std::stringstream ss;
+ ss << "default value of '" << param << "' is negative (please report)";
+ generate_parse_err(result, ss.str());
+ } else {
+ return def;
+ }
+ }
+ return parse_udouble(parent, param, result);
+ }
+
template<typename T> bool parse_bool(const Json::Value &parent, const T &param, Json::Value &result, bool def) {
/* if not exists - default */
if (parent[param] == Json::Value::null) {
diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp
index cddf19b9..94a3e1b9 100644
--- a/src/rpc-server/trex_rpc_cmds_table.cpp
+++ b/src/rpc-server/trex_rpc_cmds_table.cpp
@@ -71,6 +71,12 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
register_command(new TrexRpcCmdPushRemote());
register_command(new TrexRpcCmdShutdown());
+
+ register_command(new TrexRpcCmdSetRxFeature());
+ register_command(new TrexRpcCmdGetRxQueuePkts());
+
+ register_command(new TrexRpcCmdSetL2());
+ register_command(new TrexRpcCmdSetL3());
}
diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp
index 4fa2447d..d08de4e1 100644
--- a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp
+++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp
@@ -235,3 +235,12 @@ TrexJsonRpcV2Parser::generate_common_error(Json::Value &json, const std::string
}
+void
+TrexJsonRpcV2Parser::generate_common_error(std::string &response, const std::string &specific_err) {
+ Json::Value resp_json;
+ Json::FastWriter writer;
+
+ generate_common_error(resp_json, specific_err);
+ response = writer.write(resp_json);
+}
+
diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h
index 0563f21d..d91cbe2d 100644
--- a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h
+++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h
@@ -89,6 +89,15 @@ public:
static void generate_common_error(Json::Value &json, const std::string &specific_err);
/**
+ * will generate a valid JSON RPC v2 error message with
+ * generic error code and message
+ *
+ * @author imarom (16-Sep-15)
+ *
+ */
+ static void generate_common_error(std::string &response, const std::string &specific_err);
+
+ /**
* *tries* to generate a pretty string from JSON
* if json_str is not a valid JSON string
* it will duplicate the source
diff --git a/src/rpc-server/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp
index 28bf1d80..e762b8c1 100644
--- a/src/rpc-server/trex_rpc_req_resp_server.cpp
+++ b/src/rpc-server/trex_rpc_req_resp_server.cpp
@@ -171,7 +171,12 @@ void TrexRpcServerReqRes::_stop_rpc_thread() {
void TrexRpcServerReqRes::handle_request(const std::string &request) {
std::string response;
- process_request(request, response);
+ if ( request.size() > MAX_RPC_MSG_LEN ) {
+ std::string err_msg = "Request is too large (" + std::to_string(request.size()) + " bytes). Consider splitting to smaller chunks.";
+ TrexJsonRpcV2Parser::generate_common_error(response, err_msg);
+ } else {
+ process_request(request, response);
+ }
zmq_send(m_socket, response.c_str(), response.size(), 0);
}
@@ -244,7 +249,12 @@ void TrexRpcServerReqRes::process_zipped_request(const std::string &request, std
/* process the request */
std::string raw_response;
- process_request_raw(unzipped, raw_response);
+ if ( unzipped.size() > MAX_RPC_MSG_LEN ) {
+ std::string err_msg = "Request is too large (" + std::to_string(unzipped.size()) + " bytes). Consider splitting to smaller chunks.";
+ TrexJsonRpcV2Parser::generate_common_error(raw_response, err_msg);
+ } else {
+ process_request_raw(unzipped, raw_response);
+ }
TrexRpcZip::compress(raw_response, response);
@@ -256,18 +266,14 @@ void TrexRpcServerReqRes::process_zipped_request(const std::string &request, std
*/
void
TrexRpcServerReqRes::handle_server_error(const std::string &specific_err) {
- Json::FastWriter writer;
- Json::Value response;
+ std::string response;
/* generate error */
TrexJsonRpcV2Parser::generate_common_error(response, specific_err);
- /* write the JSON to string and sever on ZMQ */
- std::string response_str = writer.write(response);
-
- verbose_json("Server Replied: ", response_str);
+ verbose_json("Server Replied: ", response);
- zmq_send(m_socket, response_str.c_str(), response_str.size(), 0);
+ zmq_send(m_socket, response.c_str(), response.size(), 0);
}
diff --git a/src/rpc-server/trex_rpc_req_resp_server.h b/src/rpc-server/trex_rpc_req_resp_server.h
index 92d51a2a..9a994044 100644
--- a/src/rpc-server/trex_rpc_req_resp_server.h
+++ b/src/rpc-server/trex_rpc_req_resp_server.h
@@ -53,6 +53,7 @@ protected:
void *m_context;
void *m_socket;
+ static const uint32_t MAX_RPC_MSG_LEN = 999999;
};
/**
diff --git a/src/rx_check.cpp b/src/rx_check.cpp
index bfaa4ddb..d7eecede 100755
--- a/src/rx_check.cpp
+++ b/src/rx_check.cpp
@@ -255,7 +255,9 @@ bool RxCheckManager::Create(){
void RxCheckManager::handle_packet(CRx_check_header * rxh){
- //rxh->dump(stdout);
+ // m_stats.Dump(stdout);
+ //rxh->dump(stdout);
+
m_stats.m_total_rx++;
if ( rxh->m_magic != RX_CHECK_MAGIC ){
m_stats.m_err_no_magic++;
diff --git a/src/stateful_rx_core.cpp b/src/stateful_rx_core.cpp
index ebc51fcb..dced7360 100644
--- a/src/stateful_rx_core.cpp
+++ b/src/stateful_rx_core.cpp
@@ -33,7 +33,7 @@ const uint8_t sctp_pkt[]={
0x00,0x0e,0x2e,0x24,0x37,0x5f,
0x08,0x00,
- 0x45,0x02,0x00,0x30,
+ 0x45,0x03,0x00,0x30,
0x00,0x00,0x40,0x00,
0xff,0x84,0xbd,0x04,
0x9b,0xe6,0x18,0x9b, //sIP
@@ -57,7 +57,7 @@ const uint8_t icmp_pkt[]={
0x00,0x0e,0x2e,0x24,0x37,0x5f,
0x08,0x00,
- 0x45,0x02,0x00,0x30,
+ 0x45,0x03,0x00,0x30,
0x00,0x00,0x40,0x00,
0xff,0x01,0xbd,0x04,
0x9b,0xe6,0x18,0x9b, //SIP
@@ -126,32 +126,32 @@ void CLatencyPktInfo::Create(class CLatencyPktMode *m_l_pkt_info){
}
-rte_mbuf_t * CLatencyPktInfo::generate_pkt(int port_id,uint32_t extern_ip){
- bool is_client_to_server=(port_id%2==0)?true:false;
+rte_mbuf_t * CLatencyPktInfo::generate_pkt(int port_id, uint32_t extern_ip) {
+ bool is_client_to_server = (port_id % 2 == 0) ? true:false;
+ int dual_port_index = port_id >> 1;
+ uint32_t mask = dual_port_index * m_dual_port_mask;
+ uint32_t c = m_client_ip.v4;
+ uint32_t s = m_server_ip.v4;
- int dual_port_index=(port_id>>1);
- uint32_t c=m_client_ip.v4;
- uint32_t s=m_server_ip.v4;
- if ( extern_ip ){
- c=extern_ip;
+ if (is_client_to_server) {
+ if ( extern_ip ) {
+ m_dummy_node.m_src_ip = extern_ip;
+ } else {
+ m_dummy_node.m_src_ip = c + mask;
+ }
+ m_dummy_node.m_dest_ip = s + mask;
+ } else {
+ if ( extern_ip ) {
+ m_dummy_node.m_dest_ip = extern_ip;
+ } else {
+ m_dummy_node.m_dest_ip = c + mask;
+ }
+ m_dummy_node.m_src_ip = s + mask;
}
- if (!is_client_to_server) {
- /*swap */
- uint32_t t=c;
- c=s;
- s=t;
- }
- uint32_t mask=dual_port_index*m_dual_port_mask;
- if ( extern_ip==0 ){
- c+=mask;
- }
- s+=mask;
- m_dummy_node.m_src_ip = c;
- m_dummy_node.m_dest_ip = s;
+ rte_mbuf_t *m = m_pkt_info.generate_new_mbuf(&m_dummy_node);
- rte_mbuf_t * m=m_pkt_info.generate_new_mbuf(&m_dummy_node);
- return (m);
+ return m;
}
void CLatencyPktInfo::set_ip(uint32_t src,
@@ -461,8 +461,11 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) {
}
if ( (pkt_size-vlan_offset) != m_pkt_size ) {
- m_length_error++;
- return (false);
+ // patch for e1000 card. e1000 hands us the packet with Ethernet FCS, so it is 4 bytes longer
+ if ((pkt_size - vlan_offset - 4) != m_pkt_size ) {
+ m_length_error++;
+ return (false);
+ }
}
c_l_pkt_mode->update_recv(p + m_l4_offset + vlan_offset, &m_icmp_rx_seq, &m_icmp_tx_seq);
#ifdef LATENCY_DEBUG
@@ -588,32 +591,56 @@ void CLatencyManager::send_pkt_all_ports(){
}
}
-void CLatencyManager::send_grat_arp_all_ports() {
- for (int port_id = 0; port_id < m_max_ports; port_id++) {
- if (! CGlobalInfo::m_options.m_ip_cfg[port_id].grat_arp_needed())
- continue;
-
- CLatencyManagerPerPort * lp = &m_ports[port_id];
- rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id));
- assert(m);
- uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, 60); // ARP packet is shorter than 60
- uint32_t sip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip();
- uint8_t *src_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src;
- uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan();
- // gratuitous ARP. Requested IP is our source.
- CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id);
+double CLatencyManager::grat_arp_timeout() {
+ return (double)CGlobalInfo::m_options.m_arp_ref_per / m_arp_info.size();
+}
+
+void CLatencyManager::add_grat_arp_src(COneIPv4Info &ip) {
+ m_arp_info.insert(ip);
+}
+void CLatencyManager::send_one_grat_arp() {
+ const COneIPInfo *ip_info;
+ uint16_t port_id;
+ CLatencyManagerPerPort * lp;
+ rte_mbuf_t *m;
+ uint8_t src_mac[ETHER_ADDR_LEN];
+ uint16_t vlan;
+ uint32_t sip;
+
+ ip_info = m_arp_info.get_next();
+ if (!ip_info)
+ ip_info = m_arp_info.get_next();
+ // Two times NULL means there are no addresses
+ if (!ip_info)
+ return;
+
+ port_id = ip_info->get_port();
+ lp = &m_ports[port_id];
+ m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id));
+ assert(m);
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, ip_info->get_grat_arp_len());
+ ip_info->get_mac(src_mac);
+ vlan = ip_info->get_vlan();
+ switch(ip_info->ip_ver()) {
+ case COneIPInfo::IP4_VER:
+ sip = ((COneIPv4Info *)ip_info)->get_ip();
+ CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id);
if (CGlobalInfo::m_options.preview.getVMode() >= 3) {
- printf("Sending gratuitous ARP on port %d vlan:%d, sip:0x%08x\n", port_id, vlan, sip);
+ printf("Sending gratuitous ARP on port %d vlan:%d, sip:%s\n", port_id, vlan
+ , ip_to_str(sip).c_str());
utl_DumpBuffer(stdout, p, 60, 0);
}
-
if ( lp->m_io->tx(m) == 0 ) {
lp->m_port.m_ign_stats.m_tx_arp++;
lp->m_port.m_ign_stats.m_tot_bytes += 64; // mbuf size is smaller, but 64 bytes will be sent
} else {
lp->m_port.m_tx_pkt_err++;
}
+ break;
+ case COneIPInfo::IP6_VER:
+ //??? implement ipv6
+ break;
}
}
@@ -653,58 +680,6 @@ void CLatencyManager::handle_rx_pkt(CLatencyManagerPerPort * lp,
rte_pktmbuf_free(m);
}
-// In VM, we receive the RX packets in DP core, and send message to RX core with the packet
-void CLatencyManager::handle_latency_pkt_msg(uint8_t thread_id, CGenNodeLatencyPktInfo * msg) {
-
- assert(msg->m_latency_offset==0xdead);
-
- uint8_t rx_port_index=(thread_id<<1)+(msg->m_dir&1);
- assert( rx_port_index <m_max_ports ) ;
- CLatencyManagerPerPort * lp=&m_ports[rx_port_index];
- handle_rx_pkt(lp,(rte_mbuf_t *)msg->m_pkt);
-}
-
-
-void CLatencyManager::run_rx_queue_msgs(uint8_t thread_id,
- CNodeRing * r){
-
- while ( true ) {
- CGenNode * node;
- if ( r->Dequeue(node)!=0 ){
- break;
- }
- assert(node);
-
- CGenNodeMsgBase * msg=(CGenNodeMsgBase *)node;
-
- uint8_t msg_type = msg->m_msg_type;
- switch (msg_type ) {
- case CGenNodeMsgBase::LATENCY_PKT:
- handle_latency_pkt_msg(thread_id,(CGenNodeLatencyPktInfo *) msg);
- break;
- default:
- printf("ERROR latency-thread message type is not valid %d \n",msg_type);
- assert(0);
- }
-
- CGlobalInfo::free_node(node);
- }
-}
-
-// VM mode function. Handle messages from DP
-void CLatencyManager::try_rx_queues(){
-
- CMessagingManager * rx_dp = CMsgIns::Ins()->getRxDp();
- uint8_t threads=CMsgIns::Ins()->get_num_threads();
- int ti;
- for (ti=0; ti<(int)threads; ti++) {
- CNodeRing * r = rx_dp->getRingDpToCp(ti);
- if ( !r->isEmpty() ){
- run_rx_queue_msgs((uint8_t)ti,r);
- }
- }
-}
-
void CLatencyManager::try_rx(){
rte_mbuf_t * rx_pkts[64];
int i;
@@ -766,8 +741,6 @@ void CLatencyManager::start(int iter, bool activate_watchdog) {
m_p_queue.push(node);
}
- bool do_try_rx_queue = CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ? true : false;
-
if (activate_watchdog) {
m_monitor.create("STF RX CORE", 1);
TrexWatchDog::getInstance().register_monitor(&m_monitor);
@@ -783,9 +756,6 @@ void CLatencyManager::start(int iter, bool activate_watchdog) {
if (dt> (0.0)) {
break;
}
- if (do_try_rx_queue){
- try_rx_queues();
- }
try_rx();
rte_pause();
}
@@ -815,9 +785,9 @@ void CLatencyManager::start(int iter, bool activate_watchdog) {
case CGenNode::GRAT_ARP:
m_cpu_dp_u.start_work1();
- send_grat_arp_all_ports();
+ send_one_grat_arp();
m_p_queue.pop();
- node->m_time += (double)CGlobalInfo::m_options.m_arp_ref_per;
+ node->m_time += grat_arp_timeout();
m_p_queue.push(node);
m_cpu_dp_u.commit1();
break;
diff --git a/src/stateful_rx_core.h b/src/stateful_rx_core.h
index 3fa5892f..8744a58a 100644
--- a/src/stateful_rx_core.h
+++ b/src/stateful_rx_core.h
@@ -24,6 +24,7 @@ limitations under the License.
#include "bp_sim.h"
#include "flow_stat.h"
+#include "utl_ip.h"
#define L_PKT_SUBMODE_NO_REPLY 1
#define L_PKT_SUBMODE_REPLY 2
@@ -31,33 +32,6 @@ limitations under the License.
class TrexWatchDog;
-class CRXCoreIgnoreStat {
- friend class CCPortLatency;
- friend class CLatencyManager;
- public:
- inline CRXCoreIgnoreStat operator- (const CRXCoreIgnoreStat &t_in) {
- CRXCoreIgnoreStat t_out;
- t_out.m_tx_arp = this->m_tx_arp - t_in.m_tx_arp;
- t_out.m_tx_ipv6_n_solic = this->m_tx_ipv6_n_solic - t_in.m_tx_ipv6_n_solic;
- t_out.m_tot_bytes = this->m_tot_bytes - t_in.m_tot_bytes;
- return t_out;
- }
- uint64_t get_tx_bytes() {return m_tot_bytes;}
- uint64_t get_tx_pkts() {return m_tx_arp + m_tx_ipv6_n_solic;}
- uint64_t get_tx_arp() {return m_tx_arp;}
- uint64_t get_tx_n_solic() {return m_tx_ipv6_n_solic;}
- void clear() {
- m_tx_arp = 0;
- m_tx_ipv6_n_solic = 0;
- m_tot_bytes = 0;
- }
-
- private:
- uint64_t m_tx_arp;
- uint64_t m_tx_ipv6_n_solic;
- uint64_t m_tot_bytes;
-};
-
class CLatencyPktInfo {
public:
void Create(class CLatencyPktMode *m_l_pkt_info);
@@ -346,18 +320,16 @@ public:
return ( &m_nat_check_manager );
}
CLatencyPktMode *c_l_pkt_mode;
+ void add_grat_arp_src(COneIPv4Info &ip);
private:
void tickle();
void send_pkt_all_ports();
- void send_grat_arp_all_ports();
+ double grat_arp_timeout();
+ void send_one_grat_arp();
void try_rx();
- void try_rx_queues();
- void run_rx_queue_msgs(uint8_t thread_id, CNodeRing * r);
void wait_for_rx_dump();
void handle_rx_pkt(CLatencyManagerPerPort * lp, rte_mbuf_t * m);
- /* messages handlers */
- void handle_latency_pkt_msg(uint8_t thread_id, CGenNodeLatencyPktInfo * msg);
private:
pqueue_t m_p_queue; /* priorty queue */
@@ -374,7 +346,7 @@ private:
CCpuUtlDp m_cpu_dp_u;
CCpuUtlCp m_cpu_cp_u;
TrexMonitor m_monitor;
-
+ CManyIPInfo m_arp_info; // for grat ARP
volatile bool m_do_stop __rte_cache_aligned ;
};
diff --git a/src/stateless/cp/trex_exception.h b/src/stateless/cp/trex_exception.h
index c12732ef..ffc2f734 100644
--- a/src/stateless/cp/trex_exception.h
+++ b/src/stateless/cp/trex_exception.h
@@ -55,7 +55,10 @@ class TrexException : public std::runtime_error
T_FLOW_STAT_NO_FREE_HW_ID,
T_FLOW_STAT_RX_CORE_START_FAIL,
T_FLOW_STAT_BAD_HW_ID,
- T_INVALID
+
+ T_RX_PKT_PARSE_ERR,
+
+ T_INVALID,
};
TrexException() : std::runtime_error(""), m_type(T_INVALID) {
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index 9bb20990..e9b3c6d4 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -25,6 +25,7 @@ limitations under the License.
#include <trex_streams_compiler.h>
#include <common/basic_utils.h>
#include <common/captureFile.h>
+#include "trex_stateless_rx_defs.h"
#include <string>
@@ -98,20 +99,26 @@ protected:
************************************/
class StreamsFeeder {
public:
+
StreamsFeeder(TrexStatelessPort *port) {
-
/* start pesimistic */
m_success = false;
-
+
+ m_port = port;
+ }
+
+ void feed() {
+
/* fetch the original streams */
- port->get_object_list(m_in_streams);
+ m_port->get_object_list(m_in_streams);
for (const TrexStream *in_stream : m_in_streams) {
TrexStream *out_stream = in_stream->clone(true);
- get_stateless_obj()->m_rx_flow_stat.start_stream(out_stream);
-
m_out_streams.push_back(out_stream);
+
+ get_stateless_obj()->m_rx_flow_stat.start_stream(out_stream);
+
}
}
@@ -146,6 +153,8 @@ private:
vector<TrexStream *> m_in_streams;
vector<TrexStream *> m_out_streams;
bool m_success;
+
+ TrexStatelessPort *m_port;
};
@@ -156,9 +165,9 @@ private:
TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api) : m_dp_events(this) {
std::vector<std::pair<uint8_t, uint8_t>> core_pair_list;
- m_port_id = port_id;
- m_port_state = PORT_STATE_IDLE;
- m_platform_api = api;
+ m_port_id = port_id;
+ m_port_state = PORT_STATE_IDLE;
+ m_platform_api = api;
/* get the platform specific data */
api->get_interface_info(port_id, m_api_info);
@@ -262,6 +271,7 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration,
double factor = calculate_effective_factor(mul, force);
StreamsFeeder feeder(this);
+ feeder.feed();
/* compiler it */
std::vector<TrexStreamsCompiledObj *> compiled_objs;
@@ -501,6 +511,7 @@ TrexStatelessPort::update_traffic(const TrexPortMultiplier &mul, bool force) {
void
TrexStatelessPort::push_remote(const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
double duration,
@@ -540,6 +551,7 @@ TrexStatelessPort::push_remote(const std::string &pcap_filename,
m_pending_async_stop_event,
pcap_filename,
ipg_usec,
+ min_ipg_sec,
speedup,
count,
duration,
@@ -584,10 +596,9 @@ TrexStatelessPort::get_max_stream_id() const {
}
void
-TrexStatelessPort::get_properties(std::string &driver, uint32_t &speed) {
+TrexStatelessPort::get_properties(std::string &driver) {
driver = m_api_info.driver_name;
- speed = m_platform_api->getPortAttrObj(m_port_id)->get_link_speed();
}
bool
@@ -888,16 +899,6 @@ TrexStatelessPort::get_port_effective_rate(double &pps,
}
void
-TrexStatelessPort::get_macaddr(std::string &hw_macaddr,
- std::string &src_macaddr,
- std::string &dst_macaddr) {
-
- utl_macaddr_to_str(m_api_info.mac_info.hw_macaddr, hw_macaddr);
- utl_macaddr_to_str(m_api_info.mac_info.src_macaddr, src_macaddr);
- utl_macaddr_to_str(m_api_info.mac_info.dst_macaddr, dst_macaddr);
-}
-
-void
TrexStatelessPort::get_pci_info(std::string &pci_addr, int &numa_node) {
pci_addr = m_api_info.pci_addr;
numa_node = m_api_info.numa_node;
@@ -908,6 +909,9 @@ TrexStatelessPort::add_stream(TrexStream *stream) {
verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "add_stream");
+ if (m_stream_table.size() >= MAX_STREAMS) {
+ throw TrexException("Reached limit of " + std::to_string(MAX_STREAMS) + " streams at the port.");
+ }
get_stateless_obj()->m_rx_flow_stat.add_stream(stream);
m_stream_table.add_stream(stream);
@@ -944,6 +948,141 @@ TrexStatelessPort::remove_and_delete_all_streams() {
}
}
+void
+TrexStatelessPort::start_rx_capture(const std::string &pcap_filename, uint64_t limit) {
+ static MsgReply<bool> reply;
+
+ reply.reset();
+
+ TrexStatelessRxStartCapture *msg = new TrexStatelessRxStartCapture(m_port_id, pcap_filename, limit, reply);
+ send_message_to_rx((TrexStatelessCpToRxMsgBase *)msg);
+
+ /* as below, must wait for ACK from RX core before returning ACK */
+ reply.wait_for_reply();
+}
+
+void
+TrexStatelessPort::stop_rx_capture() {
+ TrexStatelessCpToRxMsgBase *msg = new TrexStatelessRxStopCapture(m_port_id);
+ send_message_to_rx(msg);
+}
+
+void
+TrexStatelessPort::start_rx_queue(uint64_t size) {
+ static MsgReply<bool> reply;
+
+ reply.reset();
+
+ TrexStatelessRxStartQueue *msg = new TrexStatelessRxStartQueue(m_port_id, size, reply);
+ send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+
+ /* we cannot return ACK to the user until the RX core has approved
+ this might cause the user to lose some packets from the queue
+ */
+ reply.wait_for_reply();
+}
+
+void
+TrexStatelessPort::stop_rx_queue() {
+ TrexStatelessCpToRxMsgBase *msg = new TrexStatelessRxStopQueue(m_port_id);
+ send_message_to_rx(msg);
+}
+
+
+const RXPacketBuffer *
+TrexStatelessPort::get_rx_queue_pkts() {
+ static MsgReply<const RXPacketBuffer *> reply;
+
+ reply.reset();
+
+ TrexStatelessRxQueueGetPkts *msg = new TrexStatelessRxQueueGetPkts(m_port_id, reply);
+ send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+
+ return reply.wait_for_reply();
+}
+
+
+/**
+ * configures port in L2 mode
+ *
+ */
+void
+TrexStatelessPort::set_l2_mode(const uint8_t *dest_mac) {
+
+ /* not valid under traffic */
+ verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "set_l2_mode");
+
+ /* no IPv4 src */
+ getPortAttrObj()->set_src_ipv4(0);
+
+ /* set destination as MAC */
+ getPortAttrObj()->get_dest().set_dest(dest_mac);
+
+ TrexStatelessRxSetL2Mode *msg = new TrexStatelessRxSetL2Mode(m_port_id);
+ send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+}
+
+/**
+ * configures port in L3 mode - unresolved
+ */
+void
+TrexStatelessPort::set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4) {
+
+ /* not valid under traffic */
+ verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "set_l3_mode");
+
+ /* set src IPv4 */
+ getPortAttrObj()->set_src_ipv4(src_ipv4);
+
+ /* set dest IPv4 */
+ getPortAttrObj()->get_dest().set_dest(dest_ipv4);
+
+ /* send RX core the relevant info */
+ CManyIPInfo ip_info;
+ ip_info.insert(COneIPv4Info(src_ipv4, 0, getPortAttrObj()->get_src_mac()));
+
+ TrexStatelessRxSetL3Mode *msg = new TrexStatelessRxSetL3Mode(m_port_id, ip_info, false);
+ send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+}
+
+/**
+ * configures port in L3 mode - resolved
+ *
+ */
+void
+TrexStatelessPort::set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4, const uint8_t *resolved_mac) {
+
+ verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "set_l3_mode");
+
+ /* set src IPv4 */
+ getPortAttrObj()->set_src_ipv4(src_ipv4);
+
+ /* set dest IPv4 + resolved MAC */
+ getPortAttrObj()->get_dest().set_dest(dest_ipv4, resolved_mac);
+
+ /* send RX core the relevant info */
+ CManyIPInfo ip_info;
+ ip_info.insert(COneIPv4Info(src_ipv4, 0, getPortAttrObj()->get_src_mac()));
+
+ bool is_grat_arp_needed = !getPortAttrObj()->is_loopback();
+
+ TrexStatelessRxSetL3Mode *msg = new TrexStatelessRxSetL3Mode(m_port_id, ip_info, is_grat_arp_needed);
+ send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+}
+
+
+Json::Value
+TrexStatelessPort::rx_features_to_json() {
+ static MsgReply<Json::Value> reply;
+
+ reply.reset();
+
+ TrexStatelessRxFeaturesToJson *msg = new TrexStatelessRxFeaturesToJson(m_port_id, reply);
+ send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+
+ return reply.wait_for_reply();
+}
+
/************* Trex Port Owner **************/
TrexPortOwner::TrexPortOwner() {
diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h
index e2a2aeba..d4ac4018 100644
--- a/src/stateless/cp/trex_stateless_port.h
+++ b/src/stateless/cp/trex_stateless_port.h
@@ -24,12 +24,15 @@ limitations under the License.
#include "common/basic_utils.h"
#include "internal_api/trex_platform_api.h"
#include "trex_dp_port_events.h"
+#include "trex_stateless_rx_defs.h"
#include "trex_stream.h"
class TrexStatelessCpToDpMsgBase;
class TrexStatelessCpToRxMsgBase;
class TrexStreamsGraphObj;
class TrexPortMultiplier;
+class RXPacketBuffer;
+
/**
* TRex port owner can perform
@@ -218,6 +221,7 @@ public:
*/
void push_remote(const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
double duration,
@@ -255,11 +259,8 @@ public:
* @author imarom (16-Sep-15)
*
* @param driver
- * @param speed
*/
- void get_properties(std::string &driver, uint32_t &speed);
-
-
+ void get_properties(std::string &driver);
/**
* encode stats as JSON
@@ -362,14 +363,71 @@ public:
double &bps_L2,
double &percentage);
+ void get_pci_info(std::string &pci_addr, int &numa_node);
- void get_macaddr(std::string &hw_macaddr,
- std::string &src_macaddr,
- std::string &dst_macaddr);
- void get_pci_info(std::string &pci_addr, int &numa_node);
+ /**
+ * enable RX capture on port
+ *
+ */
+ void start_rx_capture(const std::string &pcap_filename, uint64_t limit);
+
+ /**
+ * disable RX capture if on
+ *
+ */
+ void stop_rx_capture();
+
+ /**
+ * start RX queueing of packets
+ *
+ * @author imarom (11/7/2016)
+ *
+ * @param limit
+ */
+ void start_rx_queue(uint64_t limit);
+ /**
+ * stop RX queueing
+ *
+ * @author imarom (11/7/2016)
+ */
+ void stop_rx_queue();
+ /**
+ * fetch the RX queue packets from the queue
+ *
+ */
+ const RXPacketBuffer *get_rx_queue_pkts();
+
+ /**
+ * configures port for L2 mode
+ *
+ */
+ void set_l2_mode(const uint8_t *dest_mac);
+
+ /**
+ * configures port in L3 mode
+ *
+ */
+ void set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4);
+ void set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4, const uint8_t *resolved_mac);
+
+ /**
+ * generate a JSON describing the status
+ * of the RX features
+ *
+ */
+ Json::Value rx_features_to_json();
+
+ /**
+ * return the port attribute object
+ *
+ */
+ TRexPortAttr *getPortAttrObj() {
+ return m_platform_api->getPortAttrObj(m_port_id);
+ }
+
private:
bool is_core_active(int core_id);
@@ -401,7 +459,7 @@ private:
*
*/
void send_message_to_rx(TrexStatelessCpToRxMsgBase *msg);
-
+
/**
* when a port stops, perform various actions
*
@@ -456,6 +514,8 @@ private:
TrexPortOwner m_owner;
int m_pending_async_stop_event;
+ static const uint32_t MAX_STREAMS = 20000;
+
};
@@ -502,9 +562,9 @@ public:
static const std::initializer_list<std::string> g_types;
static const std::initializer_list<std::string> g_ops;
- mul_type_e m_type;
- mul_op_e m_op;
- double m_value;
+ mul_type_e m_type;
+ mul_op_e m_op;
+ double m_value;
};
#endif /* __TREX_STATELESS_PORT_H__ */
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp
index 857ac8f9..6f9376c2 100644
--- a/src/stateless/dp/trex_stateless_dp_core.cpp
+++ b/src/stateless/dp/trex_stateless_dp_core.cpp
@@ -478,6 +478,7 @@ bool TrexStatelessDpPerPort::pause_traffic(uint8_t port_id){
bool TrexStatelessDpPerPort::push_pcap(uint8_t port_id,
const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
bool is_dual) {
@@ -508,6 +509,7 @@ bool TrexStatelessDpPerPort::push_pcap(uint8_t port_id,
slave_mac_addr,
pcap_filename,
ipg_usec,
+ min_ipg_sec,
speedup,
count,
is_dual);
@@ -1169,6 +1171,7 @@ TrexStatelessDpCore::push_pcap(uint8_t port_id,
int event_id,
const std::string &pcap_filename,
double ipg_usec,
+ double m_min_ipg_sec,
double speedup,
uint32_t count,
double duration,
@@ -1179,7 +1182,7 @@ TrexStatelessDpCore::push_pcap(uint8_t port_id,
lp_port->set_event_id(event_id);
/* delegate the command to the port */
- bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, speedup, count, is_dual);
+ bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, m_min_ipg_sec, speedup, count, is_dual);
if (!rc) {
/* report back that we stopped */
CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id);
@@ -1263,6 +1266,7 @@ bool CGenNodePCAP::create(uint8_t port_id,
const uint8_t *slave_mac_addr,
const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
bool is_dual) {
@@ -1275,13 +1279,14 @@ bool CGenNodePCAP::create(uint8_t port_id,
m_count = count;
m_is_dual = is_dual;
m_dir = dir;
+ m_min_ipg_sec = min_ipg_sec;
/* mark this node as slow path */
set_slow_path(true);
if (ipg_usec != -1) {
/* fixed IPG */
- m_ipg_sec = usec_to_sec(ipg_usec / speedup);
+ m_ipg_sec = std::max(min_ipg_sec, usec_to_sec(ipg_usec / speedup));
m_speedup = 0;
} else {
/* packet IPG */
@@ -1304,9 +1309,7 @@ bool CGenNodePCAP::create(uint8_t port_id,
m_raw_packet = new CCapPktRaw();
if ( m_reader->ReadPacket(m_raw_packet) == false ){
- /* handle error */
- delete m_reader;
- return (false);
+ return false;
}
/* set the dir */
diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h
index b386daf7..e880a6eb 100644
--- a/src/stateless/dp/trex_stateless_dp_core.h
+++ b/src/stateless/dp/trex_stateless_dp_core.h
@@ -74,6 +74,7 @@ public:
bool push_pcap(uint8_t port_id,
const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
bool is_dual);
@@ -183,6 +184,7 @@ public:
int event_id,
const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
double duration,
diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h
index dda3113a..bc7be057 100644
--- a/src/stateless/dp/trex_stream_node.h
+++ b/src/stateless/dp/trex_stream_node.h
@@ -468,6 +468,7 @@ public:
const uint8_t *slave_mac_addr,
const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
bool is_dual);
@@ -536,7 +537,7 @@ public:
if (m_ipg_sec != -1) {
return m_ipg_sec;
} else {
- return ((m_raw_packet->get_time() - m_last_pkt_time) / m_speedup);
+ return (std::max(m_min_ipg_sec, (m_raw_packet->get_time() - m_last_pkt_time) / m_speedup));
}
}
@@ -632,6 +633,7 @@ private:
double m_last_pkt_time;
double m_speedup;
double m_ipg_sec;
+ double m_min_ipg_sec;
uint32_t m_count;
double m_next_time_offset; /* in sec */
@@ -644,7 +646,7 @@ private:
bool m_is_dual;
/* pad to match the size of CGenNode */
- uint8_t m_pad_end[19];
+ uint8_t m_pad_end[11];
} __rte_cache_aligned;
diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp
index 95613b41..aeb1e677 100644
--- a/src/stateless/messaging/trex_stateless_messaging.cpp
+++ b/src/stateless/messaging/trex_stateless_messaging.cpp
@@ -191,6 +191,7 @@ TrexStatelessDpPushPCAP::handle(TrexStatelessDpCore *dp_core) {
m_event_id,
m_pcap_filename,
m_ipg_usec,
+ m_min_ipg_sec,
m_speedup,
m_count,
m_duration,
@@ -204,6 +205,7 @@ TrexStatelessDpPushPCAP::clone() {
m_event_id,
m_pcap_filename,
m_ipg_usec,
+ m_min_ipg_sec,
m_speedup,
m_count,
m_duration,
@@ -241,13 +243,15 @@ TrexDpPortEventMsg::handle() {
}
/************************* messages from CP to RX **********************/
-bool TrexStatelessRxStartMsg::handle (CRxCoreStateless *rx_core) {
- rx_core->work();
+bool TrexStatelessRxEnableLatency::handle (CRxCoreStateless *rx_core) {
+ rx_core->enable_latency();
+ m_reply.set_reply(true);
+
return true;
}
-bool TrexStatelessRxStopMsg::handle (CRxCoreStateless *rx_core) {
- rx_core->idle();
+bool TrexStatelessRxDisableLatency::handle (CRxCoreStateless *rx_core) {
+ rx_core->disable_latency();
return true;
}
@@ -255,3 +259,76 @@ bool TrexStatelessRxQuit::handle (CRxCoreStateless *rx_core) {
rx_core->quit();
return true;
}
+
+
+bool
+TrexStatelessRxStartCapture::handle(CRxCoreStateless *rx_core) {
+ rx_core->start_recorder(m_port_id, m_pcap_filename, m_limit);
+
+ /* mark as done */
+ m_reply.set_reply(true);
+
+ return true;
+}
+
+bool
+TrexStatelessRxStopCapture::handle(CRxCoreStateless *rx_core) {
+ rx_core->stop_recorder(m_port_id);
+
+ return true;
+}
+
+bool
+TrexStatelessRxStartQueue::handle(CRxCoreStateless *rx_core) {
+ rx_core->start_queue(m_port_id, m_size);
+
+ /* mark as done */
+ m_reply.set_reply(true);
+
+ return true;
+}
+
+bool
+TrexStatelessRxStopQueue::handle(CRxCoreStateless *rx_core) {
+ rx_core->stop_queue(m_port_id);
+
+ return true;
+}
+
+
+
+bool
+TrexStatelessRxQueueGetPkts::handle(CRxCoreStateless *rx_core) {
+ const RXPacketBuffer *pkt_buffer = rx_core->get_rx_queue_pkts(m_port_id);
+
+ /* set the reply */
+ m_reply.set_reply(pkt_buffer);
+
+ return true;
+}
+
+
+bool
+TrexStatelessRxFeaturesToJson::handle(CRxCoreStateless *rx_core) {
+ Json::Value output = rx_core->get_rx_port_mngr(m_port_id).to_json();
+
+ /* set the reply */
+ m_reply.set_reply(output);
+
+ return true;
+}
+
+bool
+TrexStatelessRxSetL2Mode::handle(CRxCoreStateless *rx_core) {
+ rx_core->get_rx_port_mngr(m_port_id).set_l2_mode();
+
+ return true;
+}
+
+bool
+TrexStatelessRxSetL3Mode::handle(CRxCoreStateless *rx_core) {
+ rx_core->get_rx_port_mngr(m_port_id).set_l3_mode(m_src_addr, m_is_grat_arp_needed);
+
+ return true;
+}
+
diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h
index fb2c27ab..72b92d11 100644
--- a/src/stateless/messaging/trex_stateless_messaging.h
+++ b/src/stateless/messaging/trex_stateless_messaging.h
@@ -24,11 +24,67 @@ limitations under the License.
#include "msg_manager.h"
#include "trex_dp_port_events.h"
+#include "trex_exception.h"
+#include "trex_stateless_rx_defs.h"
+#include "os_time.h"
+#include "utl_ip.h"
class TrexStatelessDpCore;
class CRxCoreStateless;
class TrexStreamsCompiledObj;
class CFlowGenListPerThread;
+class RXPacketBuffer;
+
+/**
+ * Generic message reply object
+ *
+ * @author imarom (11/27/2016)
+ */
+template<typename T> class MsgReply {
+
+public:
+
+ MsgReply() {
+ reset();
+ }
+
+ void reset() {
+ m_pending = true;
+ }
+
+ bool is_pending() const {
+ return m_pending;
+ }
+
+ void set_reply(const T &reply) {
+ m_reply = reply;
+
+ /* before marking as done make sure all stores are committed */
+ asm volatile("mfence" ::: "memory");
+ m_pending = false;
+ }
+
+ T wait_for_reply(int timeout_ms = 500, int backoff_ms = 1) {
+ int guard = timeout_ms;
+
+ while (is_pending()) {
+ guard -= backoff_ms;
+ if (guard < 0) {
+ throw TrexException("timeout: failed to get reply from core");
+ }
+
+ delay(backoff_ms);
+ }
+
+ return m_reply;
+
+ }
+
+protected:
+ volatile bool m_pending;
+ T m_reply;
+};
+
/**
* defines the base class for CP to DP messages
@@ -257,6 +313,7 @@ public:
int event_id,
const std::string &pcap_filename,
double ipg_usec,
+ double min_ipg_sec,
double speedup,
uint32_t count,
double duration,
@@ -265,6 +322,7 @@ public:
m_port_id = port_id;
m_event_id = event_id;
m_ipg_usec = ipg_usec;
+ m_min_ipg_sec = min_ipg_sec;
m_speedup = speedup;
m_count = count;
m_duration = duration;
@@ -279,6 +337,7 @@ private:
std::string m_pcap_filename;
int m_event_id;
double m_ipg_usec;
+ double m_min_ipg_sec;
double m_speedup;
double m_duration;
uint32_t m_count;
@@ -312,7 +371,7 @@ private:
/************************* messages from DP to CP **********************/
/**
- * defines the base class for CP to DP messages
+ * defines the base class for DP to CP messages
*
* @author imarom (27-Oct-15)
*/
@@ -404,11 +463,19 @@ public:
};
-class TrexStatelessRxStartMsg : public TrexStatelessCpToRxMsgBase {
+
+class TrexStatelessRxEnableLatency : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxEnableLatency(MsgReply<bool> &reply) : m_reply(reply) {
+ }
+
bool handle (CRxCoreStateless *rx_core);
+
+private:
+ MsgReply<bool> &m_reply;
};
-class TrexStatelessRxStopMsg : public TrexStatelessCpToRxMsgBase {
+class TrexStatelessRxDisableLatency : public TrexStatelessCpToRxMsgBase {
bool handle (CRxCoreStateless *rx_core);
};
@@ -416,4 +483,151 @@ class TrexStatelessRxQuit : public TrexStatelessCpToRxMsgBase {
bool handle (CRxCoreStateless *rx_core);
};
+
+
+class TrexStatelessRxStartCapture : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxStartCapture(uint8_t port_id,
+ const std::string &pcap_filename,
+ uint64_t limit,
+ MsgReply<bool> &reply) : m_reply(reply) {
+
+ m_port_id = port_id;
+ m_limit = limit;
+ m_pcap_filename = pcap_filename;
+ }
+
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+ std::string m_pcap_filename;
+ uint64_t m_limit;
+ MsgReply<bool> &m_reply;
+};
+
+
+class TrexStatelessRxStopCapture : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxStopCapture(uint8_t port_id) {
+ m_port_id = port_id;
+ }
+
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+};
+
+
+class TrexStatelessRxStartQueue : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxStartQueue(uint8_t port_id,
+ uint64_t size,
+ MsgReply<bool> &reply) : m_reply(reply) {
+
+ m_port_id = port_id;
+ m_size = size;
+ }
+
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+ uint64_t m_size;
+ MsgReply<bool> &m_reply;
+};
+
+
+class TrexStatelessRxStopQueue : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxStopQueue(uint8_t port_id) {
+ m_port_id = port_id;
+ }
+
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+};
+
+
+
+class TrexStatelessRxQueueGetPkts : public TrexStatelessCpToRxMsgBase {
+public:
+
+ TrexStatelessRxQueueGetPkts(uint8_t port_id, MsgReply<const RXPacketBuffer *> &reply) : m_reply(reply) {
+ m_port_id = port_id;
+ }
+
+ /**
+ * virtual function to handle a message
+ *
+ */
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+ MsgReply<const RXPacketBuffer *> &m_reply;
+
+};
+
+/**
+ * updates the RX core that we are in L2 mode
+ */
+class TrexStatelessRxSetL2Mode : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxSetL2Mode(uint8_t port_id) {
+ m_port_id = port_id;
+ }
+
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+};
+
+/**
+ * updates the RX core that we are in a L3 mode
+ */
+class TrexStatelessRxSetL3Mode : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxSetL3Mode(uint8_t port_id,
+ const CManyIPInfo &src_addr,
+ bool is_grat_arp_needed) {
+
+ m_port_id = port_id;
+ m_src_addr = src_addr;
+ m_is_grat_arp_needed = is_grat_arp_needed;
+ }
+
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+ CManyIPInfo m_src_addr;
+ bool m_is_grat_arp_needed;
+};
+
+/**
+ * a request from RX core to dump to Json the RX features
+ */
+class TrexStatelessRxFeaturesToJson : public TrexStatelessCpToRxMsgBase {
+public:
+
+ TrexStatelessRxFeaturesToJson(uint8_t port_id, MsgReply<Json::Value> &reply) : m_reply(reply) {
+ m_port_id = port_id;
+ }
+
+ /**
+ * virtual function to handle a message
+ *
+ */
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+ MsgReply<Json::Value> &m_reply;
+};
+
#endif /* __TREX_STATELESS_MESSAGING_H__ */
diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp
index d162c5b3..d27485de 100644
--- a/src/stateless/rx/trex_stateless_rx_core.cpp
+++ b/src/stateless/rx/trex_stateless_rx_core.cpp
@@ -26,6 +26,8 @@
#include "pal/linux/sanb_atomic.h"
#include "trex_stateless_messaging.h"
#include "trex_stateless_rx_core.h"
+#include "trex_stateless.h"
+
void CRFC2544Info::create() {
m_latency.Create();
@@ -64,15 +66,7 @@ void CRFC2544Info::export_data(rfc2544_info_t_ &obj) {
obj.set_latency_json(json);
};
-void CCPortLatencyStl::reset() {
- for (int i = 0; i < MAX_FLOW_STATS; i++) {
- m_rx_pg_stat[i].clear();
- m_rx_pg_stat_payload[i].clear();
- }
-}
-
void CRxCoreStateless::create(const CRxSlCfg &cfg) {
- m_rcv_all = false;
m_capture = false;
m_max_ports = cfg.m_max_ports;
@@ -82,15 +76,21 @@ void CRxCoreStateless::create(const CRxSlCfg &cfg) {
m_ring_to_cp = cp_rx->getRingDpToCp(0);
m_state = STATE_IDLE;
- for (int i = 0; i < m_max_ports; i++) {
- CLatencyManagerPerPortStl * lp = &m_ports[i];
- lp->m_io = cfg.m_ports[i];
- lp->m_port.reset();
+ for (int i = 0; i < MAX_FLOW_STATS_PAYLOAD; i++) {
+ m_rfc2544[i].create();
}
+
m_cpu_cp_u.Create(&m_cpu_dp_u);
- for (int i = 0; i < MAX_FLOW_STATS_PAYLOAD; i++) {
- m_rfc2544[i].create();
+ /* create per port manager */
+ for (int i = 0; i < m_max_ports; i++) {
+ const TRexPortAttr *port_attr = get_stateless_obj()->get_platform_api()->getPortAttrObj(i);
+ m_rx_port_mngr[i].create(port_attr,
+ cfg.m_ports[i],
+ m_rfc2544,
+ &m_err_cntrs,
+ &m_cpu_dp_u,
+ cfg.m_num_crc_fix_bytes);
}
}
@@ -124,10 +124,31 @@ bool CRxCoreStateless::periodic_check_for_cp_messages() {
handle_cp_msg(msg);
}
+ /* a message might result in a change of state */
+ recalculate_next_state();
return true;
}
+void CRxCoreStateless::recalculate_next_state() {
+ if (m_state == STATE_QUIT) {
+ return;
+ }
+
+ /* next state is determine by the question are there any ports with active features ? */
+ m_state = (are_any_features_active() ? STATE_WORKING : STATE_IDLE);
+}
+
+bool CRxCoreStateless::are_any_features_active() {
+ for (int i = 0; i < m_max_ports; i++) {
+ if (m_rx_port_mngr[i].has_features_set()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void CRxCoreStateless::idle_state_loop() {
const int SHORT_DELAY_MS = 2;
const int LONG_DELAY_MS = 50;
@@ -141,7 +162,7 @@ void CRxCoreStateless::idle_state_loop() {
counter = 0;
continue;
} else {
- flush_rx();
+ flush_all_pending_pkts();
}
/* enter deep sleep only if enough time had passed */
@@ -154,284 +175,113 @@ void CRxCoreStateless::idle_state_loop() {
}
}
-void CRxCoreStateless::start() {
- int count = 0;
- int i = 0;
- bool do_try_rx_queue =CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ? true : false;
-
- /* register a watchdog handle on current core */
- m_monitor.create("STL RX CORE", 1);
- TrexWatchDog::getInstance().register_monitor(&m_monitor);
-
- while (true) {
- if (m_state == STATE_WORKING) {
- i++;
- if (i == 100000) { // approx 10msec
- i = 0;
- periodic_check_for_cp_messages(); // m_state might change in here
- }
- } else {
- if (m_state == STATE_QUIT)
- break;
- count = 0;
- i = 0;
- set_working_msg_ack(false);
- idle_state_loop();
- set_working_msg_ack(true);
- }
- if (do_try_rx_queue) {
- try_rx_queues();
- }
- count += try_rx();
+/**
+ * for each port give a tick (for flushing if needed)
+ *
+ */
+void CRxCoreStateless::port_manager_tick() {
+ for (int i = 0; i < m_max_ports; i++) {
+ m_rx_port_mngr[i].tick();
}
- rte_pause();
-
- m_monitor.disable();
}
-void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *m) {
- CFlowStatParser parser;
-
- if (m_rcv_all || parser.parse(rte_pktmbuf_mtod(m, uint8_t *), m->pkt_len) == 0) {
- uint32_t ip_id;
- if (m_rcv_all || (parser.get_ip_id(ip_id) == 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)) {
- 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 *)
- (p + m->pkt_len - sizeof(struct flow_stat_payload_header));
- hw_id = fsp_head->hw_id;
- CRFC2544Info *curr_rfc2544;
-
- if (unlikely(fsp_head->magic != FLOW_STAT_PAYLOAD_MAGIC) || hw_id >= MAX_FLOW_STATS_PAYLOAD) {
- good_packet = false;
- if (!m_rcv_all)
- m_err_cntrs.m_bad_header++;
- } else {
- curr_rfc2544 = &m_rfc2544[hw_id];
-
- if (fsp_head->flow_seq != curr_rfc2544->get_exp_flow_seq()) {
- // bad flow seq num
- // Might be the first packet of a new flow, packet from an old flow, or garbage.
-
- if (fsp_head->flow_seq == curr_rfc2544->get_prev_flow_seq()) {
- // packet from previous flow using this hw_id that arrived late
- good_packet = false;
- m_err_cntrs.m_old_flow++;
- } else {
- if (curr_rfc2544->no_flow_seq()) {
- // first packet we see from this flow
- good_packet = true;
- curr_rfc2544->set_exp_flow_seq(fsp_head->flow_seq);
- } else {
- // garbage packet
- good_packet = false;
- m_err_cntrs.m_bad_header++;
- }
- }
- }
- }
-
- if (good_packet) {
- uint32_t pkt_seq = fsp_head->seq;
- uint32_t exp_seq = curr_rfc2544->get_seq();
- if (unlikely(pkt_seq != exp_seq)) {
- if (pkt_seq < exp_seq) {
- if (exp_seq - pkt_seq > 100000) {
- // packet loss while we had wrap around
- curr_rfc2544->inc_seq_err(pkt_seq - exp_seq);
- curr_rfc2544->inc_seq_err_too_big();
- curr_rfc2544->set_seq(pkt_seq + 1);
- } else {
- if (pkt_seq == (exp_seq - 1)) {
- curr_rfc2544->inc_dup();
- } else {
- curr_rfc2544->inc_ooo();
- // We thought it was lost, but it was just out of order
- curr_rfc2544->dec_seq_err();
- }
- curr_rfc2544->inc_seq_err_too_low();
- }
- } else {
- if (unlikely (pkt_seq - exp_seq > 100000)) {
- // packet reorder while we had wrap around
- if (pkt_seq == (exp_seq - 1)) {
- curr_rfc2544->inc_dup();
- } else {
- curr_rfc2544->inc_ooo();
- // We thought it was lost, but it was just out of order
- curr_rfc2544->dec_seq_err();
- }
- curr_rfc2544->inc_seq_err_too_low();
- } else {
- // seq > curr_rfc2544->seq. Assuming lost packets
- curr_rfc2544->inc_seq_err(pkt_seq - exp_seq);
- curr_rfc2544->inc_seq_err_too_big();
- curr_rfc2544->set_seq(pkt_seq + 1);
- }
- }
- } else {
- curr_rfc2544->set_seq(pkt_seq + 1);
- }
- lp->m_port.m_rx_pg_stat_payload[hw_id].add_pkts(1);
- lp->m_port.m_rx_pg_stat_payload[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
- uint64_t d = (os_get_hr_tick_64() - fsp_head->time_stamp );
- dsec_t ctime = ptime_convert_hr_dsec(d);
- curr_rfc2544->add_sample(ctime);
- }
- } else {
- hw_id = get_hw_id(ip_id);
- if (hw_id < MAX_FLOW_STATS) {
- lp->m_port.m_rx_pg_stat[hw_id].add_pkts(1);
- lp->m_port.m_rx_pg_stat[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
- }
- }
- }
- }
+/**
+ * for each port handle the grat ARP mechansim
+ *
+ */
+void CRxCoreStateless::handle_grat_arp() {
+ for (int i = 0; i < m_max_ports; i++) {
+ m_rx_port_mngr[i].send_next_grat_arp();
}
}
-void CRxCoreStateless::capture_pkt(rte_mbuf_t *m) {
+void CRxCoreStateless::handle_work_stage() {
+
+ /* set the next sync time to */
+ dsec_t sync_time_sec = now_sec() + (1.0 / 1000);
+ dsec_t tick_time_sec = now_sec() + 1.0;
+ dsec_t grat_arp_sec = now_sec() + (double)CGlobalInfo::m_options.m_arp_ref_per;
-}
+ while (m_state == STATE_WORKING) {
+ process_all_pending_pkts();
-// In VM setup, handle packets coming as messages from DP cores.
-void CRxCoreStateless::handle_rx_queue_msgs(uint8_t thread_id, CNodeRing * r) {
- while ( true ) {
- CGenNode * node;
- if ( r->Dequeue(node) != 0 ) {
- break;
+ dsec_t now = now_sec();
+
+ /* until a scheduler is added here - dirty IFs */
+
+ if ( (now - sync_time_sec) > 0 ) {
+ periodic_check_for_cp_messages();
+ sync_time_sec = now + (1.0 / 1000);
+ }
+
+ if ( (now - tick_time_sec) > 0) {
+ port_manager_tick();
+ tick_time_sec = now + 1.0;
}
- assert(node);
- CGenNodeMsgBase * msg = (CGenNodeMsgBase *)node;
- CGenNodeLatencyPktInfo * l_msg;
- uint8_t msg_type = msg->m_msg_type;
- uint8_t rx_port_index;
- CLatencyManagerPerPortStl * lp;
-
- switch (msg_type) {
- case CGenNodeMsgBase::LATENCY_PKT:
- l_msg = (CGenNodeLatencyPktInfo *)msg;
- assert(l_msg->m_latency_offset == 0xdead);
- rx_port_index = (thread_id << 1) + (l_msg->m_dir & 1);
- assert( rx_port_index < m_max_ports );
- lp = &m_ports[rx_port_index];
- handle_rx_pkt(lp, (rte_mbuf_t *)l_msg->m_pkt);
- if (m_capture)
- capture_pkt((rte_mbuf_t *)l_msg->m_pkt);
- rte_pktmbuf_free((rte_mbuf_t *)l_msg->m_pkt);
- break;
- default:
- printf("ERROR latency-thread message type is not valid %d \n", msg_type);
- assert(0);
+ if ( (now - grat_arp_sec) > 0) {
+ handle_grat_arp();
+ grat_arp_sec = now + (double)CGlobalInfo::m_options.m_arp_ref_per;
}
- CGlobalInfo::free_node(node);
+ rte_pause();
+
}
}
-// VM mode function. Handle messages from DP
-void CRxCoreStateless::try_rx_queues() {
+void CRxCoreStateless::start() {
+ /* register a watchdog handle on current core */
+ m_monitor.create("STL RX CORE", 1);
+ TrexWatchDog::getInstance().register_monitor(&m_monitor);
- CMessagingManager * rx_dp = CMsgIns::Ins()->getRxDp();
- uint8_t threads=CMsgIns::Ins()->get_num_threads();
- int ti;
- for (ti = 0; ti < (int)threads; ti++) {
- CNodeRing * r = rx_dp->getRingDpToCp(ti);
- if ( ! r->isEmpty() ) {
- handle_rx_queue_msgs((uint8_t)ti, r);
+ recalculate_next_state();
+
+ while (m_state != STATE_QUIT) {
+ switch (m_state) {
+ case STATE_IDLE:
+ idle_state_loop();
+ break;
+ case STATE_WORKING:
+ handle_work_stage();
+ break;
+
+ default:
+ assert(0);
+ break;
}
+
}
-}
-// exactly the same as try_rx, without the handle_rx_pkt
-// purpose is to flush rx queues when core is in idle state
-void CRxCoreStateless::flush_rx() {
- rte_mbuf_t * rx_pkts[64];
- int i, total_pkts = 0;
- for (i = 0; i < m_max_ports; i++) {
- CLatencyManagerPerPortStl * lp = &m_ports[i];
- rte_mbuf_t * m;
- /* try to read 64 packets clean up the queue */
- uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
- total_pkts += cnt_p;
- if (cnt_p) {
- m_cpu_dp_u.start_work1();
- int j;
- for (j = 0; j < cnt_p; j++) {
- m = rx_pkts[j];
- rte_pktmbuf_free(m);
- }
- /* commit only if there was work to do ! */
- m_cpu_dp_u.commit1();
- }/* if work */
- }// all ports
+ m_monitor.disable();
}
-int CRxCoreStateless::try_rx() {
- rte_mbuf_t * rx_pkts[64];
- int i, total_pkts = 0;
- for (i = 0; i < m_max_ports; i++) {
- CLatencyManagerPerPortStl * lp = &m_ports[i];
- rte_mbuf_t * m;
- /* try to read 64 packets clean up the queue */
- uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
- total_pkts += cnt_p;
- if (cnt_p) {
- m_cpu_dp_u.start_work1();
- int j;
- for (j = 0; j < cnt_p; j++) {
- m = rx_pkts[j];
- handle_rx_pkt(lp, m);
- rte_pktmbuf_free(m);
- }
- /* commit only if there was work to do ! */
- m_cpu_dp_u.commit1();
- }/* if work */
- }// all ports
- return total_pkts;
-}
+void CRxCoreStateless::capture_pkt(rte_mbuf_t *m) {
-bool CRxCoreStateless::is_flow_stat_id(uint32_t id) {
- if ((id & 0x000fff00) == IP_ID_RESERVE_BASE) return true;
- return false;
}
-bool CRxCoreStateless::is_flow_stat_payload_id(uint32_t id) {
- if (id == FLOW_STAT_PAYLOAD_IP_ID) return true;
- return false;
-}
+int CRxCoreStateless::process_all_pending_pkts(bool flush_rx) {
+
+ int total_pkts = 0;
+ for (int i = 0; i < m_max_ports; i++) {
+ total_pkts += m_rx_port_mngr[i].process_all_pending_pkts(flush_rx);
+ }
+
+ return total_pkts;
-uint16_t CRxCoreStateless::get_hw_id(uint16_t id) {
- return (0x00ff & id);
}
void CRxCoreStateless::reset_rx_stats(uint8_t port_id) {
- for (int hw_id = 0; hw_id < MAX_FLOW_STATS; hw_id++) {
- m_ports[port_id].m_port.m_rx_pg_stat[hw_id].clear();
- }
+ m_rx_port_mngr[port_id].clear_stats();
}
int CRxCoreStateless::get_rx_stats(uint8_t port_id, rx_per_flow_t *rx_stats, int min, int max
, bool reset, TrexPlatformApi::driver_stat_cap_e type) {
- for (int hw_id = min; hw_id <= max; hw_id++) {
- if (type == TrexPlatformApi::IF_STAT_PAYLOAD) {
- rx_stats[hw_id - min] = m_ports[port_id].m_port.m_rx_pg_stat_payload[hw_id];
- } else {
- rx_stats[hw_id - min] = m_ports[port_id].m_port.m_rx_pg_stat[hw_id];
- }
- if (reset) {
- if (type == TrexPlatformApi::IF_STAT_PAYLOAD) {
- m_ports[port_id].m_port.m_rx_pg_stat_payload[hw_id].clear();
- } else {
- m_ports[port_id].m_port.m_rx_pg_stat[hw_id].clear();
- }
- }
- }
- return 0;
+
+ /* for now only latency stats */
+ m_rx_port_mngr[port_id].get_latency_stats(rx_stats, min, max, reset, type);
+
+ return (0);
+
}
int CRxCoreStateless::get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, int max, bool reset) {
@@ -458,13 +308,6 @@ int CRxCoreStateless::get_rx_err_cntrs(CRxCoreErrCntrs *rx_err) {
return 0;
}
-void CRxCoreStateless::set_working_msg_ack(bool val) {
- sanb_smp_memory_barrier();
- m_ack_start_work_msg = val;
- sanb_smp_memory_barrier();
-}
-
-
void CRxCoreStateless::update_cpu_util(){
m_cpu_cp_u.Update();
}
@@ -472,3 +315,58 @@ void CRxCoreStateless::update_cpu_util(){
double CRxCoreStateless::get_cpu_util() {
return m_cpu_cp_u.GetVal();
}
+
+
+void
+CRxCoreStateless::start_recorder(uint8_t port_id, const std::string &pcap_filename, uint64_t limit) {
+ m_rx_port_mngr[port_id].start_recorder(pcap_filename, limit);
+ recalculate_next_state();
+}
+
+void
+CRxCoreStateless::stop_recorder(uint8_t port_id) {
+ m_rx_port_mngr[port_id].stop_recorder();
+ recalculate_next_state();
+}
+
+void
+CRxCoreStateless::start_queue(uint8_t port_id, uint64_t size) {
+ m_rx_port_mngr[port_id].start_queue(size);
+ recalculate_next_state();
+}
+
+void
+CRxCoreStateless::stop_queue(uint8_t port_id) {
+ m_rx_port_mngr[port_id].stop_queue();
+ recalculate_next_state();
+}
+
+void
+CRxCoreStateless::enable_latency() {
+ for (int i = 0; i < m_max_ports; i++) {
+ m_rx_port_mngr[i].enable_latency();
+ }
+
+ recalculate_next_state();
+}
+
+void
+CRxCoreStateless::disable_latency() {
+ for (int i = 0; i < m_max_ports; i++) {
+ m_rx_port_mngr[i].disable_latency();
+ }
+
+ recalculate_next_state();
+}
+
+RXPortManager &
+CRxCoreStateless::get_rx_port_mngr(uint8_t port_id) {
+ assert(port_id < m_max_ports);
+ return m_rx_port_mngr[port_id];
+
+}
+
+void
+CRxCoreStateless::get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff) {
+ get_rx_port_mngr(port_id).get_ignore_stats(stat, get_diff);
+}
diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h
index 3f9fb6cc..4eed59a1 100644
--- a/src/stateless/rx/trex_stateless_rx_core.h
+++ b/src/stateless/rx/trex_stateless_rx_core.h
@@ -21,10 +21,12 @@
#ifndef __TREX_STATELESS_RX_CORE_H__
#define __TREX_STATELESS_RX_CORE_H__
#include <stdint.h>
+
#include "stateful_rx_core.h"
#include "os_time.h"
#include "pal/linux/sanb_atomic.h"
#include "utl_cpuu.h"
+#include "trex_stateless_rx_port_mngr.h"
class TrexStatelessCpToRxMsgBase;
@@ -37,25 +39,6 @@ class CCPortLatencyStl {
rx_per_flow_t m_rx_pg_stat_payload[MAX_FLOW_STATS_PAYLOAD];
};
-class CLatencyManagerPerPortStl {
-public:
- CCPortLatencyStl m_port;
- CPortLatencyHWBase * m_io;
-};
-
-class CRxSlCfg {
- public:
- CRxSlCfg (){
- m_max_ports = 0;
- m_cps = 0.0;
- }
-
- public:
- uint32_t m_max_ports;
- double m_cps;
- CPortLatencyHWBase * m_ports[TREX_MAX_PORTS];
-};
-
class CRFC2544Info {
public:
void create();
@@ -109,12 +92,20 @@ class CRxCoreErrCntrs {
m_old_flow = 0;
}
- private:
+ public:
uint64_t m_bad_header;
uint64_t m_old_flow;
};
+/**
+ * stateless RX core
+ *
+ */
class CRxCoreStateless {
+
+ /**
+ * core states
+ */
enum state_e {
STATE_IDLE,
STATE_WORKING,
@@ -129,47 +120,85 @@ class CRxCoreStateless {
, TrexPlatformApi::driver_stat_cap_e type);
int get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, int max, bool reset);
int get_rx_err_cntrs(CRxCoreErrCntrs *rx_err);
- void work() {
- m_state = STATE_WORKING;
- m_err_cntrs.reset(); // When starting to work, reset global counters
- }
- void idle() {m_state = STATE_IDLE;}
+
+
void quit() {m_state = STATE_QUIT;}
- bool is_working() const {return (m_ack_start_work_msg == true);}
- void set_working_msg_ack(bool val);
+ bool is_working() const {return (m_state == STATE_WORKING);}
double get_cpu_util();
void update_cpu_util();
+ const RXPacketBuffer *get_rx_queue_pkts(uint8_t port_id) {
+ return m_rx_port_mngr[port_id].get_pkt_buffer();
+ }
+
+ /**
+ * start capturing of RX packets on a specific port
+ *
+ */
+ void start_recorder(uint8_t port_id, const std::string &pcap_filename, uint64_t limit);
+ void stop_recorder(uint8_t port_id);
+
+ /**
+ * start RX queueing of packets
+ *
+ */
+ void start_queue(uint8_t port_id, uint64_t size);
+ void stop_queue(uint8_t port_id);
+
+ /**
+ * enable latency feature for RX packets
+ * will be apply to all ports
+ */
+ void enable_latency();
+ void disable_latency();
+
+ RXPortManager &get_rx_port_mngr(uint8_t port_id);
+
+ /**
+ * fetch the ignored stats for a port
+ *
+ */
+ void get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff);
private:
void handle_cp_msg(TrexStatelessCpToRxMsgBase *msg);
bool periodic_check_for_cp_messages();
void tickle();
void idle_state_loop();
- void handle_rx_pkt(CLatencyManagerPerPortStl * lp, rte_mbuf_t * m);
+
+ void recalculate_next_state();
+ bool are_any_features_active();
+
void capture_pkt(rte_mbuf_t *m);
void handle_rx_queue_msgs(uint8_t thread_id, CNodeRing * r);
- void flush_rx();
- int try_rx();
- void try_rx_queues();
- bool is_flow_stat_id(uint32_t id);
- bool is_flow_stat_payload_id(uint32_t id);
- uint16_t get_hw_id(uint16_t id);
+ void handle_work_stage();
+ void port_manager_tick();
+ void handle_grat_arp();
+
+ int process_all_pending_pkts(bool flush_rx = false);
+ void flush_all_pending_pkts() {
+ process_all_pending_pkts(true);
+ }
+
+ void try_rx_queues();
+
private:
- TrexMonitor m_monitor;
- uint32_t m_max_ports;
- bool m_capture;
- bool m_rcv_all;
- CLatencyManagerPerPortStl m_ports[TREX_MAX_PORTS];
- state_e m_state;
- CNodeRing *m_ring_from_cp;
- CNodeRing *m_ring_to_cp;
- CCpuUtlDp m_cpu_dp_u;
- CCpuUtlCp m_cpu_cp_u;
+ TrexMonitor m_monitor;
+ uint32_t m_max_ports;
+ bool m_capture;
+ state_e m_state;
+ CNodeRing *m_ring_from_cp;
+ CNodeRing *m_ring_to_cp;
+ CCpuUtlDp m_cpu_dp_u;
+ CCpuUtlCp m_cpu_cp_u;
+
// Used for acking "work" (go out of idle) messages from cp
volatile bool m_ack_start_work_msg __rte_cache_aligned;
+
CRxCoreErrCntrs m_err_cntrs;
CRFC2544Info m_rfc2544[MAX_FLOW_STATS_PAYLOAD];
+
+ RXPortManager m_rx_port_mngr[TREX_MAX_PORTS];
};
#endif
diff --git a/src/stateless/rx/trex_stateless_rx_defs.h b/src/stateless/rx/trex_stateless_rx_defs.h
new file mode 100644
index 00000000..aefcc133
--- /dev/null
+++ b/src/stateless/rx/trex_stateless_rx_defs.h
@@ -0,0 +1,62 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2016-2016 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.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef __TREX_STATELESS_RX_DEFS_H__
+#define __TREX_STATELESS_RX_DEFS_H__
+
+#include "trex_defs.h"
+#include <json/json.h>
+
+class CPortLatencyHWBase;
+
+
+/**
+ * general SL cfg
+ *
+ */
+class CRxSlCfg {
+ public:
+ CRxSlCfg (){
+ m_max_ports = 0;
+ m_cps = 0.0;
+ m_num_crc_fix_bytes = 0;
+ }
+
+ public:
+ uint32_t m_max_ports;
+ double m_cps;
+ CPortLatencyHWBase * m_ports[TREX_MAX_PORTS];
+ uint8_t m_num_crc_fix_bytes;
+};
+
+/**
+ * describes the filter type applied to the RX
+ * RX_FILTER_MODE_HW - only hardware filtered traffic will
+ * reach the RX core
+ *
+ */
+typedef enum rx_filter_mode_ {
+ RX_FILTER_MODE_HW,
+ RX_FILTER_MODE_ALL
+} rx_filter_mode_e;
+
+#endif /* __TREX_STATELESS_RX_DEFS_H__ */
+
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
new file mode 100644
index 00000000..5aac1ea6
--- /dev/null
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
@@ -0,0 +1,889 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2016-2016 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.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+#include "bp_sim.h"
+#include "trex_stateless_rx_port_mngr.h"
+#include "common/captureFile.h"
+#include "trex_stateless_rx_core.h"
+#include "common/Network/Packet/Arp.h"
+#include "pkt_gen.h"
+
+/**************************************
+ * latency RX feature
+ *
+ *************************************/
+RXLatency::RXLatency() {
+ m_rcv_all = false;
+ m_rfc2544 = NULL;
+ m_err_cntrs = NULL;
+
+ for (int i = 0; i < MAX_FLOW_STATS; i++) {
+ m_rx_pg_stat[i].clear();
+ m_rx_pg_stat_payload[i].clear();
+ }
+}
+
+void
+RXLatency::create(CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs) {
+ m_rfc2544 = rfc2544;
+ m_err_cntrs = err_cntrs;
+}
+
+void
+RXLatency::handle_pkt(const rte_mbuf_t *m) {
+ CFlowStatParser parser;
+
+ if (m_rcv_all || parser.parse(rte_pktmbuf_mtod(m, uint8_t *), m->pkt_len) == 0) {
+ uint32_t ip_id;
+ if (m_rcv_all || (parser.get_ip_id(ip_id) == 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)) {
+ 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 *)
+ (p + m->pkt_len - sizeof(struct flow_stat_payload_header));
+ hw_id = fsp_head->hw_id;
+ CRFC2544Info *curr_rfc2544;
+
+ if (unlikely(fsp_head->magic != FLOW_STAT_PAYLOAD_MAGIC) || hw_id >= MAX_FLOW_STATS_PAYLOAD) {
+ good_packet = false;
+ if (!m_rcv_all)
+ m_err_cntrs->m_bad_header++;
+ } else {
+ curr_rfc2544 = &m_rfc2544[hw_id];
+
+ if (fsp_head->flow_seq != curr_rfc2544->get_exp_flow_seq()) {
+ // bad flow seq num
+ // Might be the first packet of a new flow, packet from an old flow, or garbage.
+
+ if (fsp_head->flow_seq == curr_rfc2544->get_prev_flow_seq()) {
+ // packet from previous flow using this hw_id that arrived late
+ good_packet = false;
+ m_err_cntrs->m_old_flow++;
+ } else {
+ if (curr_rfc2544->no_flow_seq()) {
+ // first packet we see from this flow
+ good_packet = true;
+ curr_rfc2544->set_exp_flow_seq(fsp_head->flow_seq);
+ } else {
+ // garbage packet
+ good_packet = false;
+ m_err_cntrs->m_bad_header++;
+ }
+ }
+ }
+ }
+
+ if (good_packet) {
+ uint32_t pkt_seq = fsp_head->seq;
+ uint32_t exp_seq = curr_rfc2544->get_seq();
+ if (unlikely(pkt_seq != exp_seq)) {
+ if (pkt_seq < exp_seq) {
+ if (exp_seq - pkt_seq > 100000) {
+ // packet loss while we had wrap around
+ curr_rfc2544->inc_seq_err(pkt_seq - exp_seq);
+ curr_rfc2544->inc_seq_err_too_big();
+ curr_rfc2544->set_seq(pkt_seq + 1);
+ } else {
+ if (pkt_seq == (exp_seq - 1)) {
+ curr_rfc2544->inc_dup();
+ } else {
+ curr_rfc2544->inc_ooo();
+ // We thought it was lost, but it was just out of order
+ curr_rfc2544->dec_seq_err();
+ }
+ curr_rfc2544->inc_seq_err_too_low();
+ }
+ } else {
+ if (unlikely (pkt_seq - exp_seq > 100000)) {
+ // packet reorder while we had wrap around
+ if (pkt_seq == (exp_seq - 1)) {
+ curr_rfc2544->inc_dup();
+ } else {
+ curr_rfc2544->inc_ooo();
+ // We thought it was lost, but it was just out of order
+ curr_rfc2544->dec_seq_err();
+ }
+ curr_rfc2544->inc_seq_err_too_low();
+ } else {
+ // seq > curr_rfc2544->seq. Assuming lost packets
+ curr_rfc2544->inc_seq_err(pkt_seq - exp_seq);
+ curr_rfc2544->inc_seq_err_too_big();
+ curr_rfc2544->set_seq(pkt_seq + 1);
+ }
+ }
+ } else {
+ curr_rfc2544->set_seq(pkt_seq + 1);
+ }
+ m_rx_pg_stat_payload[hw_id].add_pkts(1);
+ m_rx_pg_stat_payload[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
+ uint64_t d = (os_get_hr_tick_64() - fsp_head->time_stamp );
+ dsec_t ctime = ptime_convert_hr_dsec(d);
+ curr_rfc2544->add_sample(ctime);
+ }
+ } else {
+ hw_id = get_hw_id(ip_id);
+ if (hw_id < MAX_FLOW_STATS) {
+ m_rx_pg_stat[hw_id].add_pkts(1);
+ m_rx_pg_stat[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+RXLatency::reset_stats() {
+ for (int hw_id = 0; hw_id < MAX_FLOW_STATS; hw_id++) {
+ m_rx_pg_stat[hw_id].clear();
+ }
+}
+
+
+void
+RXLatency::get_stats(rx_per_flow_t *rx_stats,
+ int min,
+ int max,
+ bool reset,
+ TrexPlatformApi::driver_stat_cap_e type) {
+
+ for (int hw_id = min; hw_id <= max; hw_id++) {
+ if (type == TrexPlatformApi::IF_STAT_PAYLOAD) {
+ rx_stats[hw_id - min] = m_rx_pg_stat_payload[hw_id];
+ } else {
+ rx_stats[hw_id - min] = m_rx_pg_stat[hw_id];
+ }
+ if (reset) {
+ if (type == TrexPlatformApi::IF_STAT_PAYLOAD) {
+ m_rx_pg_stat_payload[hw_id].clear();
+ } else {
+ m_rx_pg_stat[hw_id].clear();
+ }
+ }
+ }
+}
+
+
+Json::Value
+RXLatency::to_json() const {
+ return Json::objectValue;
+}
+
+/**************************************
+ * RX feature queue
+ *
+ *************************************/
+
+RXPacketBuffer::RXPacketBuffer(uint64_t size) {
+ m_buffer = nullptr;
+ m_head = 0;
+ m_tail = 0;
+ m_size = (size + 1); // for the empty/full difference 1 slot reserved
+
+ /* generate queue */
+ m_buffer = new RXPacket*[m_size](); // zeroed
+}
+
+RXPacketBuffer::~RXPacketBuffer() {
+ assert(m_buffer);
+
+ while (!is_empty()) {
+ RXPacket *pkt = pop();
+ delete pkt;
+ }
+ delete [] m_buffer;
+}
+
+void
+RXPacketBuffer::push(const rte_mbuf_t *m) {
+ /* if full - pop the oldest */
+ if (is_full()) {
+ delete pop();
+ }
+
+ /* push packet */
+ m_buffer[m_head] = new RXPacket(m);
+ m_head = next(m_head);
+}
+
+RXPacket *
+RXPacketBuffer::pop() {
+ assert(!is_empty());
+
+ RXPacket *pkt = m_buffer[m_tail];
+ m_tail = next(m_tail);
+
+ return pkt;
+}
+
+uint64_t
+RXPacketBuffer::get_element_count() const {
+ if (m_head >= m_tail) {
+ return (m_head - m_tail);
+ } else {
+ return ( get_capacity() - (m_tail - m_head - 1) );
+ }
+}
+
+Json::Value
+RXPacketBuffer::to_json() const {
+
+ Json::Value output = Json::arrayValue;
+
+ int tmp = m_tail;
+ while (tmp != m_head) {
+ RXPacket *pkt = m_buffer[tmp];
+ output.append(pkt->to_json());
+ tmp = next(tmp);
+ }
+
+ return output;
+}
+
+
+void
+RXQueue::start(uint64_t size) {
+ if (m_pkt_buffer) {
+ delete m_pkt_buffer;
+ }
+ m_pkt_buffer = new RXPacketBuffer(size);
+}
+
+void
+RXQueue::stop() {
+ if (m_pkt_buffer) {
+ delete m_pkt_buffer;
+ m_pkt_buffer = NULL;
+ }
+}
+
+const RXPacketBuffer *
+RXQueue::fetch() {
+
+ /* if no buffer or the buffer is empty - give a NULL one */
+ if ( (!m_pkt_buffer) || (m_pkt_buffer->get_element_count() == 0) ) {
+ return nullptr;
+ }
+
+ /* hold a pointer to the old one */
+ RXPacketBuffer *old_buffer = m_pkt_buffer;
+
+ /* replace the old one with a new one and freeze the old */
+ m_pkt_buffer = new RXPacketBuffer(old_buffer->get_capacity());
+
+ return old_buffer;
+}
+
+void
+RXQueue::handle_pkt(const rte_mbuf_t *m) {
+ m_pkt_buffer->push(m);
+}
+
+Json::Value
+RXQueue::to_json() const {
+ assert(m_pkt_buffer != NULL);
+
+ Json::Value output = Json::objectValue;
+
+ output["size"] = Json::UInt64(m_pkt_buffer->get_capacity());
+ output["count"] = Json::UInt64(m_pkt_buffer->get_element_count());
+
+ return output;
+}
+
+/**************************************
+ * RX feature recorder
+ *
+ *************************************/
+
+RXPacketRecorder::RXPacketRecorder() {
+ m_writer = NULL;
+ m_count = 0;
+ m_limit = 0;
+ m_epoch = -1;
+
+ m_pending_flush = false;
+}
+
+void
+RXPacketRecorder::start(const std::string &pcap, uint64_t limit) {
+ m_writer = CCapWriterFactory::CreateWriter(LIBPCAP, (char *)pcap.c_str());
+ if (m_writer == NULL) {
+ std::stringstream ss;
+ ss << "unable to create PCAP file: " << pcap;
+ throw TrexException(ss.str());
+ }
+
+ assert(limit > 0);
+
+ m_limit = limit;
+ m_count = 0;
+ m_pending_flush = false;
+ m_pcap_filename = pcap;
+}
+
+void
+RXPacketRecorder::stop() {
+ if (!m_writer) {
+ return;
+ }
+
+ delete m_writer;
+ m_writer = NULL;
+}
+
+void
+RXPacketRecorder::flush_to_disk() {
+
+ if (m_writer && m_pending_flush) {
+ m_writer->flush_to_disk();
+ m_pending_flush = false;
+ }
+}
+
+void
+RXPacketRecorder::handle_pkt(const rte_mbuf_t *m) {
+ if (!m_writer) {
+ return;
+ }
+
+ dsec_t now = now_sec();
+ if (m_epoch < 0) {
+ m_epoch = now;
+ }
+
+ dsec_t dt = now - m_epoch;
+
+ CPktNsecTimeStamp t_c(dt);
+ m_pkt.time_nsec = t_c.m_time_nsec;
+ m_pkt.time_sec = t_c.m_time_sec;
+
+ const uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *);
+ m_pkt.pkt_len = m->pkt_len;
+ memcpy(m_pkt.raw, p, m->pkt_len);
+
+ m_writer->write_packet(&m_pkt);
+ m_count++;
+ m_pending_flush = true;
+
+ if (m_count == m_limit) {
+ stop();
+ }
+
+}
+
+Json::Value
+RXPacketRecorder::to_json() const {
+ Json::Value output = Json::objectValue;
+
+ output["pcap_filename"] = m_pcap_filename;
+ output["limit"] = Json::UInt64(m_limit);
+ output["count"] = Json::UInt64(m_count);
+
+ return output;
+}
+
+
+/**************************************
+ * RX feature server (ARP, ICMP) and etc.
+ *
+ *************************************/
+
+class RXPktParser {
+public:
+ RXPktParser(const rte_mbuf_t *m) {
+
+ m_mbuf = m;
+
+ /* start point */
+ m_current = rte_pktmbuf_mtod(m, uint8_t *);;
+ m_size_left = rte_pktmbuf_pkt_len(m);
+
+ m_ether = NULL;
+ m_arp = NULL;
+ m_ipv4 = NULL;
+ m_icmp = NULL;
+ m_vlan_tag = 0;
+
+ /* ethernet */
+ m_ether = (EthernetHeader *)parse_bytes(14);
+
+ uint16_t next_proto;
+ if (m_ether->getNextProtocol() == EthernetHeader::Protocol::VLAN) {
+ parse_bytes(4);
+ m_vlan_tag = m_ether->getVlanTag();
+ next_proto = m_ether->getVlanProtocol();
+ } else {
+ next_proto = m_ether->getNextProtocol();
+ }
+
+ /**
+ * support only for ARP or IPv4 based protocols
+ */
+ switch (next_proto) {
+ case EthernetHeader::Protocol::ARP:
+ parse_arp();
+ return;
+
+ case EthernetHeader::Protocol::IP:
+ parse_ipv4();
+ return;
+
+ default:
+ return;
+ }
+
+ }
+
+ const rte_mbuf_t *m_mbuf;
+ EthernetHeader *m_ether;
+ ArpHdr *m_arp;
+ IPHeader *m_ipv4;
+ ICMPHeader *m_icmp;
+ uint16_t m_vlan_tag;
+
+protected:
+
+ const uint8_t *parse_bytes(uint32_t size) {
+ if (m_size_left < size) {
+ parse_err();
+ }
+
+ const uint8_t *p = m_current;
+ m_current += size;
+ m_size_left -= size;
+
+ return p;
+ }
+
+ void parse_arp() {
+ m_arp = (ArpHdr *)parse_bytes(sizeof(ArpHdr));
+ }
+
+ void parse_ipv4() {
+ m_ipv4 = (IPHeader *)parse_bytes(IPHeader::DefaultSize);
+
+ /* advance over IP options if exists */
+ parse_bytes(m_ipv4->getOptionLen());
+
+ switch (m_ipv4->getNextProtocol()) {
+ case IPHeader::Protocol::ICMP:
+ parse_icmp();
+ return;
+
+ default:
+ return;
+ }
+ }
+
+ void parse_icmp() {
+ m_icmp = (ICMPHeader *)parse_bytes(sizeof(ICMPHeader));
+ }
+
+ void parse_err() {
+ throw TrexException(TrexException::T_RX_PKT_PARSE_ERR);
+ }
+
+ const uint8_t *m_current;
+ uint16_t m_size_left;
+};
+
+RXServer::RXServer() {
+ m_io = NULL;
+ m_src_addr = NULL;
+ m_port_id = 255;
+}
+
+void
+RXServer::create(uint8_t port_id, CPortLatencyHWBase *io, const CManyIPInfo *src_addr) {
+ m_port_id = port_id;
+ m_io = io;
+ m_src_addr = src_addr;
+}
+
+
+void
+RXServer::handle_pkt(const rte_mbuf_t *m) {
+
+ RXPktParser parser(m);
+
+ if (parser.m_icmp) {
+ handle_icmp(parser);
+ } else if (parser.m_arp) {
+ handle_arp(parser);
+ } else {
+ return;
+ }
+
+}
+void
+RXServer::handle_icmp(RXPktParser &parser) {
+
+ /* maybe not for us... */
+ if (!m_src_addr->exists(parser.m_ipv4->getDestIp())) {
+ return;
+ }
+
+ /* we handle only echo request */
+ if (parser.m_icmp->getType() != ICMPHeader::TYPE_ECHO_REQUEST) {
+ return;
+ }
+
+ /* duplicate the MBUF */
+ rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf);
+ if (!response) {
+ return;
+ }
+
+ /* reparse the cloned packet */
+ RXPktParser response_parser(response);
+
+ /* swap MAC */
+ MacAddress tmp = response_parser.m_ether->mySource;
+ response_parser.m_ether->mySource = response_parser.m_ether->myDestination;
+ response_parser.m_ether->myDestination = tmp;
+
+ /* swap IP */
+ std::swap(response_parser.m_ipv4->mySource, response_parser.m_ipv4->myDestination);
+
+ /* new packet - new TTL */
+ response_parser.m_ipv4->setTimeToLive(128);
+ response_parser.m_ipv4->updateCheckSum();
+
+ /* update type and fix checksum */
+ response_parser.m_icmp->setType(ICMPHeader::TYPE_ECHO_REPLY);
+ response_parser.m_icmp->updateCheckSum(response_parser.m_ipv4->getTotalLength() - response_parser.m_ipv4->getHeaderLength());
+
+ /* send */
+ m_io->tx(response);
+}
+
+void
+RXServer::handle_arp(RXPktParser &parser) {
+ MacAddress src_mac;
+
+ /* only ethernet format supported */
+ if (parser.m_arp->getHrdType() != ArpHdr::ARP_HDR_HRD_ETHER) {
+ return;
+ }
+
+ /* IPV4 only */
+ if (parser.m_arp->getProtocolType() != ArpHdr::ARP_HDR_PROTO_IPV4) {
+ return;
+ }
+
+ /* support only for ARP request */
+ if (parser.m_arp->getOp() != ArpHdr::ARP_HDR_OP_REQUEST) {
+ return;
+ }
+
+ /* are we the target ? if not - go home */
+ if (!m_src_addr->lookup(parser.m_arp->getTip(), 0, src_mac)) {
+ return;
+ }
+
+ /* duplicate the MBUF */
+ rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf);
+ if (!response) {
+ return;
+ }
+
+ /* reparse the cloned packet */
+ RXPktParser response_parser(response);
+
+ /* reply */
+ response_parser.m_arp->setOp(ArpHdr::ARP_HDR_OP_REPLY);
+
+ /* fix the MAC addresses */
+ response_parser.m_ether->mySource = src_mac;
+ response_parser.m_ether->myDestination = parser.m_ether->mySource;
+
+ /* fill up the fields */
+
+ /* src */
+ response_parser.m_arp->m_arp_sha = src_mac;
+ response_parser.m_arp->setSip(parser.m_arp->getTip());
+
+ /* dst */
+ response_parser.m_arp->m_arp_tha = parser.m_arp->m_arp_sha;
+ response_parser.m_arp->m_arp_tip = parser.m_arp->m_arp_sip;
+
+ /* send */
+ m_io->tx(response);
+
+}
+
+rte_mbuf_t *
+RXServer::duplicate_mbuf(const rte_mbuf_t *m) {
+ /* RX packets should always be one segment */
+ assert(m->nb_segs == 1);
+
+ /* allocate */
+ rte_mbuf_t *clone_mbuf = CGlobalInfo::pktmbuf_alloc_by_port(m_port_id, rte_pktmbuf_pkt_len(m));
+ if (!clone_mbuf) {
+ return NULL;
+ }
+
+ /* append data */
+ uint8_t *dest = (uint8_t *)rte_pktmbuf_append(clone_mbuf, rte_pktmbuf_pkt_len(m));
+ if (!dest) {
+ return NULL;
+ }
+
+ /* copy data */
+ const uint8_t *src = rte_pktmbuf_mtod(m, const uint8_t *);
+ memcpy(dest, src, rte_pktmbuf_pkt_len(m));
+
+ return clone_mbuf;
+}
+
+/**************************************
+ * Gratidious ARP
+ *
+ *************************************/
+void
+RXGratARP::create(uint8_t port_id,
+ CPortLatencyHWBase *io,
+ CManyIPInfo *src_addr,
+ CRXCoreIgnoreStat *ign_stats) {
+
+ m_port_id = port_id;
+ m_io = io;
+ m_src_addr = src_addr;
+ m_ign_stats = ign_stats;
+}
+
+void
+RXGratARP::send_next_grat_arp() {
+ uint8_t src_mac[ETHER_ADDR_LEN];
+
+ const COneIPInfo *ip_info = m_src_addr->get_next_loop();
+ if (!ip_info) {
+ return;
+ }
+
+ rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(m_port_id));
+ assert(m);
+
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, ip_info->get_grat_arp_len());
+ ip_info->get_mac(src_mac);
+ uint16_t vlan = ip_info->get_vlan();
+
+ /* for now only IPv4 */
+ assert(ip_info->ip_ver() == COneIPInfo::IP4_VER);
+ uint32_t sip = ((COneIPv4Info *)ip_info)->get_ip();
+
+ CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, m_port_id);
+
+ if (m_io->tx(m) == 0) {
+ m_ign_stats->m_tx_arp += 1;
+ m_ign_stats->m_tot_bytes += 64;
+ }
+
+}
+
+Json::Value
+RXGratARP::to_json() const {
+ Json::Value output = Json::objectValue;
+ output["interval_sec"] = (double)CGlobalInfo::m_options.m_arp_ref_per;
+
+ return output;
+}
+
+/**************************************
+ * Port manager
+ *
+ *************************************/
+
+RXPortManager::RXPortManager() {
+ clear_all_features();
+ m_io = NULL;
+ m_cpu_dp_u = NULL;
+ m_port_id = UINT8_MAX;
+}
+
+
+void
+RXPortManager::create(const TRexPortAttr *port_attr,
+ CPortLatencyHWBase *io,
+ CRFC2544Info *rfc2544,
+ CRxCoreErrCntrs *err_cntrs,
+ CCpuUtlDp *cpu_util,
+ uint8_t crc_bytes_num) {
+
+ m_port_id = port_attr->get_port_id();
+ m_io = io;
+ m_cpu_dp_u = cpu_util;
+ m_num_crc_fix_bytes = crc_bytes_num;
+
+ /* init features */
+ m_latency.create(rfc2544, err_cntrs);
+ m_server.create(m_port_id, io, &m_src_addr);
+ m_grat_arp.create(m_port_id, io, &m_src_addr, &m_ign_stats);
+
+ /* by default, server is always on */
+ set_feature(SERVER);
+}
+
+void RXPortManager::handle_pkt(const rte_mbuf_t *m) {
+
+ /* handle features */
+
+ if (is_feature_set(LATENCY)) {
+ m_latency.handle_pkt(m);
+ }
+
+ if (is_feature_set(RECORDER)) {
+ m_recorder.handle_pkt(m);
+ }
+
+ if (is_feature_set(QUEUE)) {
+ m_queue.handle_pkt(m);
+ }
+
+ if (is_feature_set(SERVER)) {
+ m_server.handle_pkt(m);
+ }
+}
+
+int RXPortManager::process_all_pending_pkts(bool flush_rx) {
+
+ rte_mbuf_t *rx_pkts[64];
+
+ /* try to read 64 packets clean up the queue */
+ uint16_t cnt_p = m_io->rx_burst(rx_pkts, 64);
+ if (cnt_p == 0) {
+ return cnt_p;
+ }
+
+
+ m_cpu_dp_u->start_work1();
+
+ for (int j = 0; j < cnt_p; j++) {
+ rte_mbuf_t *m = rx_pkts[j];
+
+ if (!flush_rx) {
+ // patch relevant only for e1000 driver
+ if (m_num_crc_fix_bytes) {
+ rte_pktmbuf_trim(m, m_num_crc_fix_bytes);
+ }
+
+ handle_pkt(m);
+ }
+
+ rte_pktmbuf_free(m);
+ }
+
+ /* commit only if there was work to do ! */
+ m_cpu_dp_u->commit1();
+
+
+ return cnt_p;
+}
+
+void
+RXPortManager::tick() {
+ if (is_feature_set(RECORDER)) {
+ m_recorder.flush_to_disk();
+ }
+}
+
+void
+RXPortManager::send_next_grat_arp() {
+ if (is_feature_set(GRAT_ARP)) {
+ m_grat_arp.send_next_grat_arp();
+ }
+}
+
+
+void
+RXPortManager::set_l2_mode() {
+
+ /* no IPv4 addresses */
+ m_src_addr.clear();
+
+ /* stop grat arp */
+ stop_grat_arp();
+}
+
+void
+RXPortManager::set_l3_mode(const CManyIPInfo &ip_info, bool is_grat_arp_needed) {
+
+ /* copy L3 address */
+ m_src_addr = ip_info;
+
+ if (is_grat_arp_needed) {
+ start_grat_arp();
+ }
+ else {
+ stop_grat_arp();
+ }
+
+}
+
+
+
+Json::Value
+RXPortManager::to_json() const {
+ Json::Value output = Json::objectValue;
+
+ if (is_feature_set(LATENCY)) {
+ output["latency"] = m_latency.to_json();
+ output["latency"]["is_active"] = true;
+ } else {
+ output["latency"]["is_active"] = false;
+ }
+
+ if (is_feature_set(RECORDER)) {
+ output["sniffer"] = m_recorder.to_json();
+ output["sniffer"]["is_active"] = true;
+ } else {
+ output["sniffer"]["is_active"] = false;
+ }
+
+ if (is_feature_set(QUEUE)) {
+ output["queue"] = m_queue.to_json();
+ output["queue"]["is_active"] = true;
+ } else {
+ output["queue"]["is_active"] = false;
+ }
+
+ if (is_feature_set(GRAT_ARP)) {
+ output["grat_arp"] = m_grat_arp.to_json();
+ output["grat_arp"]["is_active"] = true;
+ } else {
+ output["grat_arp"]["is_active"] = false;
+ }
+
+ return output;
+}
+
+
+void RXPortManager::get_ignore_stats(CRXCoreIgnoreStat &stat, bool get_diff) {
+ if (get_diff) {
+ stat = m_ign_stats - m_ign_stats_prev;
+ m_ign_stats_prev = m_ign_stats;
+ } else {
+ stat = m_ign_stats;
+ }
+}
+
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.h b/src/stateless/rx/trex_stateless_rx_port_mngr.h
new file mode 100644
index 00000000..8947def7
--- /dev/null
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h
@@ -0,0 +1,517 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2016-2016 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.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef __TREX_STATELESS_RX_PORT_MNGR_H__
+#define __TREX_STATELESS_RX_PORT_MNGR_H__
+
+#include <stdint.h>
+#include "common/base64.h"
+
+#include "common/captureFile.h"
+
+
+class CPortLatencyHWBase;
+class CRFC2544Info;
+class CRxCoreErrCntrs;
+
+/**************************************
+ * RX feature latency
+ *
+ *************************************/
+class RXLatency {
+public:
+
+ RXLatency();
+
+ void create(CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs);
+
+ void handle_pkt(const rte_mbuf_t *m);
+
+ Json::Value to_json() const;
+
+ void get_stats(rx_per_flow_t *rx_stats,
+ int min,
+ int max,
+ bool reset,
+ TrexPlatformApi::driver_stat_cap_e type);
+
+ void reset_stats();
+
+private:
+ bool is_flow_stat_id(uint32_t id) {
+ if ((id & 0x000fff00) == IP_ID_RESERVE_BASE) return true;
+ return false;
+ }
+
+ bool is_flow_stat_payload_id(uint32_t id) {
+ if (id == FLOW_STAT_PAYLOAD_IP_ID) return true;
+ return false;
+ }
+
+ uint16_t get_hw_id(uint16_t id) {
+ return (0x00ff & id);
+}
+
+public:
+
+ rx_per_flow_t m_rx_pg_stat[MAX_FLOW_STATS];
+ rx_per_flow_t m_rx_pg_stat_payload[MAX_FLOW_STATS_PAYLOAD];
+
+ bool m_rcv_all;
+ CRFC2544Info *m_rfc2544;
+ CRxCoreErrCntrs *m_err_cntrs;
+};
+
+/**
+ * describes a single saved RX packet
+ *
+ */
+class RXPacket {
+public:
+
+ RXPacket(const rte_mbuf_t *m) {
+ /* assume single part packet */
+ assert(m->nb_segs == 1);
+
+ m_size = m->pkt_len;
+ const uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *);
+
+ m_raw = new uint8_t[m_size];
+ memcpy(m_raw, p, m_size);
+
+ /* generate a packet timestamp */
+ m_timestamp = now_sec();
+ }
+
+ /* slow path and also RVO - pass by value is ok */
+ Json::Value to_json() {
+ Json::Value output;
+ output["ts"] = m_timestamp;
+ output["binary"] = base64_encode(m_raw, m_size);
+ return output;
+ }
+
+ ~RXPacket() {
+ if (m_raw) {
+ delete [] m_raw;
+ }
+ }
+
+private:
+
+ uint8_t *m_raw;
+ uint16_t m_size;
+ dsec_t m_timestamp;
+};
+
+
+/**************************************
+ * RX feature queue
+ *
+ *************************************/
+
+class RXPacketBuffer {
+public:
+
+ RXPacketBuffer(uint64_t size);
+ ~RXPacketBuffer();
+
+ /**
+ * push a packet to the buffer
+ *
+ */
+ void push(const rte_mbuf_t *m);
+
+ /**
+ * generate a JSON output of the queue
+ *
+ */
+ Json::Value to_json() const;
+
+
+ bool is_empty() const {
+ return (m_head == m_tail);
+ }
+
+ bool is_full() const {
+ return ( next(m_head) == m_tail);
+ }
+
+ /**
+ * return the total amount of space possible
+ */
+ uint64_t get_capacity() const {
+ /* one slot is used for diff between full/empty */
+ return (m_size - 1);
+ }
+
+ /**
+ * returns how many elements are in the queue
+ */
+ uint64_t get_element_count() const;
+
+private:
+ int next(int v) const {
+ return ( (v + 1) % m_size );
+ }
+
+ /* pop in case of full queue - internal usage */
+ RXPacket * pop();
+
+ int m_head;
+ int m_tail;
+ int m_size;
+ RXPacket **m_buffer;
+};
+
+
+class RXQueue {
+public:
+ RXQueue() {
+ m_pkt_buffer = nullptr;
+ }
+
+ ~RXQueue() {
+ stop();
+ }
+
+ /**
+ * start RX queue
+ *
+ */
+ void start(uint64_t size);
+
+ /**
+ * fetch the current buffer
+ * return NULL if no packets
+ */
+ const RXPacketBuffer * fetch();
+
+ /**
+ * stop RX queue
+ *
+ */
+ void stop();
+
+ void handle_pkt(const rte_mbuf_t *m);
+
+ Json::Value to_json() const;
+
+private:
+ RXPacketBuffer *m_pkt_buffer;
+};
+
+/**************************************
+ * RX feature PCAP recorder
+ *
+ *************************************/
+
+class RXPacketRecorder {
+public:
+ RXPacketRecorder();
+
+ ~RXPacketRecorder() {
+ stop();
+ }
+
+ void start(const std::string &pcap, uint64_t limit);
+ void stop();
+ void handle_pkt(const rte_mbuf_t *m);
+
+ /**
+ * flush any cached packets to disk
+ *
+ */
+ void flush_to_disk();
+
+ Json::Value to_json() const;
+
+private:
+ CFileWriterBase *m_writer;
+ std::string m_pcap_filename;
+ CCapPktRaw m_pkt;
+ dsec_t m_epoch;
+ uint64_t m_limit;
+ uint64_t m_count;
+ bool m_pending_flush;
+};
+
+
+/**************************************
+ * RX server (ping, ARP and etc.)
+ *
+ *************************************/
+class RXPktParser;
+class RXServer {
+public:
+
+ RXServer();
+ void create(uint8_t port_id, CPortLatencyHWBase *io, const CManyIPInfo *src_addr);
+ void handle_pkt(const rte_mbuf_t *m);
+
+private:
+ void handle_icmp(RXPktParser &parser);
+ void handle_arp(RXPktParser &parser);
+ rte_mbuf_t *duplicate_mbuf(const rte_mbuf_t *m);
+
+ CPortLatencyHWBase *m_io;
+ uint8_t m_port_id;
+ const CManyIPInfo *m_src_addr;
+};
+
+/**************************************
+ * Gratidious ARP
+ *
+ *************************************/
+class RXGratARP {
+public:
+ RXGratARP() {
+ m_io = NULL;
+ m_port_id = UINT8_MAX;
+ m_src_addr = NULL;
+ m_ign_stats = NULL;
+ }
+
+ void create(uint8_t port_id,
+ CPortLatencyHWBase *io,
+ CManyIPInfo *src_addr,
+ CRXCoreIgnoreStat *ignore_stats);
+
+
+ /**
+ * the main 'tick' of the service
+ *
+ */
+ void send_next_grat_arp();
+
+ Json::Value to_json() const;
+
+private:
+ uint8_t m_port_id;
+ CPortLatencyHWBase *m_io;
+ CManyIPInfo *m_src_addr;
+ CRXCoreIgnoreStat *m_ign_stats;
+};
+
+/************************ manager ***************************/
+
+/**
+ * per port RX features manager
+ *
+ * @author imarom (10/30/2016)
+ */
+class RXPortManager {
+public:
+ enum feature_t {
+ NO_FEATURES = 0x0,
+ LATENCY = 0x1,
+ RECORDER = 0x2,
+ QUEUE = 0x4,
+ SERVER = 0x8,
+ GRAT_ARP = 0x10,
+ };
+
+ RXPortManager();
+
+ void create(const TRexPortAttr *port_attr,
+ CPortLatencyHWBase *io,
+ CRFC2544Info *rfc2544,
+ CRxCoreErrCntrs *err_cntrs,
+ CCpuUtlDp *cpu_util,
+ uint8_t crc_bytes_num);
+
+
+ void clear_stats() {
+ m_latency.reset_stats();
+ }
+
+
+ void get_latency_stats(rx_per_flow_t *rx_stats,
+ int min,
+ int max,
+ bool reset,
+ TrexPlatformApi::driver_stat_cap_e type) {
+
+ return m_latency.get_stats(rx_stats, min, max, reset, type);
+ }
+
+ RXLatency & get_latency() {
+ return m_latency;
+ }
+
+ /* latency */
+ void enable_latency() {
+ set_feature(LATENCY);
+ }
+
+ void disable_latency() {
+ unset_feature(LATENCY);
+ }
+
+ /* recorder */
+ void start_recorder(const std::string &pcap, uint64_t limit_pkts) {
+ m_recorder.start(pcap, limit_pkts);
+ set_feature(RECORDER);
+ }
+
+ void stop_recorder() {
+ m_recorder.stop();
+ unset_feature(RECORDER);
+ }
+
+ /* queue */
+ void start_queue(uint32_t size) {
+ m_queue.start(size);
+ set_feature(QUEUE);
+ }
+
+ void stop_queue() {
+ m_queue.stop();
+ unset_feature(QUEUE);
+ }
+
+ const RXPacketBuffer *get_pkt_buffer() {
+ if (!is_feature_set(QUEUE)) {
+ return nullptr;
+ }
+
+ return m_queue.fetch();
+ }
+
+ void start_grat_arp() {
+ set_feature(GRAT_ARP);
+ }
+
+ void stop_grat_arp() {
+ unset_feature(GRAT_ARP);
+ }
+
+ /**
+ * fetch and process all packets
+ *
+ */
+ int process_all_pending_pkts(bool flush_rx = false);
+
+
+ /**
+ * flush all pending packets without processing them
+ *
+ */
+ void flush_all_pending_pkts() {
+ process_all_pending_pkts(true);
+ }
+
+
+ /**
+ * handle a single packet
+ *
+ */
+ void handle_pkt(const rte_mbuf_t *m);
+
+ /**
+ * maintenance
+ *
+ * @author imarom (11/24/2016)
+ */
+ void tick();
+
+ /**
+ * send next grat arp (if on)
+ *
+ * @author imarom (12/13/2016)
+ */
+ void send_next_grat_arp();
+
+ /**
+ * set port mode to L2
+ */
+ void set_l2_mode();
+
+ /**
+ * set port mode to L3
+ *
+ * @author imarom (12/13/2016)
+ */
+ void set_l3_mode(const CManyIPInfo &ip_info, bool is_grat_arp_needed);
+
+
+ bool has_features_set() {
+ return (m_features != NO_FEATURES);
+ }
+
+
+ bool no_features_set() {
+ return (!has_features_set());
+ }
+
+ /**
+ * returns ignored set of stats
+ * (grat ARP, PING response and etc.)
+ */
+ void get_ignore_stats(CRXCoreIgnoreStat &stat, bool get_diff);
+
+ /**
+ * write the status to a JSON format
+ */
+ Json::Value to_json() const;
+
+private:
+
+ void clear_all_features() {
+ m_features = NO_FEATURES;
+ }
+
+ void set_feature(feature_t feature) {
+ m_features |= feature;
+ }
+
+ void unset_feature(feature_t feature) {
+ m_features &= (~feature);
+ }
+
+ bool is_feature_set(feature_t feature) const {
+ return ( (m_features & feature) == feature );
+ }
+
+ uint32_t m_features;
+ uint8_t m_port_id;
+ RXLatency m_latency;
+ RXPacketRecorder m_recorder;
+ RXQueue m_queue;
+ RXServer m_server;
+ RXGratARP m_grat_arp;
+
+ // compensate for the fact that hardware send us packets without Ethernet CRC, and we report with it
+ uint8_t m_num_crc_fix_bytes;
+
+ CCpuUtlDp *m_cpu_dp_u;
+ CPortLatencyHWBase *m_io;
+ CManyIPInfo m_src_addr;
+
+ /* stats to ignore (ARP and etc.) */
+ CRXCoreIgnoreStat m_ign_stats;
+ CRXCoreIgnoreStat m_ign_stats_prev;
+};
+
+
+
+#endif /* __TREX_STATELESS_RX_PORT_MNGR_H__ */
+
diff --git a/src/trex_client_config.cpp b/src/trex_client_config.cpp
index ad71d38e..548d097b 100644
--- a/src/trex_client_config.cpp
+++ b/src/trex_client_config.cpp
@@ -30,38 +30,200 @@ limitations under the License.
#include "common/basic_utils.h"
#include "bp_sim.h"
+void ClientCfgDirBase::dump(FILE *fd) const {
+ if (has_src_mac_addr()) {
+ fprintf(fd, " src_mac: %s\n", utl_macaddr_to_str(m_src_mac.GetConstBuffer()).c_str());
+ } else {
+ fprintf(fd, "# No src MAC\n");
+ }
+ if (has_dst_mac_addr()) {
+ fprintf(fd, " dst_mac: %s\n", utl_macaddr_to_str(m_dst_mac.GetConstBuffer()).c_str());
+ } else {
+ fprintf(fd, "# No dst MAC\n");
+ }
+ if (has_vlan()) {
+ fprintf(fd, " vlan: %d\n", m_vlan);
+ } else {
+ fprintf(fd, "# No vlan\n");
+ }
+}
+
+void ClientCfgDirBase::update(uint32_t index, const ClientCfgDirExt &cfg) {
+ if (has_src_mac_addr()) {
+ m_src_mac += index;
+ }
+
+ if (has_dst_mac_addr() || cfg.has_next_hop() || cfg.has_ipv6_next_hop()) {
+ m_dst_mac = cfg.get_resolved_mac(index);
+ m_bitfield |= HAS_DST_MAC;
+ }
+}
+
+bool ClientCfgDirExt::need_resolve() const {
+ if (has_next_hop() || has_ipv6_next_hop())
+ return true;
+ else
+ return false;
+}
+
+void ClientCfgDirExt::set_no_resolve_needed() {
+ m_bitfield &= ~(HAS_DST_MAC | HAS_IPV6_NEXT_HOP | HAS_NEXT_HOP);
+}
+
+void ClientCfgDirExt::dump(FILE *fd) const {
+ ClientCfgDirBase::dump(fd);
+
+ if (has_next_hop()) {
+ fprintf(fd, " next_hop: %s\n", ip_to_str(m_next_hop).c_str());
+ } else {
+ fprintf(fd, "# No next hop\n");
+ }
+ if (has_ipv6_next_hop()) {
+ fprintf(fd, " ipv6_next_hop: %s\n", ip_to_str((unsigned char *)m_ipv6_next_hop).c_str());
+ } else {
+ fprintf(fd, "# No IPv6 next hop\n");
+ }
+
+ if (m_resolved_macs.size() > 0) {
+ fprintf(fd, "# Resolved MAC list:\n");
+ for (int i = 0; i < m_resolved_macs.size(); i++) {
+ fprintf(fd, "# %s\n", utl_macaddr_to_str(m_resolved_macs[i].GetConstBuffer()).c_str());
+ }
+ }
+}
+
+void ClientCfgDirExt::set_resolved_macs(CManyIPInfo &pretest_result, uint16_t count) {
+ uint16_t vlan = has_vlan() ? m_vlan : 0;
+ MacAddress base_mac = m_dst_mac;
+ m_resolved_macs.resize(count);
+
+ for (int i = 0; i < count; i++) {
+ if (need_resolve()) {
+ if (has_next_hop()) {
+ if (!pretest_result.lookup(m_next_hop + i, vlan, m_resolved_macs[i])) {
+ fprintf(stderr, "Failed resolving ip:%x, vlan:%d - exiting\n", m_next_hop+i, vlan);
+ exit(1);
+ }
+ } else {
+ //??? handle ipv6
+ }
+ } else {
+ m_resolved_macs[i] = base_mac;
+ base_mac += 1;
+ }
+ }
+}
+
+void ClientCfgBase::update(uint32_t index, const ClientCfgExt *cfg) {
+ m_initiator.update(index, cfg->m_initiator);
+ m_responder.update(index, cfg->m_responder);
+}
+
void
-ClientCfgEntry::dump() const {
+ClientCfgEntry::dump(FILE *fd) const {
- std::cout << "IP start: " << ip_to_str(m_ip_start) << "\n";
- std::cout << "IP end: " << ip_to_str(m_ip_end) << "\n";
+ fprintf(fd, "- ip_start : %s\n", ip_to_str(m_ip_start).c_str());
+ fprintf(fd, " ip_end : %s\n", ip_to_str(m_ip_end).c_str());
+ m_cfg.dump(fd);
+ fprintf(fd, " count : %d\n", m_count);
+}
- //m_cfg.dump();
+void ClientCfgEntry::set_resolved_macs(CManyIPInfo &pretest_result) {
+ m_cfg.m_initiator.set_resolved_macs(pretest_result, m_count);
+ m_cfg.m_responder.set_resolved_macs(pretest_result, m_count);
+}
- #if 0
- std::cout << "Init. MAC addr: ";
- for (int i = 0; i < 6; i++) {
- printf("%lx:", ( (m_initiator.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
+void ClientCfgCompactEntry::fill_from_dir(ClientCfgDirExt cfg, uint8_t port_id) {
+ m_port = port_id;
+ if (cfg.has_next_hop()) {
+ m_next_hop_base.ip = cfg.m_next_hop;
+ if (cfg.has_src_ip()) {
+ m_src_ip.ip = cfg.m_src_ip;
+ } else {
+ m_src_ip.ip = 0;
+ }
+ m_is_ipv4 = true;
+ } else if (cfg.has_ipv6_next_hop()) {
+ memcpy(m_next_hop_base.ipv6, cfg.m_ipv6_next_hop, sizeof(m_next_hop_base.ipv6));
+ if (cfg.has_src_ipv6()) {
+ memcpy(m_src_ip.ipv6, cfg.m_src_ipv6, sizeof(m_src_ip.ipv6));
+ } else {
+ memset(m_src_ip.ipv6, 0, sizeof(m_src_ip.ipv6));
+ }
+ m_is_ipv4 = false;
}
- std::cout << "\n";
- std::cout << "Init. VLAN: " << m_initiator.m_vlan << "\n";
+ if (cfg.has_vlan()) {
+ m_vlan = cfg.m_vlan;
+ } else {
+ m_vlan = 0;
+ }
+}
- std::cout << "Res. MAC addr: ";
- for (int i = 0; i < 6; i++) {
- printf("%lx:", ( (m_responder.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
+void
+ClientCfgDB::dump(FILE *fd) {
+ //fprintf(fd, "#**********Client config file start*********\n");
+ fprintf(fd, "vlan: %s\n", m_under_vlan ? "true" : "false");
+ fprintf(fd, "groups:\n");
+
+ for (std::map<uint32_t, ClientCfgEntry>::iterator it = m_groups.begin(); it != m_groups.end(); ++it) {
+ fprintf(fd, "# ****%s:****\n", ip_to_str(it->first).c_str());
+ ((ClientCfgEntry)it->second).dump(fd);
}
- std::cout << "\n";
+ //fprintf(fd, "#**********Client config end*********\n");
+}
- std::cout << "Res. VLAN: " << m_responder.m_vlan << "\n";
- #endif
+void ClientCfgDB::set_resolved_macs(CManyIPInfo &pretest_result) {
+ std::map<uint32_t, ClientCfgEntry>::iterator it;
+ for (it = m_groups.begin(); it != m_groups.end(); it++) {
+ ClientCfgEntry &cfg = it->second;
+ cfg.set_resolved_macs(pretest_result);
+ }
}
+void ClientCfgDB::get_entry_list(std::vector<ClientCfgCompactEntry *> &ret) {
+ uint8_t port;
+ bool result;
+
+ assert(m_tg != NULL);
+ for (std::map<uint32_t, ClientCfgEntry>::iterator it = m_groups.begin(); it != m_groups.end(); ++it) {
+ ClientCfgEntry &cfg = it->second;
+ if (cfg.m_cfg.m_initiator.need_resolve() || cfg.m_cfg.m_initiator.need_resolve()) {
+ result = m_tg->find_port(cfg.m_ip_start, cfg.m_ip_end, port);
+ if (! result) {
+ fprintf(stderr, "Error in clinet config range %s - %s.\n"
+ , ip_to_str(cfg.m_ip_start).c_str(), ip_to_str(cfg.m_ip_end).c_str());
+ exit(-1);
+ }
+ if (port == UINT8_MAX) {
+ // if port not found, it means this adderss is not needed. Don't try to resolve.
+ cfg.m_cfg.m_initiator.set_no_resolve_needed();
+ cfg.m_cfg.m_responder.set_no_resolve_needed();
+ } else {
+ if (cfg.m_cfg.m_initiator.need_resolve()) {
+ ClientCfgCompactEntry *init_entry = new ClientCfgCompactEntry();
+ assert(init_entry);
+ init_entry->m_count = cfg.m_count;
+ init_entry->fill_from_dir(cfg.m_cfg.m_initiator, port);
+ ret.push_back(init_entry);
+ }
+
+ if (cfg.m_cfg.m_responder.need_resolve()) {
+ ClientCfgCompactEntry *resp_entry = new ClientCfgCompactEntry();
+ assert(resp_entry);
+ resp_entry->m_count = cfg.m_count;
+ resp_entry->fill_from_dir(cfg.m_cfg.m_responder, port + 1);
+ ret.push_back(resp_entry);
+ }
+ }
+ }
+ }
+}
/**
- * loads a YAML file containing
- * the client groups configuration
- *
+ * loads a YAML file containing
+ * the client groups configuration
+ *
*/
void
ClientCfgDB::load_yaml_file(const std::string &filename) {
@@ -93,7 +255,7 @@ ClientCfgDB::load_yaml_file(const std::string &filename) {
/**
* reads a single group of clients from YAML
- *
+ *
*/
void
ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node) {
@@ -116,7 +278,7 @@ ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &nod
parse_dir(parser, init, group.m_cfg.m_initiator);
parse_dir(parser, resp, group.m_cfg.m_responder);
-
+
group.m_count = parser.parse_uint(node, "count", 0, UINT64_MAX, 1);
/* add to map with copying */
@@ -124,12 +286,32 @@ ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &nod
}
-void
-ClientCfgDB::parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDir &dir) {
+void
+ClientCfgDB::parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDirExt &dir) {
+ if (node.FindValue("src_ip")) {
+ dir.set_src_ip(parser.parse_ip(node, "src_ip"));
+ }
+
+ if (node.FindValue("src_ipv6")) {
+ uint16_t ip_num[8];
+ parser.parse_ipv6(node, "src_ipv6", (unsigned char *)&ip_num);
+ dir.set_src_ipv6(ip_num);
+ }
+
+ if (node.FindValue("next_hop")) {
+ dir.set_next_hop(parser.parse_ip(node, "next_hop"));
+ }
+
+ if (node.FindValue("ipv6_next_hop")) {
+ uint16_t ip_num[8];
+ parser.parse_ipv6(node, "ipv6_next_hop", (unsigned char *)&ip_num);
+ dir.set_ipv6_next_hop(ip_num);
+ }
+
if (node.FindValue("src_mac")) {
dir.set_src_mac_addr(parser.parse_mac_addr(node, "src_mac"));
}
-
+
if (node.FindValue("dst_mac")) {
dir.set_dst_mac_addr(parser.parse_mac_addr(node, "dst_mac"));
}
@@ -141,11 +323,20 @@ ClientCfgDB::parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, Client
parser.parse_err("VLAN config was disabled", node["vlan"]);
}
}
+
+ if ((dir.has_next_hop() || dir.has_ipv6_next_hop()) && (dir.has_dst_mac_addr() || dir.has_src_mac_addr())) {
+ parser.parse_err("Should not configure both next_hop/ipv6_next_hop and dst_mac or src_mac", node);
+ }
+
+ if (dir.has_next_hop() && dir.has_ipv6_next_hop()) {
+ parser.parse_err("Should not configure both next_hop and ipv6_next_hop", node);
+ }
+
}
/**
* sanity checks
- *
+ *
* @author imarom (28-Jun-16)
*/
void
@@ -154,7 +345,7 @@ ClientCfgDB::verify(const YAMLParserWrapper &parser) const {
uint32_t monotonic = 0;
/* check that no interval overlaps */
-
+
/* all intervals do not overloap iff when sorted each start/end dots are strong monotonic */
for (const auto &p : m_groups) {
const ClientCfgEntry &group = p.second;
@@ -169,13 +360,13 @@ ClientCfgDB::verify(const YAMLParserWrapper &parser) const {
}
/**
- * lookup function
- * should be fast
- *
+ * lookup function
+ * should be fast
+ *
*/
ClientCfgEntry *
ClientCfgDB::lookup(uint32_t ip) {
-
+
/* a cache to avoid constant search (usually its a range of IPs) */
if ( (m_cache_group) && (m_cache_group->contains(ip)) ) {
return m_cache_group;
@@ -185,7 +376,7 @@ ClientCfgDB::lookup(uint32_t ip) {
m_cache_group = NULL;
std::map<uint32_t ,ClientCfgEntry>::iterator it;
-
+
/* upper bound fetchs the first greater element */
it = m_groups.upper_bound(ip);
@@ -217,12 +408,12 @@ ClientCfgDB::lookup(uint32_t ip) {
/**
* for convenience - search by IP as string
- *
+ *
* @author imarom (28-Jun-16)
- *
- * @param ip
- *
- * @return ClientCfgEntry*
+ *
+ * @param ip
+ *
+ * @return ClientCfgEntry*
*/
ClientCfgEntry *
ClientCfgDB::lookup(const std::string &ip) {
@@ -231,5 +422,3 @@ ClientCfgDB::lookup(const std::string &ip) {
return lookup(addr);
}
-
-
diff --git a/src/trex_client_config.h b/src/trex_client_config.h
index a5bb83b3..257d354f 100644
--- a/src/trex_client_config.h
+++ b/src/trex_client_config.h
@@ -24,57 +24,56 @@ limitations under the License.
#include <stdint.h>
#include <string>
#include <map>
+#include "utl_ip.h"
+#include "common/Network/Packet/MacAddress.h"
class YAMLParserWrapper;
+struct CTupleGenYamlInfo;
+class ClientCfgDirExt;
-
+// To save memory, we use here the ClientCfgExt and ClientCfgDirExt,
+// and in tuple_gen the ClientCfgBase and ClientCfgDirBase
/**
* client configuration per direction
- *
+ *
* @author imarom (29-Jun-16)
*/
-class ClientCfgDir {
+class ClientCfgDirBase {
+ friend class ClientCfgCompactEntry;
-private:
+ protected:
enum {
- HAS_SRC_MAC = 0x1,
- HAS_DST_MAC = 0x2,
- HAS_VLAN = 0x4,
+ HAS_SRC_MAC = 0x1,
+ HAS_DST_MAC = 0x2,
+ HAS_VLAN = 0x4,
+ HAS_NEXT_HOP = 0x8,
+ HAS_IPV6_NEXT_HOP = 0x10,
+ HAS_SRC_IP = 0x20,
+ HAS_SRC_IPV6 = 0x40,
};
- uint8_t m_src_mac[6];
- uint8_t m_dst_mac[6];
+ MacAddress m_src_mac;
+ MacAddress m_dst_mac;
uint16_t m_vlan;
uint8_t m_bitfield;
-
-public:
- ClientCfgDir() {
+ public:
+ ClientCfgDirBase() {
m_bitfield = 0;
}
+ virtual void dump(FILE *fd) const;
bool has_src_mac_addr() const {
return (m_bitfield & HAS_SRC_MAC);
}
- bool has_dst_mac_addr() const {
- return (m_bitfield & HAS_DST_MAC);
- }
- bool has_vlan() const {
- return (m_bitfield & HAS_VLAN);
- }
-
void set_src_mac_addr(uint64_t mac_addr) {
- for (int i = 0; i < 6; i++) {
- m_src_mac[i] = ( mac_addr >> ((5 - i) * 8) ) & 0xFF;
- }
+ m_src_mac.set(mac_addr);
m_bitfield |= HAS_SRC_MAC;
}
void set_dst_mac_addr(uint64_t mac_addr) {
- for (int i = 0; i < 6; i++) {
- m_dst_mac[i] = ( mac_addr >> ((5 - i) * 8) ) & 0xFF;
- }
+ m_dst_mac.set(mac_addr);
m_bitfield |= HAS_DST_MAC;
}
@@ -83,26 +82,21 @@ public:
m_bitfield |= HAS_VLAN;
}
- /* updates a configuration with a group index member */
-
- void update(uint32_t index) {
- if (has_src_mac_addr()) {
- mac_add(m_src_mac, index);
- }
-
- if (has_dst_mac_addr()) {
- mac_add(m_dst_mac, index);
- }
+ bool has_dst_mac_addr() const {
+ return (m_bitfield & HAS_DST_MAC);
+ }
+ bool has_vlan() const {
+ return (m_bitfield & HAS_VLAN);
}
const uint8_t *get_src_mac_addr() const {
assert(has_src_mac_addr());
- return m_src_mac;
+ return m_src_mac.GetConstBuffer();
}
const uint8_t *get_dst_mac_addr() const {
assert(has_dst_mac_addr());
- return m_dst_mac;
+ return m_dst_mac.GetConstBuffer();
}
uint16_t get_vlan() const {
@@ -110,64 +104,165 @@ public:
return m_vlan;
}
+ /* updates a configuration with a group index member */
+ void update(uint32_t index, const ClientCfgDirExt &cfg);
+};
+
+class ClientCfgDirExt : public ClientCfgDirBase {
+ friend class ClientCfgCompactEntry;
+
private:
- /**
- * transform MAC address to uint64_t
- * performs add and return to MAC format
- *
- */
- void mac_add(uint8_t *mac, uint32_t i) {
- uint64_t tmp = 0;
+ enum {
+ HAS_SRC_MAC = 0x1,
+ HAS_DST_MAC = 0x2,
+ HAS_VLAN = 0x4,
+ HAS_NEXT_HOP = 0x8,
+ HAS_IPV6_NEXT_HOP = 0x10,
+ HAS_SRC_IP = 0x20,
+ HAS_SRC_IPV6 = 0x40,
+ };
- for (int i = 0; i < 6; i++) {
- tmp <<= 8;
- tmp |= mac[i];
+ uint32_t m_next_hop;
+ uint32_t m_src_ip;
+ uint16_t m_src_ipv6[8];
+ uint16_t m_ipv6_next_hop[8];
+ std::vector <MacAddress> m_resolved_macs;
+
+public:
+ void dump(FILE *fd) const;
+ void set_resolved_macs(CManyIPInfo &pretest_result, uint16_t count);
+ bool need_resolve() const;
+ void set_no_resolve_needed();
+
+ bool has_ipv6_next_hop() const {
+ return (m_bitfield & HAS_IPV6_NEXT_HOP);
+ }
+
+ bool has_next_hop() const {
+ return (m_bitfield & HAS_NEXT_HOP);
+ }
+
+ bool has_src_ip() const {
+ return (m_bitfield & HAS_SRC_IP);
+ }
+
+ bool has_src_ipv6() const {
+ return (m_bitfield & HAS_SRC_IPV6);
+ }
+
+ void set_src_ip(uint32_t src_ip) {
+ m_src_ip = src_ip;
+ m_bitfield |= HAS_SRC_IP;
+ }
+
+ void set_src_ipv6(const uint16_t src_ipv6[8]) {
+ for (int i = 0; i < 8; i++) {
+ m_src_ipv6[i] = src_ipv6[i];
}
+ m_bitfield |= HAS_SRC_IPV6;
+ }
- tmp += i;
+ void set_next_hop(uint32_t next_hop) {
+ m_next_hop = next_hop;
+ m_bitfield |= HAS_NEXT_HOP;
+ }
- for (int i = 0; i < 6; i++) {
- mac[i] = ( tmp >> ((5 - i) * 8) ) & 0xFF;
+ void set_ipv6_next_hop(const uint16_t next_hop[8]) {
+ for (int i = 0; i < 8; i++) {
+ m_ipv6_next_hop[i] = next_hop[i];
}
+ m_bitfield |= HAS_IPV6_NEXT_HOP;
+ }
+ virtual MacAddress get_resolved_mac(uint16_t index) const {
+ return m_resolved_macs[index];
}
+
};
+class ClientCfgExt;
+
/**
* single client config
- *
+ *
*/
-class ClientCfg {
+class ClientCfgBase {
public:
+ virtual void dump (FILE *fd) const {
+ fprintf(fd, " initiator :\n");
+ m_initiator.dump(fd);
+ fprintf(fd, " responder :\n");
+ m_responder.dump(fd);
+ }
+ virtual void update(uint32_t index, const ClientCfgExt *cfg);
- void update(uint32_t index) {
- m_initiator.update(index);
- m_responder.update(index);
+ public:
+ ClientCfgDirBase m_initiator;
+ ClientCfgDirBase m_responder;
+};
+
+class ClientCfgExt : public ClientCfgBase {
+public:
+ virtual void dump (FILE *fd) const {
+ fprintf(fd, " initiator:\n");
+ m_initiator.dump(fd);
+ fprintf(fd, " responder:\n");
+ m_responder.dump(fd);
}
- ClientCfgDir m_initiator;
- ClientCfgDir m_responder;
+ ClientCfgDirExt m_initiator;
+ ClientCfgDirExt m_responder;
+};
+
+class ClientCfgCompactEntry {
+ friend class ClientCfgDB;
+ public:
+ uint16_t get_count() {return m_count;}
+ uint16_t get_vlan() {return m_vlan;}
+ uint16_t get_port() {return m_port;}
+ bool is_ipv4() {return m_is_ipv4;}
+ uint32_t get_dst_ip() {return m_next_hop_base.ip;}
+ uint16_t *get_dst_ipv6() {return m_next_hop_base.ipv6;}
+ uint32_t get_src_ip() {return m_src_ip.ip;}
+ uint16_t *get_src_ipv6() {return m_src_ip.ipv6;}
+
+ public:
+ void fill_from_dir(ClientCfgDirExt cfg, uint8_t port_id);
+
+ private:
+ uint16_t m_count;
+ uint16_t m_vlan;
+ uint8_t m_port;
+ bool m_is_ipv4;
+ union {
+ uint32_t ip;
+ uint16_t ipv6[8];
+ } m_next_hop_base;
+ union {
+ uint32_t ip;
+ uint16_t ipv6[8];
+ } m_src_ip;
+
};
/******************************** internal section ********************************/
/**
- * describes a single client config
+ * describes a single client config
* entry loaded from the config file
- *
+ *
*/
class ClientCfgEntry {
-
+ friend class basic_client_cfg_test1_Test;
public:
ClientCfgEntry() {
reset();
}
-
- void dump() const;
-
+ void dump(FILE *fd) const;
+ void set_resolved_macs(CManyIPInfo &pretest_result);
bool contains(uint32_t ip) const {
return ( (ip >= m_ip_start) && (ip <= m_ip_end) );
}
@@ -176,19 +271,19 @@ public:
m_iterator = 0;
}
-
+
/**
- * assings a client config from the group
- * it will advance MAC addresses andf etc.
- *
+ * assings a client config from the group
+ * it will advance MAC addresses andf etc.
+ *
* @author imarom (27-Jun-16)
- *
- * @param info
+ *
+ * @param info
*/
- void assign(ClientCfg &info) {
+ void assign(ClientCfgBase &info) {
info = m_cfg;
- info.update(m_iterator);
-
+ info.update(m_iterator, &m_cfg);
+
/* advance for the next assign */
m_iterator = (m_iterator + 1) % m_count;
}
@@ -197,69 +292,92 @@ public:
uint32_t m_ip_start;
uint32_t m_ip_end;
- ClientCfg m_cfg;
+ ClientCfgExt m_cfg;
uint32_t m_count;
private:
+ void set_params(uint32_t start, uint32_t end, uint32_t count) { // for tests
+ m_ip_start = start;
+ m_ip_end = end;
+ m_count = count;
+ }
+ void set_cfg(const ClientCfgExt &cfg) {
+ m_cfg = cfg;
+ }
uint32_t m_iterator;
};
/**
* holds all the configured clients groups
- *
+ *
*/
class ClientCfgDB {
-public:
+ friend class basic_client_cfg_test1_Test;
+ public:
ClientCfgDB() {
m_is_empty = true;
m_cache_group = NULL;
m_under_vlan = false;
+ m_tg = NULL;
}
+ ~ClientCfgDB() {
+ m_groups.clear();
+ }
+
+ void dump(FILE *fd) ;
+
/**
- * if no config file was loaded
- * this should return true
- *
+ * if no config file was loaded
+ * this should return true
+ *
*/
bool is_empty() {
return m_is_empty;
}
+ void set_resolved_macs(CManyIPInfo &pretest_result);
+ void get_entry_list(std::vector<ClientCfgCompactEntry *> &ret);
+
+
/**
- * loads a YAML file
- * configuration will be built
- * according to the YAML config
- *
+ * loads a YAML file
+ * configuration will be built
+ * according to the YAML config
+ *
*/
void load_yaml_file(const std::string &filename);
/**
- * lookup for a specific IP address for
- * a group that contains this IP
- *
+ * lookup for a specific IP address for
+ * a group that contains this IP
+ *
*/
ClientCfgEntry * lookup(uint32_t ip);
ClientCfgEntry * lookup(const std::string &ip);
+ void set_tuple_gen_info(CTupleGenYamlInfo *tg) {m_tg = tg;}
private:
void parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node);
- void parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDir &dir);
-
+ void parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDirExt &dir);
+ void set_vlan(bool val) {m_under_vlan = val;} // for tests
+ void add_group(uint32_t ip, ClientCfgEntry cfg) { // for tests
+ m_groups.insert(std::make_pair(ip, cfg));
+ }
/**
* verify the YAML file loaded in valid
- *
+ *
*/
void verify(const YAMLParserWrapper &parser) const;
/* maps the IP start value to client groups */
std::map<uint32_t, ClientCfgEntry> m_groups;
- bool m_under_vlan;
-
- ClientCfgEntry *m_cache_group;
- bool m_is_empty;
+ bool m_under_vlan;
+ CTupleGenYamlInfo * m_tg;
+ ClientCfgEntry * m_cache_group;
+ bool m_is_empty;
};
#endif /* __TREX_CLIENT_CONFIG_H__ */
-
diff --git a/src/trex_port_attr.cpp b/src/trex_port_attr.cpp
new file mode 100644
index 00000000..2a68fcb9
--- /dev/null
+++ b/src/trex_port_attr.cpp
@@ -0,0 +1,152 @@
+/*
+Copyright (c) 2015-2015 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.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#include "trex_port_attr.h"
+#include "bp_sim.h"
+
+DestAttr::DestAttr(uint8_t port_id) {
+ m_port_id = port_id;
+
+ m_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest;
+ m_type = DEST_TYPE_MAC;
+
+ /* save the default */
+ memcpy(m_default_mac, m_mac, 6);
+}
+
+
+/**
+ * set dest as an IPv4 unresolved
+ */
+void
+DestAttr::set_dest(uint32_t ipv4) {
+ assert(ipv4 != 0);
+
+ m_ipv4 = ipv4;
+ memset(m_mac, 0, 6); // just to be on the safe side
+ m_type = DEST_TYPE_IPV4_UNRESOLVED;
+}
+
+/**
+ * set dest as a resolved IPv4
+ */
+void
+DestAttr::set_dest(uint32_t ipv4, const uint8_t *mac) {
+ assert(ipv4 != 0);
+
+ m_ipv4 = ipv4;
+
+ /* source might be the same as dest (this shadows the datapath memory) */
+ memmove(m_mac, mac, 6);
+ m_type = DEST_TYPE_IPV4;
+}
+
+/**
+ * dest dest as MAC
+ *
+ */
+void
+DestAttr::set_dest(const uint8_t *mac) {
+
+ m_ipv4 = 0;
+
+ /* source might be the same as dest (this shadows the datapath memory) */
+ memmove(m_mac, mac, 6);
+ m_type = DEST_TYPE_MAC;
+}
+
+void
+DestAttr::to_json(Json::Value &output) const {
+ switch (m_type) {
+
+ case DEST_TYPE_IPV4:
+ output["type"] = "ipv4";
+ output["ipv4"] = utl_uint32_to_ipv4(m_ipv4);
+ output["arp"] = utl_macaddr_to_str(m_mac);
+ break;
+
+ case DEST_TYPE_IPV4_UNRESOLVED:
+ output["type"] = "ipv4_u";
+ output["ipv4"] = utl_uint32_to_ipv4(m_ipv4);
+ break;
+
+ case DEST_TYPE_MAC:
+ output["type"] = "mac";
+ output["mac"] = utl_macaddr_to_str(m_mac);
+ break;
+
+ default:
+ assert(0);
+ }
+
+}
+
+const uint8_t *
+TRexPortAttr::get_src_mac() const {
+ return CGlobalInfo::m_options.get_src_mac_addr(m_port_id);
+}
+
+void
+TRexPortAttr::set_src_ipv4(uint32_t addr) {
+ m_src_ipv4 = addr;
+
+ /* when IP source changes - consider this as link down */
+ m_dest.on_link_down();
+}
+
+std::string
+TRexPortAttr::get_rx_filter_mode() const {
+ switch (m_rx_filter_mode) {
+ case RX_FILTER_MODE_ALL:
+ return "all";
+ case RX_FILTER_MODE_HW:
+ return "hw";
+ default:
+ assert(0);
+ }
+}
+
+
+void
+TRexPortAttr::to_json(Json::Value &output) {
+
+ output["src_mac"] = utl_macaddr_to_str(get_src_mac());
+ output["promiscuous"]["enabled"] = get_promiscuous();
+ output["link"]["up"] = is_link_up();
+ output["speed"] = get_link_speed() / 1000; // make sure we have no cards of less than 1 Gbps
+ output["rx_filter_mode"] = get_rx_filter_mode();
+
+ if (get_src_ipv4() != 0) {
+ output["src_ipv4"] = utl_uint32_to_ipv4(get_src_ipv4());
+ } else {
+ output["src_ipv4"] = Json::nullValue;
+ }
+
+
+ int mode;
+ get_flow_ctrl(mode);
+ output["fc"]["mode"] = mode;
+
+ m_dest.to_json(output["dest"]);
+
+}
+
+void
+TRexPortAttr::update_src_dst_mac(uint8_t *raw_pkt) const {
+ memcpy(raw_pkt, m_dest.get_dest_mac(), 6);
+ memcpy(raw_pkt + 6, get_src_mac(), 6);
+}
+
diff --git a/src/trex_port_attr.h b/src/trex_port_attr.h
index 9231e263..7336befa 100755
--- a/src/trex_port_attr.h
+++ b/src/trex_port_attr.h
@@ -21,10 +21,93 @@ limitations under the License.
#include <vector>
#include "rte_ethdev_includes.h"
#include "trex_defs.h"
+#include "common/basic_utils.h"
+#include <json/json.h>
+#include "trex_stateless_rx_defs.h"
+#include <string.h>
+
+/**
+ * destination port attribute
+ *
+ */
+class DestAttr {
+
+public:
+
+ DestAttr(uint8_t port_id);
+
+ /**
+ * dest can be either MAC IPv4, or IPv4 unresolved
+ */
+ enum dest_type_e {
+ DEST_TYPE_IPV4 = 1,
+ DEST_TYPE_IPV4_UNRESOLVED,
+ DEST_TYPE_MAC,
+ };
+
+ /**
+ * set dest as an IPv4 unresolved
+ */
+ void set_dest(uint32_t ipv4);
+
+ /**
+ * set dest as a resolved IPv4
+ */
+ void set_dest(uint32_t ipv4, const uint8_t *mac);
+
+ /**
+ * set dest as a plain MAC
+ */
+ void set_dest(const uint8_t *mac);
+
+
+ /**
+ * return true if destination is resolved
+ */
+ bool is_resolved() const {
+ return (m_type != DEST_TYPE_IPV4_UNRESOLVED);
+ }
+
+ /**
+ * get the dest mac
+ * if the dest is not resolved
+ * it will return the default MAC
+ */
+ const uint8_t *get_dest_mac() const {
+ return m_mac;
+ }
+
+ /**
+ * when link gets down - this should be called
+ *
+ */
+ void on_link_down() {
+ if (m_type == DEST_TYPE_IPV4) {
+ /* reset the IPv4 dest with no resolution */
+ set_dest(m_ipv4);
+ }
+ }
+
+ void to_json(Json::Value &output) const;
+
+private:
+ uint32_t m_ipv4;
+ uint8_t *m_mac;
+ dest_type_e m_type;
+ uint8_t m_port_id;
+
+private:
+ uint8_t m_default_mac[6];
+};
class TRexPortAttr {
public:
+
+ TRexPortAttr(uint8_t port_id) : m_dest(port_id) {
+ m_src_ipv4 = 0;
+ }
+
virtual ~TRexPortAttr(){}
/* UPDATES */
@@ -33,10 +116,10 @@ public:
virtual void update_device_info() = 0;
virtual void reset_xstats() = 0;
virtual void update_description() = 0;
-
+
/* GETTERS */
virtual bool get_promiscuous() = 0;
- virtual void macaddr_get(struct ether_addr *mac_addr) = 0;
+ virtual void get_hw_src_mac(struct ether_addr *mac_addr) = 0;
virtual uint32_t get_link_speed() { return m_link.link_speed; } // L1 Mbps
virtual bool is_link_duplex() { return (m_link.link_duplex ? true : false); }
virtual bool is_link_autoneg() { return (m_link.link_autoneg ? true : false); }
@@ -50,25 +133,53 @@ public:
virtual bool is_link_change_supported() { return flag_is_link_change_supported; }
virtual void get_description(std::string &description) { description = intf_info_st.description; }
virtual void get_supported_speeds(supp_speeds_t &supp_speeds) = 0;
+ virtual bool is_loopback() const = 0;
+
+ uint32_t get_src_ipv4() const {return m_src_ipv4;}
+ DestAttr & get_dest() {return m_dest;}
+
+ const uint8_t *get_src_mac() const;
+ std::string get_rx_filter_mode() const;
+ /* for a raw packet, write the src/dst MACs */
+ void update_src_dst_mac(uint8_t *raw_pkt) const;
+
/* SETTERS */
virtual int set_promiscuous(bool enabled) = 0;
virtual int add_mac(char * mac) = 0;
virtual int set_link_up(bool up) = 0;
virtual int set_flow_ctrl(int mode) = 0;
virtual int set_led(bool on) = 0;
-
-/* DUMPS */
+ virtual int set_rx_filter_mode(rx_filter_mode_e mode) = 0;
+
+ void set_src_ipv4(uint32_t addr);
+
+ /* DUMPS */
virtual void dump_link(FILE *fd) = 0;
+ /* dump object status to JSON */
+ void to_json(Json::Value &output);
+
+ uint8_t get_port_id() const {
+ return m_port_id;
+ }
+
protected:
- uint8_t m_port_id;
- rte_eth_link m_link;
- struct rte_eth_dev_info dev_info;
- bool flag_is_virtual;
- bool flag_is_fc_change_supported;
- bool flag_is_led_change_supported;
- bool flag_is_link_change_supported;
+
+ uint8_t m_port_id;
+ rte_eth_link m_link;
+ uint32_t m_src_ipv4;
+ DestAttr m_dest;
+
+ struct rte_eth_dev_info dev_info;
+
+ rx_filter_mode_e m_rx_filter_mode;
+
+ bool flag_is_virtual;
+ bool flag_is_fc_change_supported;
+ bool flag_is_led_change_supported;
+ bool flag_is_link_change_supported;
+
struct intf_info_st {
std::string pci_addr;
@@ -81,8 +192,11 @@ protected:
class DpdkTRexPortAttr : public TRexPortAttr {
public:
- DpdkTRexPortAttr(uint8_t port_id, bool is_virtual, bool fc_change_allowed) {
+ DpdkTRexPortAttr(uint8_t port_id, bool is_virtual, bool fc_change_allowed) : TRexPortAttr(port_id) {
+
m_port_id = port_id;
+ m_rx_filter_mode = RX_FILTER_MODE_HW;
+
flag_is_virtual = is_virtual;
int tmp;
flag_is_fc_change_supported = fc_change_allowed && (get_flow_ctrl(tmp) != -ENOTSUP);
@@ -101,12 +215,13 @@ public:
/* GETTERS */
virtual bool get_promiscuous();
- virtual void macaddr_get(struct ether_addr *mac_addr);
+ virtual void get_hw_src_mac(struct ether_addr *mac_addr);
virtual int get_xstats_values(xstats_values_t &xstats_values);
virtual int get_xstats_names(xstats_names_t &xstats_names);
virtual int get_flow_ctrl(int &mode);
virtual void get_supported_speeds(supp_speeds_t &supp_speeds);
-
+ virtual bool is_loopback() const;
+
/* SETTERS */
virtual int set_promiscuous(bool enabled);
virtual int add_mac(char * mac);
@@ -114,6 +229,7 @@ public:
virtual int set_flow_ctrl(int mode);
virtual int set_led(bool on);
+ virtual int set_rx_filter_mode(rx_filter_mode_e mode);
/* DUMPS */
virtual void dump_link(FILE *fd);
@@ -128,7 +244,7 @@ private:
class SimTRexPortAttr : public TRexPortAttr {
public:
- SimTRexPortAttr() {
+ SimTRexPortAttr() : TRexPortAttr(0) {
m_link.link_speed = 10000;
m_link.link_duplex = 1;
m_link.link_autoneg = 0;
@@ -146,7 +262,7 @@ public:
void reset_xstats() {}
void update_description() {}
bool get_promiscuous() { return false; }
- void macaddr_get(struct ether_addr *mac_addr) {}
+ void get_hw_src_mac(struct ether_addr *mac_addr) {}
int get_xstats_values(xstats_values_t &xstats_values) { return -ENOTSUP; }
int get_xstats_names(xstats_names_t &xstats_names) { return -ENOTSUP; }
int get_flow_ctrl(int &mode) { return -ENOTSUP; }
@@ -158,6 +274,8 @@ public:
int set_flow_ctrl(int mode) { return -ENOTSUP; }
int set_led(bool on) { return -ENOTSUP; }
void dump_link(FILE *fd) {}
+ int set_rx_filter_mode(rx_filter_mode_e mode) { return -ENOTSUP; }
+ virtual bool is_loopback() const { return false; }
};
diff --git a/src/tuple_gen.cpp b/src/tuple_gen.cpp
index 6861b73f..a4509580 100755
--- a/src/tuple_gen.cpp
+++ b/src/tuple_gen.cpp
@@ -6,7 +6,7 @@
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 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.
@@ -21,11 +21,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-
-#include "tuple_gen.h"
#include <string.h>
#include "utl_yaml.h"
#include "bp_sim.h"
+#include "tuple_gen.h"
void CServerPool::Create(IP_DIST_t dist_value,
uint32_t min_ip,
@@ -134,7 +133,7 @@ void CClientPool::allocate_configured_clients(uint32_t min_ip,
throw std::runtime_error(ss.str());
}
- ClientCfg info;
+ ClientCfgBase info;
group->assign(info);
if (is_long_range) {
@@ -216,13 +215,84 @@ void CTupleGeneratorSmart::Delete(){
m_server_pool.clear();
}
+void CTupleGenYamlInfo::dump(FILE *fd) {
+ fprintf(fd, "Client pools:\n");
+ for (int i=0; i < m_client_pool.size(); i++) {
+ m_client_pool[i].Dump(fd);
+ }
+ fprintf(fd, "Server pools:\n");
+ for (int i=0; i < m_server_pool.size(); i++) {
+ m_server_pool[i].Dump(fd);
+ }
+}
+
+// Find out matching port for given ip range.
+// If found, port is returned in port, otherwise port is set to UINT8_MAX
+// Return false in case of error. True otherwise. Port not found is not considered error.
+bool CTupleGenYamlInfo::find_port(uint32_t ip_start, uint32_t ip_end, uint8_t &port) {
+ uint8_t num_ports = CGlobalInfo::m_options.get_expected_ports();
+
+ for (int i=0; i < m_client_pool.size(); i++) {
+ CTupleGenPoolYaml &pool = m_client_pool[i];
+ uint32_t pool_start = pool.get_ip_start();
+ uint32_t pool_end = pool.get_ip_end();
+ uint32_t pool_offset = pool.getDualMask();
+ for (uint8_t port_id = 0; port_id < num_ports; port_id += 2) {
+ uint32_t pool_port_start = pool_start + pool_offset * port_id / 2;
+ uint32_t pool_port_end = pool_end + pool_offset * port_id / 2;
+ if ((ip_start >= pool_port_start) && (ip_start <= pool_port_end)) {
+ if ((ip_end >= pool_port_start) && (ip_end <= pool_port_end)) {
+ port = port_id;
+ return true;
+ } else {
+ // ip_start in range, ip_end not
+ fprintf(stderr, "Error for range %s - %s. Start is inside range %s - %s, but end is outside\n"
+ , ip_to_str(ip_start).c_str(), ip_to_str(ip_end).c_str()
+ , ip_to_str(pool_port_start).c_str(), ip_to_str(pool_port_end).c_str());
+ port = UINT8_MAX;
+ return false;
+ }
+ }
+ }
+ }
+
+ for (int i=0; i < m_server_pool.size(); i++) {
+ CTupleGenPoolYaml &pool = m_server_pool[i];
+ uint32_t pool_start = pool.get_ip_start();
+ uint32_t pool_end = pool.get_ip_end();
+ uint32_t pool_offset = pool.getDualMask();
+ for (uint8_t port_id = 1; port_id < num_ports; port_id += 2) {
+ uint32_t pool_port_start = pool_start + pool_offset * (port_id - 1) / 2;
+ uint32_t pool_port_end = pool_end + pool_offset * (port_id - 1)/ 2;
+ if ((ip_start >= pool_port_start) && (ip_start <= pool_port_end)) {
+ if ((ip_end >= pool_port_start) && (ip_end <= pool_port_end)) {
+ port = port_id;
+ return true;
+ } else {
+ fprintf(stderr, "Error for range %s - %s. Start is inside range %s - %s, but end is outside\n"
+ , ip_to_str(ip_start).c_str(), ip_to_str(ip_end).c_str()
+ , ip_to_str(pool_port_start).c_str(), ip_to_str(pool_port_end).c_str());
+ // ip_start in range, ip_end not
+ port = UINT8_MAX;
+ return false;
+ }
+ }
+ }
+ }
+
+ port = UINT8_MAX;
+ return true;
+}
+
void CTupleGenPoolYaml::Dump(FILE *fd){
- fprintf(fd," dist : %d \n",m_dist);
- fprintf(fd," IPs : %08x -%08x \n",m_ip_start,m_ip_end);
- fprintf(fd," clients per gb : %d \n",m_number_of_clients_per_gb);
- fprintf(fd," min clients : %d \n",m_min_clients);
- fprintf(fd," tcp aging : %d sec \n",m_tcp_aging_sec);
- fprintf(fd," udp aging : %d sec \n",m_udp_aging_sec);
+ fprintf(fd," Pool %s:\n", (m_name.size() == 0) ? "default":m_name.c_str());
+ fprintf(fd," dist : %d \n",m_dist);
+ fprintf(fd," IPs : %s - %s \n",ip_to_str(m_ip_start).c_str(), ip_to_str(m_ip_end).c_str());
+ fprintf(fd," dual_port_mask : %s \n",ip_to_str(m_dual_interface_mask).c_str());
+ fprintf(fd," clients per gb : %d \n",m_number_of_clients_per_gb);
+ fprintf(fd," min clients : %d \n",m_min_clients);
+ fprintf(fd," tcp aging : %d sec \n",m_tcp_aging_sec);
+ fprintf(fd," udp aging : %d sec \n",m_udp_aging_sec);
}
bool CTupleGenPoolYaml::is_valid(uint32_t num_threads,bool is_plugins){
@@ -244,10 +314,6 @@ bool CTupleGenPoolYaml::is_valid(uint32_t num_threads,bool is_plugins){
return (true);
}
-
-
-
-
#define UTL_YAML_READ(type, field, target) if (node.FindValue(#field)) { \
utl_yaml_read_ ## type (node, #field , target); \
} else { printf("generator definition mising " #field "\n"); }
diff --git a/src/tuple_gen.h b/src/tuple_gen.h
index 2491f489..e9dc8d4e 100755
--- a/src/tuple_gen.h
+++ b/src/tuple_gen.h
@@ -85,15 +85,15 @@ public:
void setClientPort(uint16_t port) {
m_client_port = port;
}
- void setClientCfg(ClientCfg *cfg) {
+ void setClientCfg(ClientCfgBase *cfg) {
m_client_cfg = cfg;
}
- ClientCfg *getClientCfg() {
+ ClientCfgBase *getClientCfg() {
return m_client_cfg;
}
- void setClientTuple(uint32_t ip, ClientCfg *cfg, uint16_t port) {
+ void setClientTuple(uint32_t ip, ClientCfgBase *cfg, uint16_t port) {
setClient(ip);
setClientPort(port);
setClientCfg(cfg);
@@ -125,7 +125,7 @@ private:
uint32_t m_server_ip;
uint32_t m_server_idx;
- ClientCfg *m_client_cfg;
+ ClientCfgBase *m_client_cfg;
uint16_t m_client_port;
uint16_t m_server_port;
@@ -337,7 +337,7 @@ template <typename T>
class CConfiguredClientInfo : public T {
public:
- CConfiguredClientInfo(uint32_t ip, const ClientCfg &cfg) : m_cfg(cfg) {
+ CConfiguredClientInfo(uint32_t ip, const ClientCfgBase &cfg) : m_cfg(cfg) {
T::set_ip(ip);
}
@@ -348,7 +348,7 @@ public:
}
private:
- ClientCfg m_cfg;
+ ClientCfgBase m_cfg;
};
@@ -852,6 +852,9 @@ struct CTupleGenPoolYaml {
uint32_t get_ip_start() {
return m_ip_start;
}
+ uint32_t get_ip_end() {
+ return m_ip_end;
+ }
bool is_valid(uint32_t num_threads,bool is_plugins);
void Dump(FILE *fd);
};
@@ -888,6 +891,9 @@ public:
exit(-1);
return 0;
}
+
+ bool find_port(uint32_t ip_start, uint32_t ip_end, uint8_t &port);
+ void dump(FILE *fd);
};
diff --git a/src/utl_ip.cpp b/src/utl_ip.cpp
new file mode 100644
index 00000000..d29ab60a
--- /dev/null
+++ b/src/utl_ip.cpp
@@ -0,0 +1,139 @@
+/*
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016-2016 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.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include <string>
+#include <iostream>
+#include <pkt_gen.h>
+#include "utl_ip.h"
+
+void COneIPInfo::dump(FILE *fd, const char *offset) const {
+ uint8_t mac[ETHER_ADDR_LEN];
+ m_mac.copyToArray(mac);
+ char ip_str[100];
+ get_ip_str(ip_str);
+ std::string mac_str;
+ utl_macaddr_to_str(mac, mac_str);
+ const char *mac_char = resolve_needed() ? "Unknown" : mac_str.c_str();
+ fprintf(fd, "%sip: %s ", offset, ip_str);
+ if (m_vlan != 0)
+ fprintf(fd, "vlan: %d ", m_vlan);
+ if (m_port != UINT8_MAX)
+ fprintf(fd, "port: %d ", m_port);
+ fprintf(fd, "mac: %s", mac_char);
+ fprintf(fd, "\n");
+}
+
+bool COneIPInfo::resolve_needed() const {
+ return m_mac.isDefaultAddress();
+}
+
+/*
+ * Fill buffer p with arp request.
+ * port_id - port id we intend to send on
+ * sip - source IP/MAC information
+ */
+void COneIPv4Info::fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip) {
+ uint8_t src_mac[ETHER_ADDR_LEN];
+ sip->get_mac(src_mac);
+
+ CTestPktGen::create_arp_req(p, ((COneIPv4Info *)sip)->get_ip(), m_ip, src_mac, m_vlan, port_id);
+}
+
+void COneIPv4Info::fill_grat_arp_buf(uint8_t *p) {
+ uint8_t src_mac[ETHER_ADDR_LEN];
+ get_mac(src_mac);
+
+ CTestPktGen::create_arp_req(p, m_ip, m_ip, src_mac, m_vlan, 0);
+}
+
+void COneIPv6Info::fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip) {
+ //??? implement ipv6
+}
+
+void COneIPv6Info::fill_grat_arp_buf(uint8_t *p) {
+ //??? implement ipv6
+}
+
+const COneIPInfo *CManyIPInfo::get_next() {
+ const COneIPInfo *ret;
+
+ if (!m_iter_initiated) {
+ m_ipv4_iter = m_ipv4_resolve.begin();
+ m_iter_initiated = true;
+ }
+
+
+ if (m_ipv4_iter == m_ipv4_resolve.end()) {
+ m_ipv4_iter = m_ipv4_resolve.begin();
+ return NULL;
+ }
+
+ ret = &(m_ipv4_iter->second);
+ m_ipv4_iter++;
+ return ret;
+}
+
+void CManyIPInfo::dump(FILE *fd) {
+ ip_vlan_to_many_ip_iter_t it;
+ for (it = m_ipv4_resolve.begin(); it != m_ipv4_resolve.end(); it++) {
+ fprintf(fd, "IPv4 resolved list:\n");
+ uint8_t mac[ETHER_ADDR_LEN];
+ it->second.get_mac(mac);
+ fprintf(fd, "ip:%s vlan: %d resolved to mac %s\n", ip_to_str(it->first.get_ip()).c_str(), it->first.get_vlan()
+ , utl_macaddr_to_str(mac).c_str());
+ }
+}
+
+void CManyIPInfo::insert(const COneIPv4Info &ip_info) {
+ CIpVlan ip_vlan(ip_info.get_ip(), ip_info.get_vlan());
+
+ m_ipv4_resolve.insert(std::make_pair(ip_vlan, ip_info));
+}
+
+bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) const {
+ ip_vlan_to_many_ip_iter_t it = m_ipv4_resolve.find(CIpVlan(ip, vlan));
+ if (it != m_ipv4_resolve.end()) {
+ uint8_t mac[ETHER_ADDR_LEN];
+ (*it).second.get_mac(mac);
+ ret_mac.set(mac);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool CManyIPInfo::exists(uint32_t ip, uint16_t vlan) const {
+ ip_vlan_to_many_ip_iter_t it = m_ipv4_resolve.find(CIpVlan(ip, vlan));
+ return (it != m_ipv4_resolve.end());
+}
+
+void CManyIPInfo::clear() {
+ m_ipv4_resolve.clear();
+ m_ipv6_resolve.clear();
+ m_iter_initiated = false;
+}
+
+const COneIPInfo *CManyIPInfo::get_first() {
+ if (m_ipv4_resolve.size() == 0) {
+ return NULL;
+ } else {
+ m_ipv4_iter = m_ipv4_resolve.begin();
+ return &(m_ipv4_iter->second);
+ }
+}
diff --git a/src/utl_ip.h b/src/utl_ip.h
new file mode 100644
index 00000000..bab92c0f
--- /dev/null
+++ b/src/utl_ip.h
@@ -0,0 +1,269 @@
+#ifndef UTL_IP_H
+#define UTL_IP_H
+/*
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016-2016 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.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include <map>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "common/basic_utils.h"
+#include "common/Network/Packet/CPktCmn.h"
+#include "common/Network/Packet/MacAddress.h"
+
+/* IP address, last 32-bits of IPv6 remaps IPv4 */
+typedef struct {
+ uint16_t v6[6]; /* First 96-bits of IPv6 */
+ uint32_t v4; /* Last 32-bits IPv6 overloads v4 */
+} ipaddr_t;
+
+// Routine to create IPv4 address string
+inline int ip_to_str(uint32_t ip,char * str) {
+ uint32_t ipv4 = PKT_HTONL(ip);
+ inet_ntop(AF_INET, (const char *)&ipv4, str, INET_ADDRSTRLEN);
+ return(strlen(str));
+}
+
+inline std::string ip_to_str(uint32_t ip) {
+ char tmp[INET_ADDRSTRLEN];
+ ip_to_str(ip, tmp);
+ return tmp;
+}
+
+// Routine to create IPv6 address string
+inline int ipv6_to_str(ipaddr_t *ip, char * str) {
+ int idx=0;
+ uint16_t ipv6[8];
+ for (uint8_t i=0; i<6; i++) {
+ ipv6[i] = PKT_HTONS(ip->v6[i]);
+ }
+ uint32_t ipv4 = PKT_HTONL(ip->v4);
+ ipv6[6] = ipv4 & 0xffff;
+ ipv6[7] = ipv4 >> 16;
+
+ str[idx++] = '[';
+ inet_ntop(AF_INET6, (const char *)&ipv6, &str[1], INET6_ADDRSTRLEN);
+ idx = strlen(str);
+ str[idx++] = ']';
+ str[idx] = 0;
+ return(idx);
+}
+
+inline std::string ip_to_str(uint8_t *ip) {
+ char tmp[INET6_ADDRSTRLEN];
+ ipv6_to_str((ipaddr_t *)ip, tmp);
+ return tmp;
+}
+
+class CIpVlan {
+ // to be able to use this in map
+ friend bool operator<(const CIpVlan& l, const CIpVlan& r) {
+ if (l.get_ip() == r.get_ip()) {
+ return l.get_vlan() < r.get_vlan();
+ } else {
+ return l.get_ip() < r.get_ip();
+ }
+ }
+
+ public:
+ CIpVlan(uint32_t ip, uint16_t vlan) {
+ m_ip = ip;
+ m_vlan = vlan;
+ }
+ uint16_t get_vlan() const {return m_vlan;}
+ void set_vlan(uint16_t vlan) {m_vlan = vlan;}
+ uint16_t get_ip() const {return m_ip;}
+ void set_ip(uint32_t ip) {m_ip = ip;}
+
+ private:
+ uint32_t m_ip;
+ uint16_t m_vlan;
+};
+
+
+class COneIPInfo {
+ public:
+ enum {
+ IP4_VER=4,
+ IP6_VER=6,
+ } COneIPInfo_ip_types;
+
+ public:
+ virtual ~COneIPInfo() {}
+ virtual void get_mac(uint8_t *mac) const {
+ m_mac.copyToArray(mac);
+ }
+ virtual void set_mac(uint8_t *mac) {
+ m_mac.set(mac);
+ }
+ uint16_t get_vlan() const {return m_vlan;}
+ uint16_t get_port() const {return m_port;}
+ void set_port(uint8_t port) {m_port = port;}
+ virtual void dump(FILE *fd) const {
+ dump(fd, "");
+ }
+ virtual void dump(FILE *fd, const char *offset) const;
+ virtual uint8_t ip_ver() const {return 0;}
+ virtual uint32_t get_arp_req_len() const=0;
+ virtual uint32_t get_grat_arp_len() const=0;
+ virtual void fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip)=0;
+ virtual void fill_grat_arp_buf(uint8_t *p)=0;
+ virtual bool resolve_needed() const;
+
+ protected:
+ COneIPInfo(uint16_t vlan, MacAddress mac, uint8_t port) : m_mac(mac) {
+ m_vlan = vlan;
+ m_port = port;
+ }
+ COneIPInfo(uint16_t vlan, MacAddress mac) : COneIPInfo(vlan, mac, UINT8_MAX) {
+ }
+ virtual const void get_ip_str(char str[100]) const {
+ snprintf(str, 4, "Bad");
+ }
+
+ protected:
+ uint8_t m_port;
+ uint16_t m_vlan;
+ MacAddress m_mac;
+};
+
+class COneIPv4Info : public COneIPInfo {
+ friend bool operator== (const COneIPv4Info& lhs, const COneIPv4Info& rhs);
+
+ public:
+ COneIPv4Info(uint32_t ip, uint16_t vlan, MacAddress mac) : COneIPInfo(vlan, mac) {
+ m_ip = ip;
+ }
+ COneIPv4Info(uint32_t ip, uint16_t vlan) : COneIPv4Info (ip, vlan, MacAddress()) {
+ }
+ COneIPv4Info(uint32_t ip, uint16_t vlan, MacAddress mac, uint8_t port) : COneIPInfo(vlan, mac, port) {
+ m_ip = ip;
+ }
+ ~COneIPv4Info() {};
+ uint32_t get_ip() const {return m_ip;}
+ virtual uint8_t ip_ver() const {return IP4_VER;}
+ virtual uint32_t get_arp_req_len() const {return 60;}
+ virtual uint32_t get_grat_arp_len() const {return 60;}
+ virtual void fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip);
+ virtual void fill_grat_arp_buf(uint8_t *p);
+
+ private:
+ virtual const void get_ip_str(char str[100]) const {
+ ip_to_str(m_ip, str);
+ };
+ uint32_t m_ip;
+};
+
+inline bool operator== (const COneIPv4Info& lhs, const COneIPv4Info& rhs) {
+ if (lhs.m_vlan != rhs.m_vlan)
+ return false;
+
+ if (lhs.m_ip != rhs.m_ip)
+ return false;
+
+ return true;
+}
+
+inline bool operator!= (const COneIPv4Info& lhs, const COneIPv4Info& rhs){ return !(lhs == rhs); }
+
+class COneIPv6Info : public COneIPInfo {
+ friend bool operator== (const COneIPv6Info& lhs, const COneIPv6Info& rhs);
+
+ public:
+ COneIPv6Info(uint16_t ip[8], uint16_t vlan, MacAddress mac) : COneIPInfo(vlan, mac) {
+ memcpy(m_ip, ip, sizeof(m_ip));
+ }
+
+ COneIPv6Info(uint16_t ip[8], uint16_t vlan) : COneIPv6Info(ip, vlan, MacAddress()){
+ }
+
+ COneIPv6Info(uint16_t ip[8], uint16_t vlan, MacAddress mac, uint8_t port) : COneIPInfo(vlan, mac, port) {
+ memcpy(m_ip, ip, sizeof(m_ip));
+ }
+ ~COneIPv6Info() {}
+
+ const uint8_t *get_ipv6() {return (uint8_t *)m_ip;}
+ virtual uint8_t ip_ver() const {return IP6_VER;}
+ virtual uint32_t get_arp_req_len() const {return 100; /* ??? put correct number for ipv6*/}
+ virtual uint32_t get_grat_arp_len() const {return 100; /* ??? put correct number for ipv6*/}
+ virtual void fill_arp_req_buf(uint8_t *p, uint16_t port_id, COneIPInfo *sip);
+ virtual void fill_grat_arp_buf(uint8_t *p);
+
+ private:
+ virtual const void get_ip_str(char str[100]) {
+ ipv6_to_str((ipaddr_t *)m_ip, str);
+ }
+ uint16_t m_ip[8];
+};
+
+inline bool operator== (const COneIPv6Info& lhs, const COneIPv6Info& rhs) {
+ if (lhs.m_vlan != rhs.m_vlan)
+ return false;
+
+ if (memcmp(&lhs.m_ip, &rhs.m_ip, sizeof(rhs.m_ip)))
+ return false;
+
+ return true;
+}
+
+inline bool operator!= (const COneIPv6Info& lhs, const COneIPv6Info& rhs){ return !(lhs == rhs); }
+
+typedef std::map<CIpVlan, COneIPv4Info> ip_vlan_to_many_ip_t;
+typedef std::map<CIpVlan, COneIPv4Info>::const_iterator ip_vlan_to_many_ip_iter_t;
+typedef std::map<std::pair<uint16_t[8], uint16_t>, COneIPv6Info> ipv6_vlan_to_many_ipv6_t;
+
+class CManyIPInfo {
+ public:
+ CManyIPInfo () {
+ m_iter_initiated = false;
+ }
+ void insert(const COneIPv4Info &ip_info);
+ bool lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) const;
+ bool exists(uint32_t ip, uint16_t vlan = 0) const;
+ void clear();
+
+ void dump(FILE *fd);
+ uint32_t size() { return m_ipv4_resolve.size() + m_ipv6_resolve.size();}
+ const COneIPInfo *get_first();
+ const COneIPInfo *get_next();
+ const COneIPInfo *get_next_loop() {
+ const COneIPInfo *ip_info = get_next();
+ return (ip_info ? ip_info : get_next());
+ }
+
+ CManyIPInfo& operator = (const CManyIPInfo &rhs) {
+ m_ipv4_resolve = rhs.m_ipv4_resolve;
+ m_ipv6_resolve = rhs.m_ipv6_resolve;
+
+ m_iter_initiated = false;
+ return (*this);
+ }
+
+ private:
+ ip_vlan_to_many_ip_t m_ipv4_resolve;
+ ipv6_vlan_to_many_ipv6_t m_ipv6_resolve;
+
+ ip_vlan_to_many_ip_iter_t m_ipv4_iter;
+
+ bool m_iter_initiated;
+
+};
+
+
+#endif
diff --git a/src/utl_term_io.cpp b/src/utl_term_io.cpp
index 8e561188..e45aeebd 100755
--- a/src/utl_term_io.cpp
+++ b/src/utl_term_io.cpp
@@ -78,6 +78,13 @@ int utl_termio_init(){
atexit(exit_handler1);
save_termio();
set_conio_terminal_mode();
+
+ /* stdout is non-blocking */
+ int fd = fileno(stdout);
+ int f = fcntl(fd, F_GETFL, 0);
+ f |= O_NONBLOCK;
+ fcntl(fd, F_SETFL, f);
+
return (0);
}
diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp
index 094a3de8..a4fd6404 100755
--- a/src/utl_yaml.cpp
+++ b/src/utl_yaml.cpp
@@ -1,12 +1,10 @@
-#include "utl_yaml.h"
-#include <common/Network/Packet/CPktCmn.h>
/*
Hanoh Haim
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 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.
@@ -24,13 +22,15 @@ limitations under the License.
#include <istream>
#include <fstream>
#include "common/basic_utils.h"
+#include <common/Network/Packet/CPktCmn.h>
+#include "utl_yaml.h"
#define INADDRSZ 4
extern int my_inet_pton4(const char *src, unsigned char *dst);
extern int my_inet_pton6(const char *src, unsigned char *dst);
-bool utl_yaml_read_ip_addr(const YAML::Node& node,
+bool utl_yaml_read_ip_addr(const YAML::Node& node,
const std::string &name,
uint32_t & val){
std::string tmp;
@@ -42,16 +42,14 @@ bool utl_yaml_read_ip_addr(const YAML::Node& node,
val=PKT_NTOHL(ip);
res=true;
}else{
- printf(" ERROR not a valid ip %s \n",(char *)tmp.c_str());
+ printf(" Error: non valid ip %s \n",(char *)tmp.c_str());
exit(-1);
}
}
return (res);
}
-
-
-bool utl_yaml_read_uint32(const YAML::Node& node,
+bool utl_yaml_read_uint32(const YAML::Node& node,
const std::string &name,
uint32_t & val){
bool res=false;
@@ -62,7 +60,7 @@ bool utl_yaml_read_uint32(const YAML::Node& node,
return (res);
}
-bool utl_yaml_read_uint16(const YAML::Node& node,
+bool utl_yaml_read_uint16(const YAML::Node& node,
const std::string &name,
uint16_t & val){
uint32_t val_tmp;
@@ -183,10 +181,10 @@ YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name) {
return (val);
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting true/false for field '" + name + "'", node[name]);
+ parse_err("Expecting true/false for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -203,10 +201,10 @@ YAMLParserWrapper::parse_list(const YAML::Node &node, const std::string &name) {
return val;
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting sequence/list for field '" + name + "'", node[name]);
+ parse_err("Expecting sequence or list for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -223,10 +221,10 @@ YAMLParserWrapper::parse_map(const YAML::Node &node, const std::string &name) {
return val;
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting map for field '" + name + "'", node[name]);
+ parse_err("Expecting map for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -241,16 +239,43 @@ YAMLParserWrapper::parse_ip(const YAML::Node &node, const std::string &name) {
node[name] >> ip_str;
int rc = my_inet_pton4((char *)ip_str.c_str(), (unsigned char *)&ip_num);
if (!rc) {
- parse_err("invalid IP address: " + ip_str, node[name]);
+ parse_err("Invalid IP address: " + ip_str, node[name]);
}
return PKT_NTOHL(ip_num);
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting valid IP address for field '" + name + "'", node[name]);
+ parse_err("Expecting valid IP address for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("Can not locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+void
+YAMLParserWrapper::parse_ipv6(const YAML::Node &node, const std::string &name, unsigned char *ip_num) {
+ try {
+ std::string ip_str;
+
+ node[name] >> ip_str;
+ int rc = my_inet_pton6((char *)ip_str.c_str(), ip_num);
+ if (!rc) {
+ parse_err("Invalid IPv6 address: " + ip_str, node[name]);
+ }
+
+ // we want host order
+ for (int i = 0; i < 8; i++) {
+ ((uint16_t *) ip_num)[i] = PKT_NTOHS(((uint16_t *) ip_num)[i]);
+ }
+ return;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("Expecting valid IPv6 address for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
@@ -276,21 +301,21 @@ YAMLParserWrapper::parse_mac_addr(const YAML::Node &node, const std::string &nam
node[name] >> mac_str;
bool rc = mac2uint64(mac_str, mac_num);
if (!rc) {
- parse_err("invalid MAC address: " + mac_str, node[name]);
+ parse_err("Invalid MAC address: " + mac_str, node[name]);
}
return mac_num;
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting true/false for field '" + name + "'", node[name]);
+ parse_err("Expecting true/false for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
}
-uint64_t
+uint64_t
YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high, uint64_t def) {
if (!node.FindValue(name)) {
return def;
@@ -299,7 +324,7 @@ YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, u
return parse_uint(node, name, low, high);
}
-uint64_t
+uint64_t
YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high) {
try {
@@ -316,10 +341,10 @@ YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, u
return (val);
} catch (const YAML::InvalidScalar &ex) {
- parse_err("expecting true/false for field '" + name + "'", node[name]);
+ parse_err("Expecting true/false for field '" + name + "'", node[name]);
} catch (const YAML::KeyNotFound &ex) {
- parse_err("cannot locate mandatory field '" + name + "'", node);
+ parse_err("Can not locate mandatory field '" + name + "'", node);
}
assert(0);
diff --git a/src/utl_yaml.h b/src/utl_yaml.h
index ed7d66d6..004e82db 100755
--- a/src/utl_yaml.h
+++ b/src/utl_yaml.h
@@ -63,6 +63,7 @@ public:
const YAML::Node & parse_map(const YAML::Node &node, const std::string &name);
uint32_t parse_ip(const YAML::Node &node, const std::string &name);
+ void parse_ipv6(const YAML::Node &node, const std::string &name, unsigned char *ip);
uint64_t parse_mac_addr(const YAML::Node &node, const std::string &name);
uint64_t parse_mac_addr(const YAML::Node &node, const std::string &name, uint64_t def);