diff options
author | 2015-06-24 14:03:29 +0300 | |
---|---|---|
committer | 2015-06-24 14:03:29 +0300 | |
commit | 8b52a31ed2c299b759f330c4f976b9c70f5765f4 (patch) | |
tree | 9d6da5438b5b56b1d2d57e6c13494b4e65d000e7 /src/main_dpdk.cpp |
first version
Diffstat (limited to 'src/main_dpdk.cpp')
-rwxr-xr-x | src/main_dpdk.cpp | 5041 |
1 files changed, 5041 insertions, 0 deletions
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp new file mode 100755 index 00000000..22ecc52f --- /dev/null +++ b/src/main_dpdk.cpp @@ -0,0 +1,5041 @@ +/* + Hanoh Haim + Cisco Systems, Inc. +*/ + +/* +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. +*/ + +// DPDK c++ issue +#define UINT8_MAX 255 +#define UINT16_MAX 0xFFFF +// DPDK c++ issue + +#include <pwd.h> +#include <rte_common.h> +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_memzone.h> +#include <rte_tailq.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_cycles.h> +#include <rte_prefetch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> +#include <rte_interrupts.h> +#include <rte_pci.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_ring.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_random.h> +#include "bp_sim.h" +#include "os_time.h" +#include <common/arg/SimpleGlob.h> +#include <common/arg/SimpleOpt.h> +#include <common/basic_utils.h> + +extern "C" { + #include <dpdk_lib18/librte_pmd_ixgbe/ixgbe/ixgbe_type.h> +} +#include <dpdk_lib18/librte_pmd_e1000/e1000/e1000_regs.h> +#include <zmq.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <pthread.h> +#include "global_io_mode.h" +#include "utl_term_io.h" +#include "msg_manager.h" +#include "platform_cfg.h" + +#define VERSION "1.73" + + +#define RX_CHECK_MIX_SAMPLE_RATE 8 +#define RX_CHECK_MIX_SAMPLE_RATE_1G 2 + + +#define SOCKET0 0 + +#define BP_MAX_PKT 32 +#define MAX_PKT_BURST 32 + + +#define BP_MAX_PORTS (MAX_LATENCY_PORTS) +#define BP_MAX_CORES 32 +#define BP_MAX_TX_QUEUE 16 +#define BP_MASTER_AND_LATENCY 2 + +#define RTE_TEST_RX_DESC_DEFAULT 64 +#define RTE_TEST_RX_LATENCY_DESC_DEFAULT (1*1024) + +#define RTE_TEST_RX_DESC_VM_DEFAULT 512 +#define RTE_TEST_TX_DESC_VM_DEFAULT 512 + +typedef struct rte_mbuf * (*rte_mbuf_convert_to_one_seg_t)(struct rte_mbuf *m); +struct rte_mbuf * rte_mbuf_convert_to_one_seg(struct rte_mbuf *m); +extern "C" int vmxnet3_xmit_set_callback(rte_mbuf_convert_to_one_seg_t cb); + + + +#define RTE_TEST_TX_DESC_DEFAULT 512 +#define RTE_TEST_RX_DESC_DROP 0 + + + +static inline int get_vm_one_queue_enable(){ + return (CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ?1:0); +} + +static inline int get_is_latency_thread_enable(){ + return (CGlobalInfo::m_options.is_latency_enabled() ?1:0); +} + + + +struct port_cfg_t; +class CPhyEthIF; +class CPhyEthIFStats ; + + +class CTRexExtendedDriverBase { +public: + virtual int get_min_sample_rate(void)=0; + virtual void update_configuration(port_cfg_t * cfg)=0; + virtual void update_global_config_fdir(port_cfg_t * cfg)=0; + + virtual bool is_hardware_filter_is_supported(){ + return(false); + } + virtual int configure_rx_filter_rules(CPhyEthIF * _if)=0; + + virtual bool is_hardware_support_drop_queue(){ + return(false); + } + + virtual int configure_drop_queue(CPhyEthIF * _if)=0; + virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0; + virtual void clear_extended_stats(CPhyEthIF * _if)=0; + virtual int wait_for_stable_link()=0; +}; + + +class CTRexExtendedDriverBase1G : public CTRexExtendedDriverBase { + +public: + CTRexExtendedDriverBase1G(){ + } + + static CTRexExtendedDriverBase * create(){ + return ( new CTRexExtendedDriverBase1G() ); + } + + virtual void update_global_config_fdir(port_cfg_t * cfg); + + virtual int get_min_sample_rate(void){ + return ( RX_CHECK_MIX_SAMPLE_RATE_1G); + } + virtual void update_configuration(port_cfg_t * cfg); + + virtual bool is_hardware_filter_is_supported(){ + return (true); + } + + virtual int configure_rx_filter_rules(CPhyEthIF * _if); + + virtual bool is_hardware_support_drop_queue(){ + return(true); + } + + virtual int configure_drop_queue(CPhyEthIF * _if); + + virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats); + + virtual void clear_extended_stats(CPhyEthIF * _if); + + virtual int wait_for_stable_link(); +}; + +class CTRexExtendedDriverBase1GVm : public CTRexExtendedDriverBase { + +public: + CTRexExtendedDriverBase1GVm(){ + /* we are working in mode that we have 1 queue for rx and one queue for tx*/ + CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); + } + + static CTRexExtendedDriverBase * create(){ + return ( new CTRexExtendedDriverBase1GVm() ); + } + + virtual void update_global_config_fdir(port_cfg_t * cfg){ + + } + + virtual int get_min_sample_rate(void){ + return ( RX_CHECK_MIX_SAMPLE_RATE_1G); + } + virtual void update_configuration(port_cfg_t * cfg); + + virtual bool is_hardware_filter_is_supported(){ + return (true); + } + + virtual int configure_rx_filter_rules(CPhyEthIF * _if); + + virtual bool is_hardware_support_drop_queue(){ + return(false); + } + + virtual int configure_drop_queue(CPhyEthIF * _if); + + + virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats); + + virtual void clear_extended_stats(CPhyEthIF * _if); + + virtual int wait_for_stable_link(); +}; + + +class CTRexExtendedDriverBase10G : public CTRexExtendedDriverBase { +public: + CTRexExtendedDriverBase10G(){ + } + static CTRexExtendedDriverBase * create(){ + return ( new CTRexExtendedDriverBase10G() ); + } + + virtual void update_global_config_fdir(port_cfg_t * cfg); + + virtual int get_min_sample_rate(void){ + return (RX_CHECK_MIX_SAMPLE_RATE); + } + virtual void update_configuration(port_cfg_t * cfg); + + virtual bool is_hardware_filter_is_supported(){ + return (true); + } + + virtual int configure_rx_filter_rules(CPhyEthIF * _if); + + virtual bool is_hardware_support_drop_queue(){ + return(true); + } + virtual int configure_drop_queue(CPhyEthIF * _if); + + virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats); + virtual void clear_extended_stats(CPhyEthIF * _if); + virtual int wait_for_stable_link(); +}; + +class CTRexExtendedDriverBase40G : public CTRexExtendedDriverBase10G { +public: + CTRexExtendedDriverBase40G(){ + } + + static CTRexExtendedDriverBase * create(){ + return ( new CTRexExtendedDriverBase40G() ); + } + + 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 int configure_drop_queue(CPhyEthIF * _if); + + + + virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats); + virtual void clear_extended_stats(CPhyEthIF * _if); + virtual int wait_for_stable_link(); +private: + void add_rules(CPhyEthIF * _if, + enum rte_eth_flow_type type, + uint8_t ttl); +}; + +typedef CTRexExtendedDriverBase * (*create_object_t) (void); + + +class CTRexExtendedDriverRec { +public: + std::string m_driver_name; + create_object_t m_constructor; +}; + +class CTRexExtendedDriverDb { +public: + bool is_driver_exists(std::string name); + + + + void set_driver_name(std::string name){ + m_driver_was_set=true; + m_driver_name=name; + printf(" set driver name %s \n",name.c_str()); + m_drv=create_driver(m_driver_name); + assert(m_drv); + } + + CTRexExtendedDriverBase * get_drv(){ + if (!m_driver_was_set) { + printf(" ERROR too early to use this object !\n"); + printf(" need to set the right driver \n"); + assert(0); + } + assert(m_drv); + return (m_drv); + } + +public: + + static CTRexExtendedDriverDb * Ins(); + +private: + CTRexExtendedDriverBase * create_driver(std::string name); + + CTRexExtendedDriverDb(){ + register_driver(std::string("rte_ixgbe_pmd"),CTRexExtendedDriverBase10G::create); + register_driver(std::string("rte_igb_pmd"),CTRexExtendedDriverBase1G::create); + register_driver(std::string("rte_i40e_pmd"),CTRexExtendedDriverBase40G::create); + + /* virtual devices */ + register_driver(std::string("rte_em_pmd"),CTRexExtendedDriverBase1GVm::create); + register_driver(std::string("rte_vmxnet3_pmd"),CTRexExtendedDriverBase1GVm::create); + register_driver(std::string("rte_virtio_pmd"),CTRexExtendedDriverBase1GVm::create); + register_driver(std::string("rte_enic_pmd"),CTRexExtendedDriverBase1GVm::create); + + + + + m_driver_was_set=false; + m_drv=0; + m_driver_name=""; + } + void register_driver(std::string name,create_object_t func); + static CTRexExtendedDriverDb * m_ins; + bool m_driver_was_set; + std::string m_driver_name; + CTRexExtendedDriverBase * m_drv; + std::vector <CTRexExtendedDriverRec*> m_list; + +}; + +CTRexExtendedDriverDb * CTRexExtendedDriverDb::m_ins; + + +void CTRexExtendedDriverDb::register_driver(std::string name, + create_object_t func){ + CTRexExtendedDriverRec * rec; + rec = new CTRexExtendedDriverRec(); + rec->m_driver_name=name; + rec->m_constructor=func; + m_list.push_back(rec); +} + + +bool CTRexExtendedDriverDb::is_driver_exists(std::string name){ + int i; + for (i=0; i<(int)m_list.size(); i++) { + if (m_list[i]->m_driver_name == name) { + return (true); + } + } + return (false); +} + + +CTRexExtendedDriverBase * CTRexExtendedDriverDb::create_driver(std::string name){ + int i; + for (i=0; i<(int)m_list.size(); i++) { + if (m_list[i]->m_driver_name == name) { + return ( m_list[i]->m_constructor() ); + } + } + return( (CTRexExtendedDriverBase *)0); +} + + + +CTRexExtendedDriverDb * CTRexExtendedDriverDb::Ins(){ + if (!m_ins) { + m_ins = new CTRexExtendedDriverDb(); + } + return (m_ins); +} + +static CTRexExtendedDriverBase * get_ex_drv(){ + + return ( CTRexExtendedDriverDb::Ins()->get_drv()); +} + +static inline int get_min_sample_rate(void){ + return ( get_ex_drv()->get_min_sample_rate()); +} + + + + + + + +#define MAX_DPDK_ARGS 40 +static CPlatformYamlInfo global_platform_cfg_info; +static int global_dpdk_args_num ; +static char * global_dpdk_args[MAX_DPDK_ARGS]; +static char global_cores_str[100]; +static char global_prefix_str[100]; +static char global_loglevel_str[20]; + + + + +// cores =0==1,1*2,2,3,4,5,6 +// An enum for all the option types +enum { OPT_HELP, + OPT_CFG, + OPT_NODE_DUMP, + OPT_UT, + OPT_FILE_OUT, + OPT_REAL_TIME, + OPT_CORES, + OPT_SINGLE_CORE, + OPT_FLIP_CLIENT_SERVER, + OPT_FLOW_FLIP_CLIENT_SERVER, + OPT_FLOW_FLIP_CLIENT_SERVER_SIDE, + OPT_BW_FACTOR, + OPT_DURATION, + OPT_PLATFORM_FACTOR, + OPT_PUB_DISABLE, + OPT_LIMT_NUM_OF_PORTS, + OPT_PLAT_CFG_FILE, + + + OPT_LATENCY, + OPT_NO_CLEAN_FLOW_CLOSE, + OPT_LATENCY_MASK, + OPT_ONLY_LATENCY, + OPT_1G_MODE, + OPT_LATENCY_PREVIEW , + OPT_PCAP, + OPT_RX_CHECK, + OPT_IO_MODE, + OPT_IPV6, + OPT_LEARN, + OPT_LEARN_VERIFY, + OPT_NO_FLOW_CONTROL, + OPT_RX_CHECK_HOPS, + OPT_MAC_FILE, + OPT_NO_KEYBOARD_INPUT, + OPT_VLAN, + OPT_VIRT_ONE_TX_RX_QUEUE, + OPT_PREFIX, + OPT_MAC_SPLIT + +}; + + + + + +/* these are the argument types: + SO_NONE -- no argument needed + SO_REQ_SEP -- single required argument + SO_MULTI -- multiple arguments needed +*/ +static CSimpleOpt::SOption parser_options[] = +{ + { OPT_HELP, "-?", SO_NONE }, + { OPT_HELP, "-h", SO_NONE }, + { OPT_HELP, "--help", SO_NONE }, + { OPT_UT, "--ut", SO_NONE }, + { OPT_CFG, "-f", SO_REQ_SEP}, + { OPT_PLAT_CFG_FILE,"--cfg", SO_REQ_SEP}, + { OPT_REAL_TIME , "-r", SO_NONE }, + { OPT_SINGLE_CORE , "-s", SO_NONE }, + { OPT_FILE_OUT , "-o" , SO_REQ_SEP}, + { OPT_FLIP_CLIENT_SERVER,"--flip",SO_NONE }, + { OPT_FLOW_FLIP_CLIENT_SERVER,"-p",SO_NONE }, + { OPT_FLOW_FLIP_CLIENT_SERVER_SIDE,"-e",SO_NONE }, + + { OPT_NO_CLEAN_FLOW_CLOSE,"--nc",SO_NONE }, + + { OPT_LIMT_NUM_OF_PORTS,"--limit-ports", SO_REQ_SEP }, + { OPT_CORES , "-c", SO_REQ_SEP }, + { OPT_NODE_DUMP , "-v", SO_REQ_SEP }, + { OPT_LATENCY , "-l", SO_REQ_SEP }, + + { OPT_DURATION , "-d", SO_REQ_SEP }, + { OPT_PLATFORM_FACTOR , "-pm", SO_REQ_SEP }, + + { OPT_PUB_DISABLE , "-pubd", SO_NONE }, + + + { OPT_BW_FACTOR , "-m", SO_REQ_SEP }, + { OPT_LATENCY_MASK , "--lm", SO_REQ_SEP }, + { OPT_ONLY_LATENCY, "--lo", SO_NONE }, + + { OPT_1G_MODE, "-1g", SO_NONE }, + { OPT_LATENCY_PREVIEW , "-k", SO_REQ_SEP }, + { OPT_PCAP, "--pcap", SO_NONE }, + { OPT_RX_CHECK, "--rx-check", SO_REQ_SEP }, + { OPT_IO_MODE, "--iom", SO_REQ_SEP }, + { OPT_RX_CHECK_HOPS, "--hops", SO_REQ_SEP }, + { OPT_IPV6, "--ipv6", SO_NONE }, + { OPT_LEARN, "--learn", SO_NONE }, + { OPT_LEARN_VERIFY, "--learn-verify", SO_NONE }, + { OPT_NO_FLOW_CONTROL, "--no-flow-control", SO_NONE }, + { OPT_VLAN, "--vlan", SO_NONE }, + { OPT_MAC_FILE, "--mac", SO_REQ_SEP }, + { OPT_NO_KEYBOARD_INPUT ,"--no-key", SO_NONE }, + { OPT_VIRT_ONE_TX_RX_QUEUE, "--vm-sim", SO_NONE }, + { OPT_PREFIX, "--prefix", SO_REQ_SEP }, + { OPT_MAC_SPLIT, "--mac-spread", SO_REQ_SEP }, + + SO_END_OF_OPTIONS +}; + + + + +static int usage(){ + + printf(" Usage: t-rex-64 [OPTION] -f cfg.yaml -c cores \n"); + printf(" \n"); + printf(" \n"); + printf(" options \n"); + printf(" -f [file] : YAML file with template configuration \n"); + printf(" \n\n"); + printf(" --mac [file] : YAML file with <client ip, mac addr> configuration \n"); + printf(" \n\n"); + printf(" -r : realtime enable \n"); + printf(" \n\n"); + printf(" -c [number of cores] : 1 ,2,3,4,5 numnber of dual cores + master 1 means 1 master and 2 cores \n"); + printf(" \n"); + printf(" -s : run only one data path core\n"); + printf(" \n"); + printf(" --flip : flow will be sent from client->server and server->client for maximum throughput \n"); + printf(" \n"); + printf(" -p : flow-flip , send all packets flow from the same interface base of client ip \n"); + printf(" -e : like -p but comply to the generator rules \n"); + + printf(" \n"); + printf(" -l [pkt/sec] : run laterncy daemon in this rate \n"); + printf(" e.g -l 1000 run 1000 pkt/sec from each interface , zero mean to disable latency check \n"); + printf(" --lm : latency mask \n"); + printf(" 0x1 only port 0 will send traffic \n"); + printf(" --lo :only latency test \n"); + + printf(" \n"); + + printf(" --limit-ports : limit number of ports , must be even e.g 2,4 \n"); + printf(" \n"); + printf(" --nc : if set will not close all the flow , faster \n"); + printf(" \n"); + printf(" -d : duration of the test in sec \n"); + printf(" \n"); + printf(" -pm : platform factor , in case you have splitter in the setup you can multiply the total results in this factor \n"); + printf(" e.g --pm 2.0 will multiply all the results bps in this factor \n"); + printf(" \n"); + printf(" -pubd : disable monitors publishers \n"); + + printf(" -m : factor of bandwidth \n"); + printf(" \n"); + printf(" -1g : 1G trex \n"); + printf(" \n"); + printf(" -k [sec] : run latency test before starting the test. it will wait for x sec sending packet and x sec after that \n"); + printf(" \n"); + + printf(" --cfg [platform_yaml] : load and configure platform using this file see example in cfg/cfg_examplexx.yaml file \n"); + printf(" this file is used to configure/mask interfaces cores affinity and mac addr \n"); + printf(" you can copy this file to /etc/trex_cfg.yaml \n"); + printf(" \n"); + + printf(" --ipv6 : work in ipv6 mode \n"); + + printf(" --learn : Work in NAT environments, learn the dynamic NAT translation and ALG \n"); + printf(" --learn-verify : Learn the translation, but intended for verification of the mechanism in cases that NAT does not exist \n"); + printf(" \n"); + + printf(" -v [1-3] : verbose mode ( works only on the debug image ! ) \n"); + printf(" 1 show only stats \n"); + printf(" 2 run preview do not write to file \n"); + printf(" 3 run preview write stats file \n"); + printf(" Note in case of verbose mode you don't need to add the output file \n"); + printf(" \n"); + printf(" Warning : This program can generate huge-files (TB ) watch out! try this only on local drive \n"); + printf(" \n"); + printf(" \n"); + printf(" --rx-check [sample] : enable rx check thread , using this thread we sample flows 1/sample and check order,latency and more \n"); + printf(" this feature consume another thread \n"); + printf(" \n"); + printf(" --hops [hops] : If rx check is enabled, the hop number can be assigned. The default number of hops is 1\n"); + printf(" --iom [mode] : io mode for interactive mode [0- silent, 1- normal , 2- short] \n"); + printf(" this feature consume another thread \n"); + printf(" \n"); + printf(" --no-key : daemon mode, don't get input from keyboard \n"); + printf(" --no-flow-control : In default TRex disables flow-control using this flag it does not touch it \n"); + printf(" --prefix : for multi trex, each instance should have a different name \n"); + printf(" --mac-spread : Spread the destination mac-order by this factor. e.g 2 will generate the traffic to 2 devices DEST-MAC ,DEST-MAC+1 \n"); + printf(" maximum is up to 128 devices \n"); + + printf(" simulation mode : \n"); + printf(" Using this mode you can generate the traffic into a pcap file and learn how trex works \n"); + printf(" With this version you must be SUDO to use this mode ( I know this is not normal ) \n"); + printf(" you can use the Linux CEL version of t-rex to do it without super user \n"); + printf(" \n"); + printf(" -o [capfile_name] simulate trex into pcap file \n"); + printf(" --pcap export the file in pcap mode \n"); + printf(" t-rex-64 -d 10 -f cfg.yaml -o my.pcap --pcap # export 10 sec of what Trex will do on real-time to a file my.pcap \n"); + printf(" --vm-sim : simulate vm with driver of one input queue and one output queue \n"); + printf(" \n"); + printf(" Examples: "); + printf(" basic trex run for 10 sec and multiplier of x10 \n"); + printf(" #>t-rex-64 -f cfg.yaml -m 10 -d 10 \n"); + printf(" \n "); + + printf(" preview show csv stats \n"); + printf(" #>t-rex-64 -c 1 -f cfg.yaml -v 1 -p -m 10 -d 10 --nc -l 1000\n"); + printf(" \n "); + + printf(" 5) ! \n"); + printf(" #>t-rex-64 -f cfg.yaml -c 1 --flip \n"); + + printf("\n"); + printf("\n"); + printf(" Copyright (C) 2012 by hhaim Cisco-System POC for Israel dev-test \n"); + printf(" version : %s \n",VERSION); + + return (0); +} + + +int gtest_main(int argc, char **argv) ; + +static int parse_options(int argc, char *argv[], CParserOption* po, bool first_time ) { + CSimpleOpt args(argc, argv, parser_options); + + bool latency_was_set=false; + int a=0; + int node_dump=0; + + po->preview.setFileWrite(true); + po->preview.setRealTime(true); + int res1; + uint32_t tmp_data; + + + while ( args.Next() ){ + if (args.LastError() == SO_SUCCESS) { + switch (args.OptionId()) { + case OPT_UT : + printf(" Supported only in simulation \n"); + res1=0; + exit(res1); + break; + case OPT_HELP: + usage(); + return -1; + case OPT_CFG: + po->cfg_file = args.OptionArg(); + break; + case OPT_NO_KEYBOARD_INPUT : + po->preview.set_no_keyboard(true); + break; + case OPT_MAC_FILE : + po->mac_file = args.OptionArg(); + break; + case OPT_PLAT_CFG_FILE : + po->platform_cfg_file = args.OptionArg(); + break; + case OPT_SINGLE_CORE : + po->preview.setSingleCore(true); + break; + case OPT_IPV6: + po->preview.set_ipv6_mode_enable(true); + break; + case OPT_VLAN: + po->preview.set_vlan_mode_enable(true); + break; + + case OPT_LEARN : + po->preview.set_lean_mode_enable(true); + break; + + case OPT_LEARN_VERIFY : + po->preview.set_lean_mode_enable(true); + po->preview.set_lean_and_verify_mode_enable(true); + break; + + case OPT_REAL_TIME : + printf(" warning -r is deprecated, real time is not needed any more , it is the default \n"); + po->preview.setRealTime(true); + break; + case OPT_NO_FLOW_CONTROL: + po->preview.set_disable_flow_control_setting(true); + break; + + case OPT_LIMT_NUM_OF_PORTS : + po->m_expected_portd =atoi(args.OptionArg()); + break; + case OPT_CORES : + po->preview.setCores(atoi(args.OptionArg())); + break; + case OPT_FLIP_CLIENT_SERVER : + po->preview.setClientServerFlip(true); + break; + case OPT_NO_CLEAN_FLOW_CLOSE : + po->preview.setNoCleanFlowClose(true); + break; + case OPT_FLOW_FLIP_CLIENT_SERVER : + po->preview.setClientServerFlowFlip(true); + break; + case OPT_FLOW_FLIP_CLIENT_SERVER_SIDE: + po->preview.setClientServerFlowFlipAddr(true); + break; + case OPT_FILE_OUT: + po->out_file = args.OptionArg(); + break; + case OPT_NODE_DUMP: + a=atoi(args.OptionArg()); + node_dump=1; + po->preview.setFileWrite(false); + break; + case OPT_BW_FACTOR : + sscanf(args.OptionArg(),"%f", &po->m_factor); + break; + case OPT_DURATION : + sscanf(args.OptionArg(),"%f", &po->m_duration); + break; + case OPT_PUB_DISABLE: + po->preview.set_zmq_publish_enable(false); + break; + case OPT_PLATFORM_FACTOR: + sscanf(args.OptionArg(),"%f", &po->m_platform_factor); + break; + case OPT_LATENCY : + latency_was_set=true; + sscanf(args.OptionArg(),"%d", &po->m_latency_rate); + break; + case OPT_LATENCY_MASK : + sscanf(args.OptionArg(),"%x", &po->m_latency_mask); + break; + case OPT_ONLY_LATENCY : + po->preview.setOnlyLatency(true); + break; + case OPT_1G_MODE : + po->preview.set_1g_mode(true); + break; + + case OPT_LATENCY_PREVIEW : + sscanf(args.OptionArg(),"%d", &po->m_latency_prev); + break; + + case OPT_PCAP: + po->preview.set_pcap_mode_enable(true); + break; + + case OPT_RX_CHECK : + sscanf(args.OptionArg(),"%d", &tmp_data); + po->m_rx_check_sampe=(uint16_t)tmp_data; + po->preview.set_rx_check_enable(true); + break; + case OPT_RX_CHECK_HOPS : + sscanf(args.OptionArg(),"%d", &tmp_data); + po->m_rx_check_hops = (uint16_t)tmp_data; + break; + case OPT_IO_MODE : + sscanf(args.OptionArg(),"%d", &tmp_data); + po->m_io_mode=(uint16_t)tmp_data; + break; + + case OPT_VIRT_ONE_TX_RX_QUEUE: + po->preview.set_vm_one_queue_enable(true); + break; + + case OPT_PREFIX: + po->prefix = args.OptionArg(); + break; + + case OPT_MAC_SPLIT: + sscanf(args.OptionArg(),"%d", &tmp_data); + po->m_mac_splitter = (uint8_t)tmp_data; + po->preview.set_mac_ip_features_enable(true); + po->preview.setDestMacSplit(true); + break; + + default: + usage(); + return -1; + break; + } // End of switch + }// End of IF + else { + usage(); + return -1; + } + } // End of while + + + if ((po->cfg_file =="") ) { + printf("Invalid combination of parameters you must add -f with configuration file \n"); + return -1; + } + + if ( po->m_mac_splitter > 128 ){ + printf("maximum mac spreading is 128 you set it to %d \n",po->m_mac_splitter); + return -1; + } + + if ( po->preview.get_learn_mode_enable() ){ + if ( po->preview.get_ipv6_mode_enable() ){ + printf("--learn mode is not supported with --ipv6, beacuse there is not such thing NAT66 ( ipv6-ipv6) \n"); + printf("if you think it is important,open a defect \n"); + return -1; + } + if ( po->is_latency_disabled() ){ + /* set latency thread */ + po->m_latency_rate =1000; + } + } + + if (po->preview.get_is_rx_check_enable() && ( po->is_latency_disabled() ) ) { + printf(" rx check must be enable with latency check. try adding '-l 1000' \n"); + return -1; + } + + if ( node_dump ){ + po->preview.setVMode(a); + } + + /* if we have a platform factor we need to devided by it so we can still work with normalized yaml profile */ + po->m_factor = po->m_factor/po->m_platform_factor; + + uint32_t cores=po->preview.getCores(); + if ( cores > ((BP_MAX_CORES)/2-1) ) { + printf(" ERROR maximum cores are : %d \n",((BP_MAX_CORES)/2-1)); + return -1; + } + + + if ( first_time ){ + /* only first time read the configuration file */ + if ( po->platform_cfg_file.length() >0 ) { + if ( node_dump ){ + printf("load platform configuration file from %s \n",po->platform_cfg_file.c_str()); + } + global_platform_cfg_info.load_from_yaml_file(po->platform_cfg_file); + if ( node_dump ){ + global_platform_cfg_info.Dump(stdout); + } + }else{ + if ( utl_is_file_exists("/etc/trex_cfg.yaml") ){ + printf("found configuration file at /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); + } + } + } + } + + return 0; +} + + +int main_test(int argc , char * argv[]); + + + + +void delay(int msec){ + + if (msec == 0) + {//user that requested that probebly wanted the minimal delay + //but because of scaling problem he have got 0 so we will give the min delay + //printf("\n\n\nERROR-Task delay ticks == 0 found in task %s task id = %d\n\n\n\n", + // SANB_TaskName(SANB_TaskIdSelf()), SANB_TaskIdSelf()); + msec =1; + + } + + struct timespec time1, remain; // 2 sec max delay + time1.tv_sec=msec/1000; + time1.tv_nsec=(msec - (time1.tv_sec*1000))*1000000; + + nanosleep(&time1,&remain); +} + + + +static const char * default_argv[] = {"xx","-c", "0x7", "-n","2","-b","0000:0b:01.01"}; +static int argv_num = 7; + + + + + +#define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ +#define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */ +#define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */ + +/* + * These default values are optimized for use with the Intel(R) 82599 10 GbE + * Controller and the DPDK ixgbe PMD. Consider using other values for other + * network controllers and/or network drivers. + */ +#define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */ +#define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ +#define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ + +#define TX_WTHRESH_1G 1 /**< Default values of TX write-back threshold reg. */ +#define TX_PTHRESH_1G 1 /**< Default values of TX prefetch threshold reg. */ + + +struct port_cfg_t { + public: + port_cfg_t(){ + memset(&m_port_conf,0,sizeof(rte_eth_conf)); + memset(&m_rx_conf,0,sizeof(rte_eth_rxconf)); + memset(&m_tx_conf,0,sizeof(rte_eth_rxconf)); + memset(&m_rx_drop_conf,0,sizeof(rte_eth_rxconf)); + + + m_rx_conf.rx_thresh.pthresh = RX_PTHRESH; + m_rx_conf.rx_thresh.hthresh = RX_HTHRESH; + m_rx_conf.rx_thresh.wthresh = RX_WTHRESH; + m_rx_conf.rx_free_thresh =32; + + m_rx_drop_conf.rx_thresh.pthresh = 0; + m_rx_drop_conf.rx_thresh.hthresh = 0; + m_rx_drop_conf.rx_thresh.wthresh = 0; + m_rx_drop_conf.rx_free_thresh =32; + m_rx_drop_conf.rx_drop_en=1; + + m_tx_conf.tx_thresh.pthresh = TX_PTHRESH; + m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; + m_tx_conf.tx_thresh.wthresh = TX_WTHRESH; + + m_port_conf.rxmode.jumbo_frame=1; + m_port_conf.rxmode.max_rx_pkt_len =2000; + m_port_conf.rxmode.hw_strip_crc=1; + } + + + + inline void update_var(void){ + get_ex_drv()->update_configuration(this); + } + + inline void update_global_config_fdir(void){ + get_ex_drv()->update_global_config_fdir(this); + } + + /* enable FDIR */ + inline void update_global_config_fdir_10g_1g(void){ + m_port_conf.fdir_conf.mode=RTE_FDIR_MODE_PERFECT; + m_port_conf.fdir_conf.pballoc=RTE_FDIR_PBALLOC_64K; + m_port_conf.fdir_conf.status=RTE_FDIR_NO_REPORT_STATUS; + /* Offset of flexbytes field in RX packets (in 16-bit word units). */ + /* Note: divide by 2 to convert byte offset to word offset */ + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ){ + m_port_conf.fdir_conf.flexbytes_offset=(14+6)/2; + }else{ + m_port_conf.fdir_conf.flexbytes_offset=(14+8)/2; + } + + /* Increment offset 4 bytes for the case where we add VLAN */ + if ( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ){ + m_port_conf.fdir_conf.flexbytes_offset+=(4/2); + } + m_port_conf.fdir_conf.drop_queue=1; + } + + inline void update_global_config_fdir_40g(void){ + m_port_conf.fdir_conf.mode=RTE_FDIR_MODE_PERFECT; + m_port_conf.fdir_conf.pballoc=RTE_FDIR_PBALLOC_64K; + m_port_conf.fdir_conf.status=RTE_FDIR_NO_REPORT_STATUS; + /* Offset of flexbytes field in RX packets (in 16-bit word units). */ + /* Note: divide by 2 to convert byte offset to word offset */ + #if 0 + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ){ + m_port_conf.fdir_conf.flexbytes_offset=(14+6)/2; + }else{ + m_port_conf.fdir_conf.flexbytes_offset=(14+8)/2; + } + + /* Increment offset 4 bytes for the case where we add VLAN */ + if ( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ){ + m_port_conf.fdir_conf.flexbytes_offset+=(4/2); + } + #endif + + // TBD Flow Director does not work with XL710 yet we need to understand why + #if 0 + struct rte_eth_fdir_flex_conf * lp = &m_port_conf.fdir_conf.flex_conf; + + //lp->nb_flexmasks=1; + //lp->flex_mask[0].flow_type=RTE_ETH_FLOW_TYPE_SCTPV4; + //memset(lp->flex_mask[0].mask,0xff,RTE_ETH_FDIR_MAX_FLEXLEN); + + lp->nb_payloads=1; + lp->flex_set[0].type = RTE_ETH_L3_PAYLOAD; + lp->flex_set[0].src_offset[0]=8; + + //m_port_conf.fdir_conf.drop_queue=1; + #endif + } + + struct rte_eth_conf m_port_conf; + struct rte_eth_rxconf m_rx_conf; + struct rte_eth_rxconf m_rx_drop_conf; + struct rte_eth_txconf m_tx_conf; +}; + + +/* this object is per core / per port / per queue + each core will have 2 ports to send too + + + port0 port1 + + 0,1,2,3,..15 out queue ( per core ) 0,1,2,3,..15 out queue ( per core ) + +*/ + + +typedef struct cnt_name_ { + uint32_t offset; + char * name; +}cnt_name_t ; + +#define MY_REG(a) {a,(char *)#a} + + +class CPhyEthIFStats { + +public: + uint64_t ipackets; /**< Total number of successfully received packets. */ + uint64_t ibytes; /**< Total number of successfully received bytes. */ + + uint64_t f_ipackets; /**< Total number of successfully received packets - filter SCTP*/ + uint64_t f_ibytes; /**< Total number of successfully received bytes. - filter SCTP */ + + uint64_t opackets; /**< Total number of successfully transmitted packets.*/ + uint64_t obytes; /**< Total number of successfully transmitted bytes. */ + + uint64_t ierrors; /**< Total number of erroneous received packets. */ + uint64_t oerrors; /**< Total number of failed transmitted packets. */ + uint64_t imcasts; /**< Total number of multicast received packets. */ + uint64_t rx_nombuf; /**< Total number of RX mbuf allocation failures. */ + + +public: + void Clear(); + void Dump(FILE *fd); + void DumpAll(FILE *fd); +}; + +void CPhyEthIFStats::Clear(){ + + ipackets =0; + ibytes =0 ; + + f_ipackets=0; + f_ibytes=0; + + opackets=0; + obytes=0; + + ierrors=0; + oerrors=0; + imcasts=0; + rx_nombuf=0; +} + + +void CPhyEthIFStats::DumpAll(FILE *fd){ + + #define DP_A4(f) printf(" %-40s : %llu \n",#f,f) + #define DP_A(f) if (f) printf(" %-40s : %llu \n",#f,f) + DP_A4(opackets); + DP_A4(obytes); + DP_A4(ipackets); + DP_A4(ibytes); + DP_A(ierrors); + DP_A(oerrors); + +} + + +void CPhyEthIFStats::Dump(FILE *fd){ + + DP_A(opackets); + DP_A(obytes); + + DP_A(f_ipackets); + DP_A(f_ibytes); + + DP_A(ipackets); + DP_A(ibytes); + DP_A(ierrors); + DP_A(oerrors); + DP_A(imcasts); + DP_A(rx_nombuf); +} + + + +class CPhyEthIF { +public: + CPhyEthIF (){ + m_port_id=0; + m_rx_queue=0; + } + bool Create(uint8_t portid){ + m_port_id = portid; + m_last_rx_rate = 0.0; + m_last_tx_rate = 0.0; + m_last_pps=0.0; + return (true); + } + void Delete(); + + void set_rx_queue(uint8_t rx_queue){ + m_rx_queue=rx_queue; + } + + + void configure(uint16_t nb_rx_queue, + uint16_t nb_tx_queue, + const struct rte_eth_conf *eth_conf); + + void macaddr_get(struct ether_addr *mac_addr); + + void get_stats(CPhyEthIFStats *stats); + + void get_stats_1g(CPhyEthIFStats *stats); + + + void rx_queue_setup(uint16_t rx_queue_id, + uint16_t nb_rx_desc, + unsigned int socket_id, + const struct rte_eth_rxconf *rx_conf, + struct rte_mempool *mb_pool); + + void tx_queue_setup(uint16_t tx_queue_id, + uint16_t nb_tx_desc, + unsigned int socket_id, + const struct rte_eth_txconf *tx_conf); + + void configure_rx_drop_queue(); + + void configure_rx_duplicate_rules(); + + void start(); + + void stop(); + + void update_link_status(); + + bool is_link_up(){ + return (m_link.link_status?true:false); + } + + void dump_link(FILE *fd); + + void disable_flow_control(); + + void set_promiscuous(bool enable); + + void add_mac(char * mac); + + + bool get_promiscuous(); + + void dump_stats(FILE *fd); + + void update_counters(); + + + void stats_clear(); + + uint8_t get_port_id(){ + return (m_port_id); + } + + float get_last_tx_rate(){ + return (m_last_tx_rate); + } + + float get_last_rx_rate(){ + return (m_last_rx_rate); + } + + float get_last_pps_rate(){ + return (m_last_pps); + } + + CPhyEthIFStats & get_stats(){ + return ( m_stats ); + } + + void flush_rx_queue(void); + +public: + + inline uint16_t tx_burst(uint16_t queue_id, + struct rte_mbuf **tx_pkts, + uint16_t nb_pkts); + + inline uint16_t rx_burst(uint16_t queue_id, + struct rte_mbuf **rx_pkts, + uint16_t nb_pkts); + + + inline uint32_t pci_reg_read(uint32_t reg_off){ + void *reg_addr; + uint32_t reg_v; + reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr + + reg_off); + reg_v = *((volatile uint32_t *)reg_addr); + return rte_le_to_cpu_32(reg_v); + } + + + inline void pci_reg_write(uint32_t reg_off, + uint32_t reg_v){ + void *reg_addr; + + reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr + + reg_off); + *((volatile uint32_t *)reg_addr) = rte_cpu_to_le_32(reg_v); + } + + void dump_stats_extended(FILE *fd); + + uint8_t get_rte_port_id(void){ + return ( m_port_id ); + } +private: + uint8_t m_port_id; + uint8_t m_rx_queue; + struct rte_eth_link m_link; + uint64_t m_sw_try_tx_pkt; + uint64_t m_sw_tx_drop_pkt; + CBwMeasure m_bw_tx; + CBwMeasure m_bw_rx; + CPPSMeasure m_pps_tx; + + CPhyEthIFStats m_stats; + + float m_last_rx_rate; + float m_last_tx_rate; + float m_last_pps; +public: + struct rte_eth_dev_info m_dev_info; +}; + + +void CPhyEthIF::flush_rx_queue(void){ + + rte_mbuf_t * rx_pkts[32]; + int j=0; + uint16_t cnt=0; + + while (true) { + j++; + cnt = rx_burst(m_rx_queue,rx_pkts,32); + if ( cnt ) { + int i; + for (i=0; i<(int)cnt;i++) { + rte_mbuf_t * m=rx_pkts[i]; + /*printf("rx--\n"); + rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m));*/ + rte_pktmbuf_free(m); + } + } + if ( ((cnt==0) && (j>10)) || (j>15) ) { + break; + } + } + if (cnt>0) { + printf(" Warning can't flush rx-queue for port %d \n",(int)get_port_id()); + } +} + + +void CPhyEthIF::dump_stats_extended(FILE *fd){ + + cnt_name_t reg[]={ + MY_REG(IXGBE_GPTC), /* total packet */ + MY_REG(IXGBE_GOTCL), /* total bytes */ + MY_REG(IXGBE_GOTCH), + + MY_REG(IXGBE_GPRC), + MY_REG(IXGBE_GORCL), + MY_REG(IXGBE_GORCH), + + + + MY_REG(IXGBE_RXNFGPC), + MY_REG(IXGBE_RXNFGBCL), + MY_REG(IXGBE_RXNFGBCH), + MY_REG(IXGBE_RXDGPC ), + MY_REG(IXGBE_RXDGBCL ), + MY_REG(IXGBE_RXDGBCH ), + MY_REG(IXGBE_RXDDGPC ), + MY_REG(IXGBE_RXDDGBCL ), + MY_REG(IXGBE_RXDDGBCH ), + MY_REG(IXGBE_RXLPBKGPC ), + MY_REG(IXGBE_RXLPBKGBCL), + MY_REG(IXGBE_RXLPBKGBCH ), + MY_REG(IXGBE_RXDLPBKGPC ), + MY_REG(IXGBE_RXDLPBKGBCL), + MY_REG(IXGBE_RXDLPBKGBCH ), + MY_REG(IXGBE_TXDGPC ), + MY_REG(IXGBE_TXDGBCL ), + MY_REG(IXGBE_TXDGBCH ), + MY_REG(IXGBE_FDIRUSTAT ), + MY_REG(IXGBE_FDIRFSTAT ), + MY_REG(IXGBE_FDIRMATCH ), + MY_REG(IXGBE_FDIRMISS ) + + }; + fprintf (fd," externded counter \n"); + int i; + for (i=0; i<sizeof(reg)/sizeof(reg[0]); i++) { + cnt_name_t *lp=®[i]; + uint32_t c=pci_reg_read(lp->offset); + if (c) { + fprintf (fd," %s : %d \n",lp->name,c); + } + } +} + + + +void CPhyEthIF::configure(uint16_t nb_rx_queue, + uint16_t nb_tx_queue, + const struct rte_eth_conf *eth_conf){ + int ret; + ret = rte_eth_dev_configure(m_port_id, + nb_rx_queue, + nb_tx_queue, + eth_conf); + + if (ret < 0) + rte_exit(EXIT_FAILURE, "Cannot configure device: " + "err=%d, port=%u\n", + ret, m_port_id); + + /* get device info */ + rte_eth_dev_info_get(m_port_id, &m_dev_info); + +} + + +/* + +rx-queue 0 - default- all traffic no SCTP + will be drop as queue is disable + + +rx-queue 1 - SCTP traffic will go to here + + pci_reg_write(IXGBE_L34T_IMIR(0),(1<<21)); + +*/ + +void CPhyEthIF::configure_rx_duplicate_rules(){ + + if ( get_is_rx_filter_enable() ){ + + if ( get_ex_drv()->is_hardware_filter_is_supported()==false ){ + printf(" ERROR this feature is not supported with current hardware \n"); + exit(1); + } + get_ex_drv()->configure_rx_filter_rules(this); + } +} + + +void CPhyEthIF::configure_rx_drop_queue(){ + + if ( get_vm_one_queue_enable() ) { + return; + } + if ( CGlobalInfo::m_options.is_latency_disabled()==false ) { + if ( (!get_ex_drv()->is_hardware_support_drop_queue()) ) { + printf(" ERROR latency feature is not supported with current hardware \n"); + exit(1); + } + } + get_ex_drv()->configure_drop_queue(this); +} + + +void CPhyEthIF::rx_queue_setup(uint16_t rx_queue_id, + uint16_t nb_rx_desc, + unsigned int socket_id, + const struct rte_eth_rxconf *rx_conf, + struct rte_mempool *mb_pool){ + + int ret = rte_eth_rx_queue_setup(m_port_id , rx_queue_id, + nb_rx_desc, + socket_id, + rx_conf, + mb_pool); + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: " + "err=%d, port=%u\n", + ret, m_port_id); +} + + + +void CPhyEthIF::tx_queue_setup(uint16_t tx_queue_id, + uint16_t nb_tx_desc, + unsigned int socket_id, + const struct rte_eth_txconf *tx_conf){ + + int ret = rte_eth_tx_queue_setup( m_port_id, + tx_queue_id, + nb_tx_desc, + socket_id, + tx_conf); + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: " + "err=%d, port=%u queue=%u\n", + ret, m_port_id, tx_queue_id); + +} + + +void CPhyEthIF::stop(){ + rte_eth_dev_stop(m_port_id); +} + + +void CPhyEthIF::start(){ + + get_ex_drv()->clear_extended_stats(this); + + int ret; + + m_bw_tx.reset(); + m_bw_rx.reset(); + + m_stats.Clear(); + int i; + for (i=0;i<10; i++ ) { + ret = rte_eth_dev_start(m_port_id); + if (ret==0) { + return; + } + delay(1000); + } + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_dev_start: " + "err=%d, port=%u\n", + ret, m_port_id); + +} + +void CPhyEthIF::disable_flow_control(){ + if ( get_vm_one_queue_enable() ){ + return; + } + int ret; + if ( !CGlobalInfo::m_options.preview.get_is_disable_flow_control_setting() ){ + // see trex-64 issue with loopback on the same NIC + struct rte_eth_fc_conf fc_conf; + memset(&fc_conf,0,sizeof(fc_conf)); + fc_conf.mode=RTE_FC_NONE; + fc_conf.autoneg=1; + fc_conf.pause_time=100; + int i; + for (i=0; i<5; i++) { + ret=rte_eth_dev_flow_ctrl_set(m_port_id,&fc_conf); + if (ret==0) { + break; + } + delay(1000); + } + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_dev_flow_ctrl_set: " + "err=%d, port=%u\n probably link is down please check you link activity or enable flow-control using this CLI flag --no-flow-control \n", + ret, m_port_id); + } +} + + + +void CPhyEthIF::dump_link(FILE *fd){ + fprintf(fd,"port : %d \n",(int)m_port_id); + fprintf(fd,"------------\n"); + + fprintf(fd,"link : "); + if (m_link.link_status) { + fprintf(fd," link : Link Up - speed %u Mbps - %s\n", + (unsigned) m_link.link_speed, + (m_link.link_duplex == ETH_LINK_FULL_DUPLEX) ? + ("full-duplex") : ("half-duplex\n")); + } else { + fprintf(fd," Link Down\n"); + } + fprintf(fd,"promiscuous : %d \n",get_promiscuous()); +} + +void CPhyEthIF::update_link_status(){ + rte_eth_link_get(m_port_id, &m_link); +} + +void CPhyEthIF::add_mac(char * mac){ + struct ether_addr mac_addr; + int i=0; + for (i=0; i<6;i++) { + mac_addr.addr_bytes[i] =mac[i]; + } + rte_eth_dev_mac_addr_add(m_port_id, &mac_addr,0); +} + +void CPhyEthIF::set_promiscuous(bool enable){ + if (enable) { + rte_eth_promiscuous_enable(m_port_id); + }else{ + rte_eth_promiscuous_disable(m_port_id); + } +} + +bool CPhyEthIF::get_promiscuous(){ + int ret=rte_eth_promiscuous_get(m_port_id); + if (ret<0) { + rte_exit(EXIT_FAILURE, "rte_eth_promiscuous_get: " + "err=%d, port=%u\n", + ret, m_port_id); + + } + return ( ret?true:false); +} + + +void CPhyEthIF::macaddr_get(struct ether_addr *mac_addr){ + rte_eth_macaddr_get(m_port_id , mac_addr); +} + +void CPhyEthIF::get_stats_1g(CPhyEthIFStats *stats){ + + int i; + uint64_t t=0; + + + stats->ipackets += pci_reg_read(E1000_GPRC) ; + + stats->ibytes += (pci_reg_read(E1000_GORCL) ); + stats->ibytes += (((uint64_t)pci_reg_read(E1000_GORCH))<<32); + + + stats->opackets += pci_reg_read(E1000_GPTC); + stats->obytes += pci_reg_read(E1000_GOTCL) ; + stats->obytes += ( (((uint64_t)pci_reg_read(IXGBE_GOTCH))<<32) ); + + stats->f_ipackets += 0; + stats->f_ibytes += 0; + + + stats->ierrors += ( pci_reg_read(E1000_RNBC) + + pci_reg_read(E1000_CRCERRS) + + pci_reg_read(E1000_ALGNERRC ) + + pci_reg_read(E1000_SYMERRS ) + + pci_reg_read(E1000_RXERRC ) + + + pci_reg_read(E1000_ROC)+ + pci_reg_read(E1000_RUC)+ + pci_reg_read(E1000_RJC) + + + pci_reg_read(E1000_XONRXC)+ + pci_reg_read(E1000_XONTXC)+ + pci_reg_read(E1000_XOFFRXC)+ + pci_reg_read(E1000_XOFFTXC)+ + pci_reg_read(E1000_FCRUC) + ); + + stats->oerrors += 0; + stats->imcasts = 0; + stats->rx_nombuf = 0; + + m_last_tx_rate = m_bw_tx.add(stats->obytes); + m_last_rx_rate = m_bw_rx.add(stats->ibytes); + m_last_pps = m_pps_tx.add(stats->opackets); + +} + +void CPhyEthIF::get_stats(CPhyEthIFStats *stats){ + + get_ex_drv()->get_extended_stats(this,stats); + + m_last_tx_rate = m_bw_tx.add(stats->obytes); + m_last_rx_rate = m_bw_rx.add(stats->ibytes); + m_last_pps = m_pps_tx.add(stats->opackets); +} + + +void dump_hw_state(FILE *fd,struct ixgbe_hw_stats *hs ){ + + #define DP_A1(f) if (hs->f) fprintf(fd," %-40s : %llu \n",#f,hs->f) + #define DP_A2(f,m) for (i=0;i<m; i++) { if (hs->f[i]) fprintf(fd," %-40s[%d] : %llu \n",#f,i,hs->f[i]); } + int i; + + //for (i=0;i<8; i++) { if (hs->mpc[i]) fprintf(fd," %-40s[%d] : %llu \n","mpc",i,hs->mpc[i]); } + DP_A2(mpc,8); + DP_A1(crcerrs); + DP_A1(illerrc); + //DP_A1(errbc); + DP_A1(mspdc); + DP_A1(mpctotal); + DP_A1(mlfc); + DP_A1(mrfc); + DP_A1(rlec); + //DP_A1(lxontxc); + //DP_A1(lxonrxc); + //DP_A1(lxofftxc); + //DP_A1(lxoffrxc); + //DP_A2(pxontxc,8); + //DP_A2(pxonrxc,8); + //DP_A2(pxofftxc,8); + //DP_A2(pxoffrxc,8); + + //DP_A1(prc64); + //DP_A1(prc127); + //DP_A1(prc255); + // DP_A1(prc511); + //DP_A1(prc1023); + //DP_A1(prc1522); + + DP_A1(gprc); + DP_A1(bprc); + DP_A1(mprc); + DP_A1(gptc); + DP_A1(gorc); + DP_A1(gotc); + DP_A2(rnbc,8); + DP_A1(ruc); + DP_A1(rfc); + DP_A1(roc); + DP_A1(rjc); + DP_A1(mngprc); + DP_A1(mngpdc); + DP_A1(mngptc); + DP_A1(tor); + DP_A1(tpr); + DP_A1(tpt); + DP_A1(ptc64); + DP_A1(ptc127); + DP_A1(ptc255); + DP_A1(ptc511); + DP_A1(ptc1023); + DP_A1(ptc1522); + DP_A1(mptc); + DP_A1(bptc); + DP_A1(xec); + DP_A2(qprc,16) + DP_A2(qptc,16); + DP_A2(qbrc,16); + DP_A2(qbtc,16); + DP_A2(qprdc,16); + DP_A2(pxon2offc,8); + DP_A1(fdirustat_add); + DP_A1(fdirustat_remove); + DP_A1(fdirfstat_fadd); + DP_A1(fdirfstat_fremove); + DP_A1(fdirmatch); + DP_A1(fdirmiss); + DP_A1(fccrc); + DP_A1(fclast); + DP_A1(fcoerpdc); + DP_A1(fcoeprc); + DP_A1(fcoeptc); + DP_A1(fcoedwrc); + DP_A1(fcoedwtc); + DP_A1(fcoe_noddp); + DP_A1(fcoe_noddp_ext_buff); + DP_A1(ldpcec); + DP_A1(pcrc8ec); + DP_A1(b2ospc); + DP_A1(b2ogprc); + DP_A1(o2bgptc); + DP_A1(o2bspc); +} + + +void CPhyEthIF::update_counters(){ + get_stats(&m_stats); +} + +void CPhyEthIF::dump_stats(FILE *fd){ + + update_counters(); + + fprintf(fd,"port : %d \n",(int)m_port_id); + fprintf(fd,"------------\n"); + m_stats.DumpAll(fd); + //m_stats.Dump(fd); + printf (" Tx : %.1fMb/sec \n",m_last_tx_rate); + //printf (" Rx : %.1fMb/sec \n",m_last_rx_rate); +} + +void CPhyEthIF::stats_clear(){ + rte_eth_stats_reset(m_port_id); + m_stats.Clear(); +} + +inline uint16_t CPhyEthIF::tx_burst(uint16_t queue_id, + struct rte_mbuf **tx_pkts, + uint16_t nb_pkts){ + uint16_t ret = rte_eth_tx_burst(m_port_id, queue_id, tx_pkts, nb_pkts); + return (ret); +} + + +inline uint16_t CPhyEthIF::rx_burst(uint16_t queue_id, + struct rte_mbuf **rx_pkts, + uint16_t nb_pkts){ + return (rte_eth_rx_burst(m_port_id, queue_id, + rx_pkts, nb_pkts)); + +} + + + + +class CCorePerPort { +public: + CCorePerPort (){ + m_tx_queue_id=0; + m_len=0; + int i; + for (i=0; i<MAX_PKT_BURST; i++) { + m_table[i]=0; + } + m_port=0; + } + uint16_t m_tx_queue_id; + uint16_t m_len; + rte_mbuf_t * m_table[MAX_PKT_BURST]; + CPhyEthIF * m_port; +}; + + +#define MAX_MBUF_CACHE 100 + + +/* per core/gbe queue port for trasmitt */ +class CCoreEthIF : public CVirtualIF { + +public: + + CCoreEthIF(){ + m_mbuf_cache=0; + } + +public: + bool Create(uint8_t core_id, + uint16_t tx_client_queue_id, + CPhyEthIF * tx_client_port, + + uint16_t tx_server_queue_id, + CPhyEthIF * tx_server_port); + void Delete(); + + virtual int open_file(std::string file_name){ + return (0); + } + + virtual int close_file(void){ + return (flush_tx_queue()); + } + + 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 flush_rx_queue(); + __attribute__ ((noinline)) void update_mac_addr(CGenNode * node,uint8_t *p); + + bool process_rx_pkt(pkt_dir_t dir,rte_mbuf_t * m); + + +public: + void GetCoreCounters(CVirtualIFPerSideStats *stats); + void DumpCoreStats(FILE *fd); + void DumpIfStats(FILE *fd); + static void DumpIfCfgHeader(FILE *fd); + void DumpIfCfg(FILE *fd); + + socket_id_t get_socket_id(){ + return ( CGlobalInfo::m_socket.port_to_socket( m_ports[0].m_port->get_port_id() ) ); + } + +private: + + int send_burst(CCorePerPort * lp_port, + uint16_t len, + CVirtualIFPerSideStats * lp_stats); + int send_pkt(CCorePerPort * lp_port, + rte_mbuf_t *m, + CVirtualIFPerSideStats * lp_stats); + + + +private: + uint8_t m_core_id; + uint16_t m_mbuf_cache; + CCorePerPort m_ports[CS_NUM]; /* each core has 2 tx queues 1. client side and server side */ + CNodeRing * m_ring_to_rx; +}; + +bool CCoreEthIF::Create(uint8_t core_id, + uint16_t tx_client_queue_id, + CPhyEthIF * tx_client_port, + + uint16_t tx_server_queue_id, + CPhyEthIF * tx_server_port){ + m_ports[CLIENT_SIDE].m_tx_queue_id = tx_client_queue_id; + m_ports[CLIENT_SIDE].m_port = tx_client_port; + + m_ports[SERVER_SIDE].m_tx_queue_id = tx_server_queue_id; + m_ports[SERVER_SIDE].m_port = tx_server_port; + m_core_id = core_id; + + CMessagingManager * rx_dp=CMsgIns::Ins()->getRxDp(); + m_ring_to_rx = rx_dp->getRingDpToCp(core_id-1); + assert( m_ring_to_rx); + return (true); +} + +bool CCoreEthIF::process_rx_pkt(pkt_dir_t dir, + rte_mbuf_t * m){ + + CSimplePacketParser parser(m); + if ( !parser.Parse() ){ + return false; + } + bool send=false; + if ( parser.IsLatencyPkt() ){ + send=true; + + }else{ + if ( get_is_rx_filter_enable() ){ + uint8_t max_ttl = 0xff - get_rx_check_hops(); + uint8_t pkt_ttl = parser.getTTl(); + if ( (pkt_ttl==max_ttl) || (pkt_ttl==(max_ttl-1) ) ) { + send=true; + } + } + } + + + if (send) { + CGenNodeLatencyPktInfo * node=(CGenNodeLatencyPktInfo * )CGlobalInfo::create_node(); + if ( node ) { + node->m_msg_type = CGenNodeMsgBase::LATENCY_PKT; + node->m_dir = dir; + node->m_latency_offset = 0xdead; + node->m_pkt = m; + if ( m_ring_to_rx->Enqueue((CGenNode*)node)==0 ){ + }else{ + CGlobalInfo::free_node((CGenNode *)node); + send=false; + } + + #ifdef LATENCY_QUEUE_TRACE_ + printf("rx to cp --\n"); + rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m)); + #endif + }else{ + send=false; + } + } + return (send); +} + + + +void CCoreEthIF::flush_rx_queue(void){ + pkt_dir_t dir ; + bool is_latency=get_is_latency_thread_enable(); + 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_latency ){ + 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 ; + for (dir=CLIENT_SIDE; dir<CS_NUM; dir++) { + CCorePerPort * lp_port=&m_ports[dir]; + CVirtualIFPerSideStats * lp_stats= &m_stats[dir]; + if ( likely(lp_port->m_len > 0) ) { + send_burst(lp_port,lp_port->m_len,lp_stats); + lp_port->m_len = 0; + } + } + + if ( unlikely( get_vm_one_queue_enable() ) ){ + /* try drain the rx packets */ + flush_rx_queue(); + } + return (0); +} + + +void CCoreEthIF::GetCoreCounters(CVirtualIFPerSideStats *stats){ + stats->Clear(); + pkt_dir_t dir ; + for (dir=CLIENT_SIDE; dir<CS_NUM; dir++) { + stats->Add(&m_stats[dir]); + } +} + +void CCoreEthIF::DumpCoreStats(FILE *fd){ + fprintf (fd,"------------------------ \n"); + fprintf (fd," per core stats core id : %d \n",m_core_id); + fprintf (fd,"------------------------ \n"); + + CVirtualIFPerSideStats stats; + GetCoreCounters(&stats); + stats.Dump(stdout); +} + +void CCoreEthIF::DumpIfCfgHeader(FILE *fd){ + fprintf (fd," core , c-port, c-queue , s-port, s-queue \n"); + fprintf (fd," ------------------------------------------\n"); +} + +void CCoreEthIF::DumpIfCfg(FILE *fd){ + fprintf (fd," %d, %u , %u , %u , %u \n",m_core_id, + m_ports[CLIENT_SIDE].m_port->get_port_id(), + m_ports[CLIENT_SIDE].m_tx_queue_id, + m_ports[SERVER_SIDE].m_port->get_port_id(), + m_ports[SERVER_SIDE].m_tx_queue_id + ); +} + + +void CCoreEthIF::DumpIfStats(FILE *fd){ + + fprintf (fd,"------------------------ \n"); + fprintf (fd," per core per if stats id : %d \n",m_core_id); + fprintf (fd,"------------------------ \n"); + + const char * t[]={"client","server"}; + pkt_dir_t dir ; + for (dir=CLIENT_SIDE; dir<CS_NUM; dir++) { + CCorePerPort * lp=&m_ports[dir]; + CVirtualIFPerSideStats * lpstats = &m_stats[dir]; + fprintf (fd," port %d, queue id :%d - %s \n",lp->m_port->get_port_id(),lp->m_tx_queue_id,t[dir] ); + fprintf (fd," ---------------------------- \n"); + lpstats->Dump(fd); + } +} + +#define DELAY_IF_NEEDED + +int CCoreEthIF::send_burst(CCorePerPort * lp_port, + uint16_t len, + CVirtualIFPerSideStats * lp_stats){ + + uint16_t ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id,lp_port->m_table,len); + #ifdef DELAY_IF_NEEDED + while ( unlikely( ret<len ) ){ + rte_delay_us(1); + //rte_pause(); + //rte_pause(); + lp_stats->m_tx_queue_full += 1; + uint16_t ret1=lp_port->m_port->tx_burst(lp_port->m_tx_queue_id, + &lp_port->m_table[ret], + len-ret); + ret+=ret1; + } + #endif + + /* CPU has burst of packets , more that TX can send need to drop them !!*/ + if ( unlikely(ret < len) ) { + lp_stats->m_tx_drop += (len-ret); + uint16_t i; + for (i=ret; i<len;i++) { + rte_mbuf_t * m=lp_port->m_table[i]; + rte_pktmbuf_free(m); + } + } +} + + +int CCoreEthIF::send_pkt(CCorePerPort * lp_port, + rte_mbuf_t *m, + CVirtualIFPerSideStats * lp_stats + ){ + + lp_stats->m_tx_pkt +=1; + lp_stats->m_tx_bytes += (rte_pktmbuf_pkt_len(m)+4); + + uint16_t len = lp_port->m_len; + lp_port->m_table[len]=m; + len++; + /* enough pkts to be sent */ + if (unlikely(len == MAX_PKT_BURST)) { + send_burst(lp_port, MAX_PKT_BURST,lp_stats); + len = 0; + } + lp_port->m_len = len; +} + + + +void CCoreEthIF::send_one_pkt(pkt_dir_t dir, + rte_mbuf_t *m){ + CCorePerPort * lp_port=&m_ports[dir]; + CVirtualIFPerSideStats * lp_stats = &m_stats[dir]; + send_pkt(lp_port,m,lp_stats); + /* flush */ + send_burst(lp_port,lp_port->m_len,lp_stats); + lp_port->m_len = 0; +} + + +void CCoreEthIF::update_mac_addr(CGenNode * node,uint8_t *p){ + + if ( CGlobalInfo::m_options.preview.getDestMacSplit() ) { + p[5]+= (node->m_src_ip % CGlobalInfo::m_options.m_mac_splitter); + } + + if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_mapping_enable() ) ) { + /* mac mapping file is configured + */ + if (node->m_src_mac.inused==INUSED) { + memcpy(p+6, &node->m_src_mac.mac, sizeof(uint8_t)*6); + } + } else if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_overide_enable() ) ){ + /* client side */ + if ( node->is_initiator_pkt() ){ + *((uint32_t*)(p+6))=PKT_NTOHL(node->m_src_ip); + } + } +} + + +int CCoreEthIF::send_node(CGenNode * node){ + + if ( unlikely( node->get_cache_mbuf() !=NULL ) ) { + pkt_dir_t dir; + rte_mbuf_t * m=node->get_cache_mbuf(); + dir=(pkt_dir_t)node->get_mbuf_cache_dir(); + CCorePerPort * lp_port=&m_ports[dir]; + CVirtualIFPerSideStats * lp_stats = &m_stats[dir]; + rte_pktmbuf_refcnt_update(m,1); + send_pkt(lp_port,m,lp_stats); + return (0); + } + + + CFlowPktInfo * lp=node->m_pkt_info; + rte_mbuf_t * m=lp->generate_new_mbuf(node); + + pkt_dir_t dir; + bool single_port; + + dir = node->cur_interface_dir(); + single_port = node->get_is_all_flow_from_same_dir() ; + + if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){ + /* which vlan to choose 0 or 1*/ + uint8_t vlan_port = (node->m_src_ip &1); + + /* set the vlan */ + m->ol_flags = PKT_TX_VLAN_PKT; + m->l2_len =14; + uint16_t vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port]; + + + if (likely( vlan_id >0 ) ) { + m->vlan_tci = vlan_id; + dir = dir ^ vlan_port; + }else{ + /* both from the same dir but with VLAN0 */ + m->vlan_tci = CGlobalInfo::m_options.m_vlan_port[0]; + dir = dir ^ 0; + } + } + + CCorePerPort * lp_port=&m_ports[dir]; + CVirtualIFPerSideStats * lp_stats = &m_stats[dir]; + + if (unlikely(m==0)) { + lp_stats->m_tx_alloc_error++; + return(0); + } + + /* update mac addr dest/src 12 bytes */ + uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); + uint8_t p_id=lp_port->m_port->get_port_id(); + + + memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12); + + /* if customer enables both mac_file and get_mac_ip_overide, + * we will apply mac_file. + */ + if ( unlikely(CGlobalInfo::m_options.preview.get_mac_ip_features_enable() ) ) { + update_mac_addr(node,p); + } + + if ( unlikely( node->is_rx_check_enabled() ) ) { + lp_stats->m_tx_rx_check_pkt++; + lp->do_generate_new_mbuf_rxcheck(m,node,dir,single_port); + lp_stats->m_template.inc_template( node->get_template_id( )); + }else{ + // cache only if it is not sample as this is more complex mbuf struct + if ( unlikely( node->can_cache_mbuf() ) ) { + if ( !CGlobalInfo::m_options.preview.isMbufCacheDisabled() ){ + m_mbuf_cache++; + if (m_mbuf_cache < MAX_MBUF_CACHE) { + /* limit the number of object to cache */ + node->set_mbuf_cache_dir( dir); + node->set_cache_mbuf(m); + rte_pktmbuf_refcnt_update(m,1); + } + } + } + } + + /*printf("send packet -- \n"); + rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m));*/ + + /* send the packet */ + send_pkt(lp_port,m,lp_stats); + return (0); +} + + + +class CLatencyHWPort : public CPortLatencyHWBase { +public: + void Create(CPhyEthIF * p, + uint8_t tx_queue, + uint8_t rx_queue){ + m_port=p; + m_tx_queue_id=tx_queue; + m_rx_queue_id=rx_queue; + } + + virtual int tx(rte_mbuf_t * m){ + rte_mbuf_t * tx_pkts[2]; + tx_pkts[0]=m; + if ( likely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){ + /* vlan mode is the default */ + /* set the vlan */ + m->ol_flags = PKT_TX_VLAN_PKT; + m->vlan_tci =CGlobalInfo::m_options.m_vlan_port[0]; + m->l2_len =14; + } + uint16_t res=m_port->tx_burst(m_tx_queue_id,tx_pkts,1); + if ( res == 0 ) { + rte_pktmbuf_free(m); + //printf(" queue is full for latency packet !!\n"); + return (-1); + + } + #if 0 + fprintf(stdout," ==> %f.03 send packet ..\n",now_sec()); + uint8_t *p1=rte_pktmbuf_mtod(m, uint8_t*); + uint16_t pkt_size1=rte_pktmbuf_pkt_len(m); + utl_DumpBuffer(stdout,p1,pkt_size1,0); + #endif + + return (0); + } + virtual rte_mbuf_t * rx(){ + rte_mbuf_t * rx_pkts[1]; + uint16_t cnt=m_port->rx_burst(m_rx_queue_id,rx_pkts,1); + if (cnt) { + return (rx_pkts[0]); + }else{ + return (0); + } + } + + virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, + uint16_t nb_pkts){ + uint16_t cnt=m_port->rx_burst(m_rx_queue_id,rx_pkts,nb_pkts); + return (cnt); + } + + +private: + CPhyEthIF * m_port; + uint8_t m_tx_queue_id ; + uint8_t m_rx_queue_id; +}; + + +class CLatencyVmPort : public CPortLatencyHWBase { +public: + void Create(uint8_t port_index,CNodeRing * ring, + CLatencyManager * mgr){ + m_dir = (port_index%2); + m_ring_to_dp = ring; + m_mgr = mgr; + } + + virtual int tx(rte_mbuf_t * m){ + if ( likely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){ + /* vlan mode is the default */ + /* set the vlan */ + m->ol_flags = PKT_TX_VLAN_PKT; + m->vlan_tci =CGlobalInfo::m_options.m_vlan_port[0]; + m->l2_len =14; + } + + /* allocate node */ + CGenNodeLatencyPktInfo * node=(CGenNodeLatencyPktInfo * )CGlobalInfo::create_node(); + if ( node ) { + node->m_msg_type = CGenNodeMsgBase::LATENCY_PKT; + node->m_dir = m_dir; + node->m_pkt = m; + node->m_latency_offset = m_mgr->get_latency_header_offset(); + + if ( m_ring_to_dp->Enqueue((CGenNode*)node) ==0 ){ + return (0); + } + } + return (-1); + } + + virtual rte_mbuf_t * rx(){ + return (0); + } + + virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, + uint16_t nb_pkts){ + return (0); + } + + +private: + uint8_t m_dir; + CNodeRing * m_ring_to_dp; /* ring dp -> latency thread */ + CLatencyManager * m_mgr; +}; + + +class CZMqPublisher { +public: + CZMqPublisher(){ + m_context=0; + m_publisher=0; + } + + bool Create(uint16_t port,bool disable); + void Delete(); + void publish_json(std::string & s); +private: + void show_zmq_last_error(char *s); +private: + void * m_context; + void * m_publisher; +}; + +void CZMqPublisher::show_zmq_last_error(char *s){ + printf(" ERROR %s \n",s); + printf(" ZMQ: %s",zmq_strerror (zmq_errno ())); + exit(-1); +} + + +bool CZMqPublisher::Create(uint16_t port,bool disable){ + + if (disable) { + return(true); + } + m_context = zmq_ctx_new (); + if ( m_context == 0 ) { + show_zmq_last_error((char *)"can't connect to ZMQ library"); + } + m_publisher = zmq_socket (m_context, ZMQ_PUB); + if ( m_context == 0 ) { + show_zmq_last_error((char *)"can't create ZMQ socket"); + } + char buffer[100]; + sprintf(buffer,"tcp://*:%d",port); + int rc=zmq_bind (m_publisher, buffer); + if (rc != 0 ) { + sprintf(buffer,"can't bind to ZMQ socket %d",port); + show_zmq_last_error(buffer); + } + printf("zmq publisher at: %s \n",buffer); + return (true); +} + + +void CZMqPublisher::Delete(){ + if (m_publisher) { + zmq_close (m_publisher); + } + if (m_context) { + zmq_ctx_destroy (m_context); + } +} + + +void CZMqPublisher::publish_json(std::string & s){ + if ( m_publisher ){ + int size = zmq_send (m_publisher, s.c_str(), s.length(), 0); + assert(size==s.length()); + } +} + +class CPerPortStats { +public: + uint64_t opackets; + uint64_t obytes; + uint64_t ipackets; + uint64_t ibytes; + uint64_t ierrors; + uint64_t oerrors; + + float m_total_tx_bps; +}; + +class CGlobalStats { +public: + enum DumpFormat { + dmpSTANDARD, + dmpTABLE + }; + + uint64_t m_total_tx_pkts; + uint64_t m_total_rx_pkts; + uint64_t m_total_tx_bytes; + uint64_t m_total_rx_bytes; + + uint64_t m_total_alloc_error; + uint64_t m_total_queue_full; + uint64_t m_total_queue_drop; + + uint64_t m_total_clients; + uint64_t m_total_servers; + uint64_t m_active_sockets; + + uint64_t m_total_nat_time_out; + uint64_t m_total_nat_no_fid ; + uint64_t m_total_nat_active ; + uint64_t m_total_nat_open ; + uint64_t m_total_nat_learn_error ; + + CPerTxthreadTemplateInfo m_template; + + float m_socket_util; + + float m_platform_factor; + float m_tx_bps; + float m_rx_bps; + float m_tx_pps; + float m_tx_cps; + float m_tx_expected_cps; + float m_tx_expected_pps; + float m_tx_expected_bps; + float m_rx_drop_bps; + float m_active_flows; + float m_open_flows; + float m_cpu_util; + uint8_t m_threads; + + uint32_t m_num_of_ports; + CPerPortStats m_port[BP_MAX_PORTS]; +public: + void Dump(FILE *fd,DumpFormat mode); + void DumpAllPorts(FILE *fd); + void dump_json(std::string & json); +private: + std::string get_field(std::string name,float &f); + std::string get_field(std::string name,uint64_t &f); + std::string get_field_port(int port,std::string name,float &f); + std::string get_field_port(int port,std::string name,uint64_t &f); + +}; + +std::string CGlobalStats::get_field(std::string name,float &f){ + char buff[200]; + sprintf(buff,"\"%s\":%.1f,",name.c_str(),f); + return (std::string(buff)); +} + +std::string CGlobalStats::get_field(std::string name,uint64_t &f){ + char buff[200]; + sprintf(buff,"\"%s\":%llu,",name.c_str(),f); + return (std::string(buff)); +} + +std::string CGlobalStats::get_field_port(int port,std::string name,float &f){ + char buff[200]; + sprintf(buff,"\"%s-%d\":%.1f,",name.c_str(),port,f); + return (std::string(buff)); +} + +std::string CGlobalStats::get_field_port(int port,std::string name,uint64_t &f){ + char buff[200]; + sprintf(buff,"\"%s-%d\":%llu,",name.c_str(),port,f); + return (std::string(buff)); +} + + +void CGlobalStats::dump_json(std::string & json){ + json="{\"name\":\"trex-global\",\"type\":0,\"data\":{"; + + #define GET_FIELD(f) get_field(std::string(#f),f) + #define GET_FIELD_PORT(p,f) get_field_port(p,std::string(#f),lp->f) + + json+=GET_FIELD(m_cpu_util); + json+=GET_FIELD(m_platform_factor); + json+=GET_FIELD(m_tx_bps); + json+=GET_FIELD(m_rx_bps); + json+=GET_FIELD(m_tx_pps); + json+=GET_FIELD(m_tx_cps); + json+=GET_FIELD(m_tx_expected_cps); + json+=GET_FIELD(m_tx_expected_pps); + json+=GET_FIELD(m_tx_expected_bps); + json+=GET_FIELD(m_rx_drop_bps); + json+=GET_FIELD(m_active_flows); + json+=GET_FIELD(m_open_flows); + + json+=GET_FIELD(m_total_tx_pkts); + json+=GET_FIELD(m_total_rx_pkts); + json+=GET_FIELD(m_total_tx_bytes); + json+=GET_FIELD(m_total_rx_bytes); + + json+=GET_FIELD(m_total_clients); + json+=GET_FIELD(m_total_servers); + json+=GET_FIELD(m_active_sockets); + json+=GET_FIELD(m_socket_util); + + json+=GET_FIELD(m_total_nat_time_out); + json+=GET_FIELD(m_total_nat_no_fid ); + json+=GET_FIELD(m_total_nat_active ); + json+=GET_FIELD(m_total_nat_open ); + json+=GET_FIELD(m_total_nat_learn_error); + + int i; + for (i=0; i<(int)m_num_of_ports; i++) { + CPerPortStats * lp=&m_port[i]; + json+=GET_FIELD_PORT(i,opackets) ; + json+=GET_FIELD_PORT(i,obytes) ; + json+=GET_FIELD_PORT(i,ipackets) ; + json+=GET_FIELD_PORT(i,ibytes) ; + json+=GET_FIELD_PORT(i,ierrors) ; + json+=GET_FIELD_PORT(i,oerrors) ; + json+=GET_FIELD_PORT(i,m_total_tx_bps); + } + json+=m_template.dump_as_json("template"); + json+="\"unknown\":0}}" ; +} + +void CGlobalStats::DumpAllPorts(FILE *fd){ + + //fprintf (fd," Total-Tx-Pkts : %s \n",double_to_human_str((double)m_total_tx_pkts,"pkts",KBYE_1000).c_str()); + //fprintf (fd," Total-Rx-Pkts : %s \n",double_to_human_str((double)m_total_rx_pkts,"pkts",KBYE_1000).c_str()); + + //fprintf (fd," Total-Tx-Bytes : %s \n",double_to_human_str((double)m_total_tx_bytes,"bytes",KBYE_1000).c_str()); + //fprintf (fd," Total-Rx-Bytes : %s \n",double_to_human_str((double)m_total_rx_bytes,"bytes",KBYE_1000).c_str()); + + + + fprintf (fd," Cpu Utilization : %2.1f %% %2.1f Gb/core \n",m_cpu_util,(2*(m_tx_bps/1e9)*100.0/(m_cpu_util*m_threads))); + fprintf (fd," Platform_factor : %2.1f \n",m_platform_factor); + fprintf (fd," Total-Tx : %s ",double_to_human_str(m_tx_bps,"bps",KBYE_1000).c_str()); + if ( CGlobalInfo::is_learn_mode() ) { + fprintf (fd," Nat_time_out : %8llu \n",m_total_nat_time_out); + }else{ + fprintf (fd,"\n"); + } + + + fprintf (fd," Total-Rx : %s ",double_to_human_str(m_rx_bps,"bps",KBYE_1000).c_str()); + if ( CGlobalInfo::is_learn_mode() ) { + fprintf (fd," Nat_no_fid : %8llu \n",m_total_nat_no_fid); + }else{ + fprintf (fd,"\n"); + } + + fprintf (fd," Total-PPS : %s ",double_to_human_str(m_tx_pps,"pps",KBYE_1000).c_str()); + if ( CGlobalInfo::is_learn_mode() ) { + fprintf (fd," Total_nat_active: %8llu \n",m_total_nat_active); + }else{ + fprintf (fd,"\n"); + } + + fprintf (fd," Total-CPS : %s ",double_to_human_str(m_tx_cps,"cps",KBYE_1000).c_str()); + if ( CGlobalInfo::is_learn_mode() ) { + fprintf (fd," Total_nat_open : %8llu \n",m_total_nat_open); + }else{ + fprintf (fd,"\n"); + } + fprintf (fd,"\n"); + fprintf (fd," Expected-PPS : %s ",double_to_human_str(m_tx_expected_pps,"pps",KBYE_1000).c_str()); + if ( CGlobalInfo::is_learn_verify_mode() ) { + fprintf (fd," Nat_learn_errors: %8llu \n",m_total_nat_learn_error); + }else{ + fprintf (fd,"\n"); + } + fprintf (fd," Expected-CPS : %s \n",double_to_human_str(m_tx_expected_cps,"cps",KBYE_1000).c_str()); + fprintf (fd," Expected-BPS : %s \n",double_to_human_str(m_tx_expected_bps,"bps",KBYE_1000).c_str()); + fprintf (fd,"\n"); + fprintf (fd," Active-flows : %8llu Clients : %8llu Socket-util : %3.4f %% \n",(uint64_t)m_active_flows,m_total_clients,m_socket_util); + fprintf (fd," Open-flows : %8llu Servers : %8llu Socket : %8llu Socket/Clients : %.1f \n", + (uint64_t)m_open_flows, + m_total_servers, + m_active_sockets, + (float)m_active_sockets/(float)m_total_clients); + + if (m_total_alloc_error) { + fprintf (fd," Total_alloc_err : %llu \n",(uint64_t)m_total_alloc_error); + } + if ( m_total_queue_full ){ + fprintf (fd," Total_queue_full : %llu \n",(uint64_t)m_total_queue_full); + } + if (m_total_queue_drop) { + fprintf (fd," Total_queue_drop : %llu \n",(uint64_t)m_total_queue_drop); + } + + //m_template.Dump(fd); + + fprintf (fd," drop-rate : %s \n",double_to_human_str(m_rx_drop_bps,"bps",KBYE_1000).c_str() ); +} + + +void CGlobalStats::Dump(FILE *fd,DumpFormat mode){ + int i; + int port_to_show=m_num_of_ports; + if (port_to_show>4) { + port_to_show=4; + fprintf (fd," per port - limited to 4 \n"); + } + + + if ( mode== dmpSTANDARD ){ + 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"); + #define GS_DP_A4(f) fprintf(fd," %-40s : %llu \n",#f,lp->f) + #define GS_DP_A(f) if (lp->f) fprintf(fd," %-40s : %llu \n",#f,lp->f) + GS_DP_A4(opackets); + GS_DP_A4(obytes); + GS_DP_A4(ipackets); + GS_DP_A4(ibytes); + GS_DP_A(ierrors); + GS_DP_A(oerrors); + fprintf (fd," Tx : %s \n",double_to_human_str((double)lp->m_total_tx_bps,"bps",KBYE_1000).c_str()); + } + }else{ + fprintf(fd," %10s ","ports"); + for (i=0; i<(int)port_to_show; i++) { + fprintf(fd,"| %15d ",i); + } + fprintf(fd,"\n"); + fprintf(fd," -----------------------------------------------------------------------------------------\n"); + std::string names[]={"opackets","obytes","ipackets","ibytes","ierrors","oerrors","Tx Bw" + }; + for (i=0; i<7; i++) { + fprintf(fd," %10s ",names[i].c_str()); + int j=0; + for (j=0; j<port_to_show;j++) { + CPerPortStats * lp=&m_port[j]; + uint64_t cnt; + switch (i) { + case 0: + cnt=lp->opackets; + fprintf(fd,"| %15lu ",cnt); + + break; + case 1: + cnt=lp->obytes; + fprintf(fd,"| %15lu ",cnt); + + break; + case 2: + cnt=lp->ipackets; + fprintf(fd,"| %15lu ",cnt); + + break; + case 3: + cnt=lp->ibytes; + fprintf(fd,"| %15lu ",cnt); + + break; + case 4: + cnt=lp->ierrors; + fprintf(fd,"| %15lu ",cnt); + + break; + case 5: + cnt=lp->oerrors; + fprintf(fd,"| %15lu ",cnt); + + break; + case 6: + fprintf(fd,"| %15s ",double_to_human_str((double)lp->m_total_tx_bps,"bps",KBYE_1000).c_str()); + break; + default: + cnt=0xffffff; + } + } /* ports */ + fprintf(fd, "\n"); + }/* fields*/ + } + + +} + + + + + + + +struct CGlobalPortCfg { + +public: + CGlobalPortCfg (){ + m_max_ports=4; + m_max_cores=1; + m_cores_to_dual_ports=0; + m_max_queues_per_port=0; + m_test =NULL; + m_fl_was_init=false; + m_expected_pps=0.0; + m_expected_cps=0.0; + m_expected_bps=0.0; + } +public: + + bool Create(); + void Delete(); + + int ixgbe_prob_init(); + int cores_prob_init(); + int queues_prob_init(); + int ixgbe_start(); + int ixgbe_rx_queue_flush(); + int ixgbe_configure_mg(); + + + bool is_all_links_are_up(bool dump=false); + int set_promisc_all(bool enable); + + int reset_counters(); + + +public: + int start_send_master(); + int run_in_core(virtual_thread_id_t virt_core_id); + int stop_core(virtual_thread_id_t virt_core_id); + + int core_for_latency(){ + if ( (!get_is_latency_thread_enable()) ){ + return (-1); + }else{ + return ( m_max_cores - 1 ); + } + + } + + int run_in_laterncy_core(); + + int run_in_master(); + int stop_master(); + + + /* return the minimum number of dp cores need to support the active ports + this is for c==1 or m_cores_mul==1 + */ + int get_base_num_cores(){ + return (m_max_ports>>1); + } + + int get_cores_tx(){ + /* 0 - master + num_of_cores - + + + last for latency */ + if ( (!get_is_latency_thread_enable()) ){ + return (m_max_cores - 1 ); + }else{ + return (m_max_cores - BP_MASTER_AND_LATENCY ); + } + } + + + + +public: + int test_send(); + + + + int test_send1(); + int rcv_send(int port,int queue_id); + int rcv_send_all(int queue_id); + +private: + bool is_all_cores_finished(); + + int test_send_pkts(uint16_t queue_id, + int pkt, + int port); + + + int create_pkt(uint8_t *pkt,int pkt_size); + int create_udp_pkt(); + int create_sctp_pkt(); + + + +public: + void dump_stats(FILE *fd, + std::string & json,CGlobalStats::DumpFormat format); + + void dump_template_info(std::string & json); + + bool sanity_check(); + + void update_stats(void); + void get_stats(CGlobalStats & stats); + + + void dump_post_test_stats(FILE *fd); + + void dump_config(FILE *fd); + +public: + port_cfg_t m_port_cfg; + + /* + exaple1 : + req=4 ,m_max_ports =4 ,c=1 , l=1 + + ==> + m_max_cores = 4/2+1+1 =4; + m_cores_mul = 1 + + + */ + + 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; + + // statistic + CPPSMeasure m_cps; + float m_expected_pps; + float m_expected_cps; + float m_expected_bps;//bps + float m_last_total_cps; + + + + CPhyEthIF m_ports[BP_MAX_PORTS]; + CCoreEthIF m_cores_vif[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserve*/ + + + CParserOption m_po ; + CFlowGenList m_fl; + bool m_fl_was_init; + + volatile uint8_t m_signal[BP_MAX_CORES] __rte_cache_aligned ; + + CLatencyManager m_mg; + CTrexGlobalIoMode m_io_modes; + +private: + +private: + rte_mbuf_t * m_test; + uint64_t m_test_drop; + + CLatencyHWPort m_latency_vports[BP_MAX_PORTS]; /* read hardware driver */ + CLatencyVmPort m_latency_vm_vports[BP_MAX_PORTS]; /* vm driver */ + + CLatencyPktInfo m_latency_pkt; + CZMqPublisher m_zmq_publisher; +}; + + + +int CGlobalPortCfg::test_send1(){ + + CParserOption po ; + CFlowGenList fl; + + po.cfg_file = "cap2/dns.yaml"; + //po.cfg_file = "cap2/sfr3.yaml"; + //po.cfg_file = "cap2/sfr4.yaml"; + //po.cfg_file = "cap2/sfr.yaml"; + + po.preview.setVMode(3); + po.preview.setFileWrite(true); + + fl.Create(); + + fl.load_from_yaml(po.cfg_file,1); + //fl.DumpPktSize(); + + fl.generate_p_thread_info(1); + CFlowGenListPerThread * lpt; + + int i; + for (i=0; i<1; i++) { + lpt = fl.m_threads_info[i]; + //CNullIF * erf_vif = new CNullIF(); + CVirtualIF * erf_vif = &m_cores_vif[0]; + lpt->set_vif(erf_vif); + lpt->generate_erf("hey",po.preview); + lpt->m_node_gen.DumpHist(stdout); + lpt->DumpStats(stdout); + } + + m_cores_vif[0].flush_tx_queue(); + delay(1000); + //fprintf(stdout," drop : %llu \n",m_test_drop); + + m_cores_vif[0].DumpCoreStats(stdout); + m_cores_vif[0].DumpIfStats(stdout); + + fl.Delete(); +} + + +int CGlobalPortCfg::rcv_send(int port,int queue_id){ + + CPhyEthIF * lp=&m_ports[port]; + rte_mbuf_t * rx_pkts[32]; + printf(" test rx port:%d queue:%d \n",port,queue_id); + printf(" --------------\n"); + uint16_t cnt=lp->rx_burst(queue_id,rx_pkts,32); + + int i; + for (i=0; i<(int)cnt;i++) { + rte_mbuf_t * m=rx_pkts[i]; + int pkt_size=rte_pktmbuf_pkt_len(m); + char *p=rte_pktmbuf_mtod(m, char*); + utl_DumpBuffer(stdout,p,pkt_size,0); + rte_pktmbuf_free(m); + } + return (0); +} + +int CGlobalPortCfg::rcv_send_all(int queue_id){ + int i; + for (i=0; i<m_max_ports; i++) { + rcv_send(i,queue_id); + } + return (0); +} + + + + +int CGlobalPortCfg::test_send(){ + int i; + + CPhyEthIF * lp=&m_ports[0]; + + //set_promisc_all(true); + //create_sctp_pkt(); + create_udp_pkt(); + + CRx_check_header rx_check_header; + rx_check_header.m_time_stamp=0x1234567; + rx_check_header.m_option_type=RX_CHECK_V4_OPT_TYPE; + rx_check_header.m_option_len=RX_CHECK_V4_OPT_LEN; + rx_check_header.m_magic=2; + rx_check_header.m_pkt_id=7; + rx_check_header.m_flow_id=9; + rx_check_header.m_flags=11; + + + assert(m_test); + for (i=0; i<1; i++) { + //test_send_pkts(0,1,0); + //test_send_pkts(m_latency_tx_queue_id,12,0); + //test_send_pkts(m_latency_tx_queue_id,1,1); + //test_send_pkts(m_latency_tx_queue_id,1,2); + //test_send_pkts(m_latency_tx_queue_id,1,3); + test_send_pkts(0,1,0); + test_send_pkts(0,1,1); + //test_send_pkts(2,1,0); + + + //test_send_pkts(0,1,1); + //test_send_pkts(0,1,2); + //test_send_pkts(0,1,3); + + /*test_send_pkts(2,1,0); + test_send_pkts(2,1,1); + test_send_pkts(2,1,2); + test_send_pkts(2,1,3);*/ + + /*delay(1000); + fprintf(stdout," --------------------------------\n"); + fprintf(stdout," after sending to port %d \n",i); + fprintf(stdout," --------------------------------\n"); + dump_stats(stdout); + fprintf(stdout," --------------------------------\n");*/ + } + //test_send_pkts(m_latency_tx_queue_id,1,1); + //test_send_pkts(m_latency_tx_queue_id,1,2); + //test_send_pkts(m_latency_tx_queue_id,1,3); + + + printf(" ---------\n"); + printf(" rx queue 0 \n"); + printf(" ---------\n"); + rcv_send_all(0); + printf("\n\n"); + + printf(" ---------\n"); + printf(" rx queue 1 \n"); + printf(" ---------\n"); + rcv_send_all(1); + printf(" ---------\n"); + + delay(1000); + + #if 1 + int j=0; + for (j=0; j<m_max_ports; j++) { + CPhyEthIF * lp=&m_ports[j]; + printf(" port : %d \n",j); + printf(" ----------\n"); + + lp->update_counters(); + lp->get_stats().Dump(stdout); + lp->dump_stats_extended(stdout); + } + /*for (j=0; j<4; j++) { + CPhyEthIF * lp=&m_ports[j]; + lp->dump_stats_extended(stdout); + }*/ + #endif + + fprintf(stdout," drop : %llu \n",m_test_drop); + return (0); +} + + + +const uint8_t udp_pkt[]={ + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x08,0x00, + + 0x45,0x00,0x00,0x81, + 0xaf,0x7e,0x00,0x00, + 0x12,0x11,0xd9,0x23, + 0x01,0x01,0x01,0x01, + 0x3d,0xad,0x72,0x1b, + + 0x11,0x11, + 0x11,0x11, + + 0x00,0x6d, + 0x00,0x00, + + 0x64,0x31,0x3a,0x61, + 0x64,0x32,0x3a,0x69,0x64, + 0x32,0x30,0x3a,0xd0,0x0e, + 0xa1,0x4b,0x7b,0xbd,0xbd, + 0x16,0xc6,0xdb,0xc4,0xbb,0x43, + 0xf9,0x4b,0x51,0x68,0x33,0x72, + 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, + 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, + 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, + 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, + 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, + 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, + 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, + 0xe7 +}; + + +const uint8_t sctp_pkt1[]={ + + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x08,0x00, + + 0x45,0x02,0x00,0x30, + 0x00,0x00,0x40,0x00, + 0x40,0x84,0xbd,0x04, + 0x01,0x01,0x01,0x01, //sIP + 0x02,0x02,0x02,0x02, //DIP + + 0x80,0x44,//SPORT + 0x00,0x50,//DPORT + + 0x00,0x00,0x00,0x00, //checksum + + 0x11,0x22,0x33,0x44, // magic + 0x00,0x00,0x00,0x00, //64 bit counter + 0x00,0x00,0x00,0x00, + 0x00,0x01,0xa0,0x00, //seq + 0x00,0x00,0x00,0x00, + +}; + + + + + +int CGlobalPortCfg::create_pkt(uint8_t *pkt,int pkt_size){ + rte_mempool_t * mp= CGlobalInfo::m_mem_pool[0].m_big_mbuf_pool ; + + rte_mbuf_t * m=rte_pktmbuf_alloc(mp); + if ( unlikely(m==0) ) { + printf("ERROR no packets \n"); + return (0); + } + char *p=rte_pktmbuf_append(m, pkt_size); + assert(p); + /* set pkt data */ + memcpy(p,pkt,pkt_size); + //m->ol_flags = PKT_TX_VLAN_PKT; + //m->pkt.vlan_tci =200; + + m_test = m; + + return (0); +} + +int CGlobalPortCfg::create_udp_pkt(){ + return (create_pkt((uint8_t*)udp_pkt,sizeof(udp_pkt))); +} + +int CGlobalPortCfg::create_sctp_pkt(){ + return (create_pkt((uint8_t*)sctp_pkt1,sizeof(sctp_pkt1))); +} + + +/* test by sending 10 packets ...*/ +int CGlobalPortCfg::test_send_pkts(uint16_t queue_id, + int pkt, + int port){ + + CPhyEthIF * lp=&m_ports[port]; + rte_mbuf_t * tx_pkts[32]; + if (pkt >32 ) { + pkt =32; + } + + int i; + for (i=0; i<pkt; i++) { + rte_mbuf_refcnt_update(m_test,1); + tx_pkts[i]=m_test; + } + uint16_t res=lp->tx_burst(queue_id,tx_pkts,pkt); + if ((pkt-res)>0) { + m_test_drop+=(pkt-res); + } + return (0); +} + + + + + +int CGlobalPortCfg::set_promisc_all(bool enable){ + int i; + for (i=0; i<m_max_ports; i++) { + CPhyEthIF * _if=&m_ports[i]; + _if->set_promiscuous(enable); + } +} + + + +int CGlobalPortCfg::reset_counters(){ + int i; + for (i=0; i<m_max_ports; i++) { + CPhyEthIF * _if=&m_ports[i]; + _if->stats_clear(); + } +} + + +bool CGlobalPortCfg::is_all_links_are_up(bool dump){ + bool all_link_are=true; + int i; + for (i=0; i<m_max_ports; i++) { + CPhyEthIF * _if=&m_ports[i]; + _if->update_link_status(); + if ( dump ){ + _if->dump_stats(stdout); + } + if ( _if->is_link_up() == false){ + all_link_are=false; + break; + } + } + return (all_link_are); +} + + + +int CGlobalPortCfg::ixgbe_rx_queue_flush(){ + int i; + for (i=0; i<m_max_ports; i++) { + CPhyEthIF * _if=&m_ports[i]; + _if->flush_rx_queue(); + } + return (0); +} + + +int CGlobalPortCfg::ixgbe_configure_mg(void){ + int i; + CLatencyManagerCfg mg_cfg; + mg_cfg.m_max_ports = m_max_ports; + + uint32_t latency_rate=CGlobalInfo::m_options.m_latency_rate; + + if ( latency_rate ) { + mg_cfg.m_cps = (double)latency_rate ; + }else{ + mg_cfg.m_cps = 100.0; + } + + if ( get_vm_one_queue_enable() ) { + /* vm mode, indirect queues */ + for (i=0; i<m_max_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); + + mg_cfg.m_ports[i] =&m_latency_vm_vports[i]; + } + + }else{ + 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); + + mg_cfg.m_ports[i] =&m_latency_vports[i]; + } + } + + + m_mg.Create(&mg_cfg); + m_mg.set_mask(CGlobalInfo::m_options.m_latency_mask); +} + + +int CGlobalPortCfg::ixgbe_start(void){ + int i; + for (i=0; i<m_max_ports; i++) { + + 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 */ + _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_big_mbuf_pool); + + + + _if->set_rx_queue(0); + _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_big_mbuf_pool); + + 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); + + } + + }else{ + _if->configure(2, + m_cores_to_dual_ports+1, + &m_port_cfg.m_port_conf); + + /* the latency queue for SCTP */ + 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_big_mbuf_pool); + + + /* 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_big_mbuf_pool); + + + /* set the filter queue */ + _if->set_rx_queue(1); + /* sctp ring is 1 */ + _if->rx_queue_setup(1, + RTE_TEST_RX_LATENCY_DESC_DEFAULT, + socket_id, + &m_port_cfg.m_rx_conf, + CGlobalInfo::m_mem_pool[socket_id].m_big_mbuf_pool); + + int qid; + for ( qid=0; qid<(m_max_queues_per_port+1); qid++) { + _if->tx_queue_setup((uint16_t)qid, + RTE_TEST_TX_DESC_DEFAULT , + socket_id, + &m_port_cfg.m_tx_conf); + + } + + } + + + _if->stats_clear(); + + _if->start(); + _if->configure_rx_drop_queue(); + _if->configure_rx_duplicate_rules(); + + _if->disable_flow_control(); + + _if->update_link_status(); + + _if->dump_link(stdout); + + _if->add_mac((char *)CGlobalInfo::m_options.get_src_mac_addr(i)); + + fflush(stdout); + } + + if ( !is_all_links_are_up() ){ + /* wait for ports to be stable */ + get_ex_drv()->wait_for_stable_link(); + + if ( !is_all_links_are_up(true) ){ + rte_exit(EXIT_FAILURE, " " + " one of the link is down \n"); + } + } + + ixgbe_rx_queue_flush(); + + + ixgbe_configure_mg(); + + + /* core 0 - control + core 1 - port 0-0,1-0, + core 2 - port 2-0,3-0, + core 3 - port 0-1,1-1, + core 4 - port 2-1,3-1, + + */ + int port_offset=0; + int queue_offset=0; + for (i=0; i<get_cores_tx(); i++) { + int j=(i+1); + int queue_id=((j-1)/get_base_num_cores() ); /* for the first min core queue 0 , then queue 1 etc */ + m_cores_vif[j].Create(j, + queue_id, + &m_ports[port_offset], /* 0,2*/ + queue_id, + &m_ports[port_offset+1] /*1,3*/ + ); + port_offset+=2; + if (port_offset == m_max_ports) { + port_offset = 0; + } + } + + fprintf(stdout," -------------------------------\n"); + CCoreEthIF::DumpIfCfgHeader(stdout); + for (i=0; i<get_cores_tx(); i++) { + m_cores_vif[i+1].DumpIfCfg(stdout); + } + fprintf(stdout," -------------------------------\n"); +} + + +bool CGlobalPortCfg::Create(){ + + if ( !m_zmq_publisher.Create( CGlobalInfo::m_options.m_zmq_port, + !CGlobalInfo::m_options.preview.get_zmq_publish_enable() ) ){ + return (false); + } + + + /* We load the YAML twice, + this is the first time. to update global flags */ + CFlowsYamlInfo pre_yaml_info; + pre_yaml_info.load_from_yaml_file(CGlobalInfo::m_options.cfg_file); + + if ( pre_yaml_info.m_vlan_info.m_enable ){ + CGlobalInfo::m_options.preview.set_vlan_mode_enable(true); + } + /* End update pre flags */ + + ixgbe_prob_init(); + cores_prob_init(); + queues_prob_init(); + /* allocate rings */ + assert( CMsgIns::Ins()->Create(get_cores_tx()) ); + + if ( sizeof(CGenNodeNatInfo) != sizeof(CGenNode) ) { + printf("ERROR sizeof(CGenNodeNatInfo) %d != sizeof(CGenNode) %d must be the same size \n",sizeof(CGenNodeNatInfo),sizeof(CGenNode)); + assert(0); + } + + if ( sizeof(CGenNodeLatencyPktInfo) != sizeof(CGenNode) ) { + printf("ERROR sizeof(CGenNodeLatencyPktInfo) %d != sizeof(CGenNode) %d must be the same size \n",sizeof(CGenNodeLatencyPktInfo),sizeof(CGenNode)); + assert(0); + } + + /* allocate the memory */ + + uint32_t rx_mbuf = 0 ; + + if ( get_vm_one_queue_enable() ) { + rx_mbuf = (m_max_ports * RTE_TEST_RX_DESC_VM_DEFAULT); + }else{ + rx_mbuf = (m_max_ports * (RTE_TEST_RX_LATENCY_DESC_DEFAULT+RTE_TEST_RX_DESC_DEFAULT)); + } + + CGlobalInfo::init_pools(rx_mbuf); + ixgbe_start(); + dump_config(stdout); + return (true); + +} +void CGlobalPortCfg::Delete(){ + m_zmq_publisher.Delete(); +} + + + +int CGlobalPortCfg::ixgbe_prob_init(void){ + + uint8_t nb_ports; + + + m_max_ports = rte_eth_dev_count(); + if (m_max_ports == 0) + rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); + + printf(" number of ports founded : %d \n",m_max_ports); + + + + if ( CGlobalInfo::m_options.get_expected_ports() >BP_MAX_PORTS ){ + rte_exit(EXIT_FAILURE, " maximum ports supported are %d, use the configuration file to set the expected number of ports \n",BP_MAX_PORTS); + } + + if ( CGlobalInfo::m_options.get_expected_ports() > m_max_ports ){ + rte_exit(EXIT_FAILURE, " there are %d ports you expected more %d,use the configuration file to set the expected number of ports \n", + m_max_ports, + CGlobalInfo::m_options.get_expected_ports()); + } + if (CGlobalInfo::m_options.get_expected_ports() < m_max_ports ) { + /* limit the number of ports */ + m_max_ports=CGlobalInfo::m_options.get_expected_ports(); + } + assert(m_max_ports <= BP_MAX_PORTS); + + if ( m_max_ports %2 !=0 ) { + rte_exit(EXIT_FAILURE, " numbe of ports %d should be even, mask the one port in the configuration file \n, ", + m_max_ports); + + } + + struct rte_eth_dev_info dev_info; + rte_eth_dev_info_get((uint8_t) 0,&dev_info); + + if ( CGlobalInfo::m_options.preview.getVMode() > 0){ + printf("\n\n"); + printf("if_index : %d \n",dev_info.if_index); + printf("driver name : %s \n",dev_info.driver_name); + printf("min_rx_bufsize : %d \n",dev_info.min_rx_bufsize); + printf("max_rx_pktlen : %d \n",dev_info.max_rx_pktlen); + printf("max_rx_queues : %d \n",dev_info.max_rx_queues); + printf("max_tx_queues : %d \n",dev_info.max_tx_queues); + printf("max_mac_addrs : %d \n",dev_info.max_mac_addrs); + + printf("rx_offload_capa : %x \n",dev_info.rx_offload_capa); + printf("tx_offload_capa : %x \n",dev_info.tx_offload_capa); + } + + + + if ( !CTRexExtendedDriverDb::Ins()->is_driver_exists(dev_info.driver_name) ){ + printf(" ERROR driver name %s is not supported \n",dev_info.driver_name); + } + + int i; + struct rte_eth_dev_info dev_info1; + + for (i=1; i<m_max_ports; i++) { + rte_eth_dev_info_get((uint8_t) i,&dev_info1); + if ( strcmp(dev_info1.driver_name,dev_info.driver_name)!=0) { + printf(" ERROR all device should have the same type %s != %s \n",dev_info1.driver_name,dev_info.driver_name); + exit(1); + } + } + + CTRexExtendedDriverDb::Ins()->set_driver_name(dev_info.driver_name); + + /* register driver callback to convert mseg to signle seg */ + if (strcmp(dev_info.driver_name,"rte_vmxnet3_pmd")==0 ) { + vmxnet3_xmit_set_callback(rte_mbuf_convert_to_one_seg); + } + + + m_port_cfg.update_var(); + + if ( get_is_rx_filter_enable() ){ + m_port_cfg.update_global_config_fdir(); + } + + if ( get_vm_one_queue_enable() ) { + /* verify that we have only one thread/core per dual- interface */ + if ( CGlobalInfo::m_options.preview.getCores()>1 ) { + printf(" ERROR the number of cores should be 1 when the driver support only one tx queue and one rx queue \n"); + exit(1); + } + } + return (0); +} + +int CGlobalPortCfg::cores_prob_init(){ + m_max_cores = rte_lcore_count(); + assert(m_max_cores>0); + return (0); +} + +int CGlobalPortCfg::queues_prob_init(){ + + if (m_max_cores < 2) { + rte_exit(EXIT_FAILURE, "number of cores should be at least 3 \n"); + } + + if ( !( (m_max_ports == 4) || (m_max_ports == 2) || (m_max_ports == 8) || (m_max_ports == 6) ) ){ + rte_exit(EXIT_FAILURE, "supported number of ports are 2-8 you have %d \n",m_max_ports); + } + + assert((m_max_ports>>1) <= get_cores_tx() ); + + + + + m_cores_mul = CGlobalInfo::m_options.preview.getCores(); + + m_cores_to_dual_ports = m_cores_mul; + + /* core 0 - control + -core 1 - port 0/1 + -core 2 - port 2/3 + -core 3 - port 0/1 + -core 4 - port 2/3 + + 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; + + 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); + } + + assert(m_max_queues_per_port>0); + return (0); +} + + +void CGlobalPortCfg::dump_config(FILE *fd){ + fprintf(fd," number of ports : %u \n",m_max_ports); + fprintf(fd," max cores for 2 ports : %u \n",m_cores_to_dual_ports); + fprintf(fd," max queue per port : %u \n",m_max_queues_per_port); +} + + + +void CGlobalPortCfg::dump_post_test_stats(FILE *fd){ + uint64_t pkt_out=0; + uint64_t pkt_out_bytes=0; + uint64_t pkt_in_bytes=0; + uint64_t pkt_in=0; + uint64_t sw_pkt_out=0; + uint64_t sw_pkt_out_err=0; + uint64_t sw_pkt_out_bytes=0; + + int i; + for (i=0; i<get_cores_tx(); i++) { + CCoreEthIF * erf_vif = &m_cores_vif[i+1]; + CVirtualIFPerSideStats stats; + erf_vif->GetCoreCounters(&stats); + sw_pkt_out += stats.m_tx_pkt; + sw_pkt_out_err += stats.m_tx_drop +stats.m_tx_queue_full +stats.m_tx_alloc_error ; + sw_pkt_out_bytes +=stats.m_tx_bytes; + } + + + for (i=0; i<m_max_ports; i++) { + CPhyEthIF * _if=&m_ports[i]; + pkt_in +=_if->get_stats().ipackets; + pkt_in_bytes +=_if->get_stats().ibytes; + pkt_out +=_if->get_stats().opackets; + pkt_out_bytes +=_if->get_stats().obytes; + } + if ( !CGlobalInfo::m_options.is_latency_disabled() ){ + sw_pkt_out += m_mg.get_total_pkt(); + sw_pkt_out_bytes +=m_mg.get_total_bytes(); + } + + + fprintf (fd," summary stats \n"); + fprintf (fd," -------------- \n"); + + fprintf (fd," Total-pkt-drop : %d pkts \n",(int64_t)(pkt_out-pkt_in)); + fprintf (fd," Total-tx-bytes : %llu bytes \n",pkt_out_bytes); + fprintf (fd," Total-tx-sw-bytes : %llu bytes \n",sw_pkt_out_bytes); + fprintf (fd," Total-rx-bytes : %llu byte \n",pkt_in_bytes); + + fprintf (fd," \n"); + + fprintf (fd," Total-tx-pkt : %llu pkts \n",pkt_out); + fprintf (fd," Total-rx-pkt : %llu pkts \n",pkt_in); + fprintf (fd," Total-sw-tx-pkt : %llu pkts \n",sw_pkt_out); + fprintf (fd," Total-sw-err : %llu pkts \n",sw_pkt_out_err); + + + if ( !CGlobalInfo::m_options.is_latency_disabled() ){ + fprintf (fd," maximum-latency : %.0f usec \n",m_mg.get_max_latency()); + fprintf (fd," average-latency : %.0f usec \n",m_mg.get_avr_latency()); + fprintf (fd," latency-any-error : %s \n",m_mg.is_any_error()?"ERROR":"OK"); + } + + +} + + +void CGlobalPortCfg::update_stats(){ + + int i; + for (i=0; i<m_max_ports; i++) { + CPhyEthIF * _if=&m_ports[i]; + _if->update_counters(); + } + uint64_t total_open_flows=0; + + + CFlowGenListPerThread * lpt; + for (i=0; i<get_cores_tx(); i++) { + lpt = m_fl.m_threads_info[i]; + total_open_flows += lpt->m_stats.m_total_open_flows ; + } + m_last_total_cps = m_cps.add(total_open_flows); + m_fl.Update(); + +} + + +void CGlobalPortCfg::get_stats(CGlobalStats & stats){ + + int i; + float total_tx=0.0; + float total_rx=0.0; + float total_pps=0.0; + + stats.m_total_tx_pkts = 0; + stats.m_total_rx_pkts = 0; + stats.m_total_tx_bytes = 0; + stats.m_total_rx_bytes = 0; + stats.m_total_alloc_error=0; + stats.m_total_queue_full=0; + stats.m_total_queue_drop=0; + + + stats.m_num_of_ports = m_max_ports; + stats.m_cpu_util = m_fl.GetCpuUtil(); + stats.m_threads = m_fl.m_threads_info.size(); + + for (i=0; i<m_max_ports; i++) { + CPhyEthIF * _if=&m_ports[i]; + CPerPortStats * stp=&stats.m_port[i]; + + CPhyEthIFStats & st =_if->get_stats(); + + stp->opackets = st.opackets; + stp->obytes = st.obytes; + stp->ipackets = st.ipackets; + stp->ibytes = st.ibytes; + stp->ierrors = st.ierrors; + stp->oerrors = st.oerrors; + stp->m_total_tx_bps = _if->get_last_tx_rate()*_1Mb_DOUBLE; + + stats.m_total_tx_pkts += st.opackets; + stats.m_total_rx_pkts += st.ipackets; + stats.m_total_tx_bytes += st.obytes; + stats.m_total_rx_bytes += st.ibytes; + + total_tx +=_if->get_last_tx_rate(); + total_rx +=_if->get_last_rx_rate(); + total_pps +=_if->get_last_pps_rate(); + + } + + uint64_t total_open_flows=0; + uint64_t total_active_flows=0; + + uint64_t total_clients=0; + uint64_t total_servers=0; + uint64_t active_sockets=0; + uint64_t total_sockets=0; + + + uint64_t total_nat_time_out =0; + uint64_t total_nat_no_fid =0; + uint64_t total_nat_active =0; + uint64_t total_nat_open =0; + uint64_t total_nat_learn_error=0; + + + CFlowGenListPerThread * lpt; + stats.m_template.Clear(); + + for (i=0; i<get_cores_tx(); i++) { + lpt = m_fl.m_threads_info[i]; + total_open_flows += lpt->m_stats.m_total_open_flows ; + total_active_flows += (lpt->m_stats.m_total_open_flows-lpt->m_stats.m_total_close_flows) ; + + stats.m_total_alloc_error += lpt->m_node_gen.m_v_if->m_stats[0].m_tx_alloc_error+ + lpt->m_node_gen.m_v_if->m_stats[1].m_tx_alloc_error; + stats.m_total_queue_full +=lpt->m_node_gen.m_v_if->m_stats[0].m_tx_queue_full+ + lpt->m_node_gen.m_v_if->m_stats[1].m_tx_queue_full; + + stats.m_total_queue_drop =lpt->m_node_gen.m_v_if->m_stats[0].m_tx_drop+ + lpt->m_node_gen.m_v_if->m_stats[1].m_tx_drop; + + stats.m_template.Add(&lpt->m_node_gen.m_v_if->m_stats[0].m_template); + stats.m_template.Add(&lpt->m_node_gen.m_v_if->m_stats[1].m_template); + + + total_clients += lpt->m_smart_gen.getTotalClients(); + total_servers += lpt->m_smart_gen.getTotalServers(); + active_sockets += lpt->m_smart_gen.ActiveSockets(); + total_sockets += lpt->m_smart_gen.MaxSockets(); + + total_nat_time_out +=lpt->m_stats.m_nat_flow_timeout; + total_nat_no_fid +=lpt->m_stats.m_nat_lookup_no_flow_id ; + total_nat_active +=lpt->m_stats.m_nat_lookup_add_flow_id - lpt->m_stats.m_nat_lookup_remove_flow_id; + total_nat_open +=lpt->m_stats.m_nat_lookup_add_flow_id; + total_nat_learn_error +=lpt->m_stats.m_nat_flow_learn_error; + } + + stats.m_total_nat_time_out = total_nat_time_out; + stats.m_total_nat_no_fid = total_nat_no_fid; + stats.m_total_nat_active = total_nat_active; + stats.m_total_nat_open = total_nat_open; + stats.m_total_nat_learn_error = total_nat_learn_error; + + stats.m_total_clients = total_clients; + stats.m_total_servers = total_servers; + stats.m_active_sockets = active_sockets; + stats.m_socket_util =100.0*(double)active_sockets/(double)total_sockets; + + + float drop_rate=total_tx-total_rx; + if ( (drop_rate<0.0) || (drop_rate < 0.1*total_tx ) ) { + drop_rate=0.0; + } + float pf =CGlobalInfo::m_options.m_platform_factor; + stats.m_platform_factor = pf; + + stats.m_active_flows = total_active_flows*pf; + stats.m_open_flows = total_open_flows*pf; + stats.m_rx_drop_bps = drop_rate*pf *_1Mb_DOUBLE; + + stats.m_tx_bps = total_tx*pf*_1Mb_DOUBLE; + stats.m_rx_bps = total_rx*pf*_1Mb_DOUBLE; + stats.m_tx_pps = total_pps*pf; + stats.m_tx_cps = m_last_total_cps*pf; + + stats.m_tx_expected_cps = m_expected_cps*pf; + stats.m_tx_expected_pps = m_expected_pps*pf; + stats.m_tx_expected_bps = m_expected_bps*pf; +} + +bool CGlobalPortCfg::sanity_check(){ + + CFlowGenListPerThread * lpt; + uint32_t errors=0; + int i; + for (i=0; i<get_cores_tx(); i++) { + lpt = m_fl.m_threads_info[i]; + errors += lpt->m_smart_gen.getErrorAllocationCounter(); + } + + if ( errors ) { + printf(" ERRORs sockets allocation errors! \n"); + printf(" you should allocate more clients in the pool \n"); + return(true); + } + return ( false); +} + + +/* dump the template info */ +void CGlobalPortCfg::dump_template_info(std::string & json){ + CFlowGenListPerThread * lpt = m_fl.m_threads_info[0]; + CFlowsYamlInfo * yaml_info=&lpt->m_yaml_info; + + json="{\"name\":\"template_info\",\"type\":0,\"data\":["; + int i; + for (i=0; i<yaml_info->m_vec.size()-1; i++) { + CFlowYamlInfo * r=&yaml_info->m_vec[i] ; + json+="\""+ r->m_name+"\""; + json+=","; + } + json+="\""+yaml_info->m_vec[i].m_name+"\""; + json+="]}" ; +} + +void CGlobalPortCfg::dump_stats(FILE *fd,std::string & json, + CGlobalStats::DumpFormat format){ + CGlobalStats stats; + update_stats(); + get_stats(stats); + if (format==CGlobalStats::dmpTABLE) { + if ( m_io_modes.m_g_mode == CTrexGlobalIoMode::gNORMAL ){ + switch (m_io_modes.m_pp_mode ){ + case CTrexGlobalIoMode::ppDISABLE: + fprintf(fd,"\n+Per port stats disabled \n"); + break; + case CTrexGlobalIoMode::ppTABLE: + fprintf(fd,"\n-Per port stats table \n"); + stats.Dump(fd,CGlobalStats::dmpTABLE); + break; + case CTrexGlobalIoMode::ppSTANDARD: + fprintf(fd,"\n-Per port stats - standard\n"); + stats.Dump(fd,CGlobalStats::dmpSTANDARD); + break; + }; + + switch (m_io_modes.m_ap_mode ){ + case CTrexGlobalIoMode::apDISABLE: + fprintf(fd,"\n+Global stats disabled \n"); + break; + case CTrexGlobalIoMode::apENABLE: + fprintf(fd,"\n-Global stats enabled \n"); + stats.DumpAllPorts(fd); + break; + }; + } + }else{ + /* at exit , always need to dump it in standartd mode for scripts*/ + stats.Dump(fd,format); + stats.DumpAllPorts(fd); + } + stats.dump_json(json); +} + + +int CGlobalPortCfg::run_in_master(){ + + std::string json; + bool was_stopped=false; + while ( true ) { + + if ( CGlobalInfo::m_options.preview.get_no_keyboard() ==false ){ + if ( m_io_modes.handle_io_modes() ){ + was_stopped=true; + break; + } + } + + if ( sanity_check() ){ + printf(" Test was stopped \n"); + was_stopped=true; + break; + } + if (m_io_modes.m_g_mode != CTrexGlobalIoMode::gDISABLE ) { + fprintf(stdout,"\033[2J"); + fprintf(stdout,"\033[2H"); + + }else{ + if ( m_io_modes.m_g_disable_first ){ + m_io_modes.m_g_disable_first=false; + fprintf(stdout,"\033[2J"); + fprintf(stdout,"\033[2H"); + printf("clean !!!\n"); + fflush(stdout); + } + } + + + if (m_io_modes.m_g_mode == CTrexGlobalIoMode::gHELP ) { + m_io_modes.DumpHelp(stdout); + } + + dump_stats(stdout,json,CGlobalStats::dmpTABLE); + + if (m_io_modes.m_g_mode == CTrexGlobalIoMode::gNORMAL ) { + fprintf (stdout," current time : %.1f sec \n",now_sec()); + float d= CGlobalInfo::m_options.m_duration - now_sec(); + if (d<0) { + d=0; + + } + fprintf (stdout," test duration : %.1f sec \n",d); + } + + m_zmq_publisher.publish_json(json); + + /* generator json , all cores are the same just sample the first one */ + m_fl.m_threads_info[0]->m_node_gen.dump_json(json); + m_zmq_publisher.publish_json(json); + + dump_template_info(json); + m_zmq_publisher.publish_json(json); + + + + if ( !CGlobalInfo::m_options.is_latency_disabled() ){ + 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 ( get_is_rx_check_mode() ) { + + switch (m_io_modes.m_rc_mode) { + case CTrexGlobalIoMode::rcDISABLE: + fprintf(stdout,"\n+Rx Check stats disabled \n"); + break; + case CTrexGlobalIoMode::rcENABLE: + fprintf(stdout,"\n-Rx Check stats enabled \n"); + m_mg.DumpShortRxCheck(stdout); + break; + case CTrexGlobalIoMode::rcENABLE_Extended: + fprintf(stdout,"\n-Rx Check stats enhanced \n"); + m_mg.DumpRxCheck(stdout); + break; + } + + m_mg.rx_check_dump_json(json ); + m_zmq_publisher.publish_json(json); + + }/* ex checked */ + + } + + /* backward compatible */ + m_mg.dump_json(json ); + m_zmq_publisher.publish_json(json); + + /* more info */ + m_mg.dump_json_v2(json ); + m_zmq_publisher.publish_json(json); + + } + + delay(500); + + if ( is_all_cores_finished() ) { + break; + } + } + m_mg.stop(); + delay(1000); + if ( was_stopped ){ + /* we should stop latency and exit to stop agents */ + exit(-1); + } + return (0); +} + + + +int CGlobalPortCfg::run_in_laterncy_core(void){ + if ( !CGlobalInfo::m_options.is_latency_disabled() ){ + m_mg.start(0); + } + return (0); +} + + +int CGlobalPortCfg::stop_core(virtual_thread_id_t virt_core_id){ + m_signal[virt_core_id]=1; + return (0); +} + +int CGlobalPortCfg::run_in_core(virtual_thread_id_t virt_core_id){ + + CPreviewMode *lp=&CGlobalInfo::m_options.preview; + if ( lp->getSingleCore() && + (virt_core_id==2 ) && + (lp-> getCores() ==1) ){ + printf(" bypass this core \n"); + m_signal[virt_core_id]=1; + return (0); + } + + assert(m_fl_was_init); + CFlowGenListPerThread * lpt; + lpt = m_fl.m_threads_info[virt_core_id-1]; + lpt->generate_erf(CGlobalInfo::m_options.out_file,*lp); + //lpt->m_node_gen.DumpHist(stdout); + //lpt->DumpStats(stdout); + + m_signal[virt_core_id]=1; + return (0); +} + + +int CGlobalPortCfg::stop_master(){ + + delay(1000); + std::string json; + fprintf(stdout," ==================\n"); + fprintf(stdout," interface sum \n"); + fprintf(stdout," ==================\n"); + dump_stats(stdout,json,CGlobalStats::dmpSTANDARD); + fprintf(stdout," ==================\n"); + fprintf(stdout," \n\n"); + + fprintf(stdout," ==================\n"); + fprintf(stdout," interface sum \n"); + fprintf(stdout," ==================\n"); + + CFlowGenListPerThread * lpt; + uint64_t total_tx_rx_check=0; + + int i; + for (i=0; i<get_cores_tx(); i++) { + lpt = m_fl.m_threads_info[i]; + CCoreEthIF * erf_vif = &m_cores_vif[i+1]; + + erf_vif->DumpCoreStats(stdout); + erf_vif->DumpIfStats(stdout); + total_tx_rx_check+=erf_vif->m_stats[CLIENT_SIDE].m_tx_rx_check_pkt+ + erf_vif->m_stats[SERVER_SIDE].m_tx_rx_check_pkt; + } + + fprintf(stdout," ==================\n"); + fprintf(stdout," generators \n"); + fprintf(stdout," ==================\n"); + for (i=0; i<get_cores_tx(); i++) { + lpt = m_fl.m_threads_info[i]; + lpt->m_node_gen.DumpHist(stdout); + lpt->DumpStats(stdout); + } + if ( !CGlobalInfo::m_options.is_latency_disabled() ){ + fprintf(stdout," ==================\n"); + fprintf(stdout," latency \n"); + fprintf(stdout," ==================\n"); + m_mg.DumpShort(stdout); + m_mg.Dump(stdout); + m_mg.DumpShortRxCheck(stdout); + m_mg.DumpRxCheck(stdout); + m_mg.DumpRxCheckVerification(stdout,total_tx_rx_check); + } + + dump_stats(stdout,json,CGlobalStats::dmpSTANDARD); + dump_post_test_stats(stdout); + m_fl.Delete(); + +} + +bool CGlobalPortCfg::is_all_cores_finished(){ + int i; + for (i=0; i<get_cores_tx(); i++) { + if ( m_signal[i+1]==0){ + return (false); + } + } + return (true); +} + + + +int CGlobalPortCfg::start_send_master(){ + int i; + for (i=0; i<BP_MAX_CORES; i++) { + m_signal[i]=0; + } + + m_fl.Create(); + m_fl.load_from_yaml(CGlobalInfo::m_options.cfg_file,get_cores_tx()); + if (CGlobalInfo::m_options.mac_file != "") { + CGlobalInfo::m_options.preview.set_mac_ip_mapping_enable(true); + m_fl.load_from_mac_file(CGlobalInfo::m_options.mac_file); + m_fl.is_mac_info_configured = true; + } else { + m_fl.is_mac_info_configured = false; + } + + m_expected_pps = m_fl.get_total_pps(); + m_expected_cps = 1000.0*m_fl.get_total_kcps(); + m_expected_bps = m_fl.get_total_tx_bps(); + if ( m_fl.get_total_repeat_flows() > 2000) { + /* disable flows cache */ + CGlobalInfo::m_options.preview.setDisableMbufCache(true); + } + + CTupleGenYamlInfo * tg=&m_fl.m_yaml_info.m_tuple_gen; + + m_mg.set_ip( tg->m_clients_ip_start, + tg->m_servers_ip_start, + tg->m_dual_interface_mask + ); + + + if ( CGlobalInfo::m_options.preview.getVMode() >0 ) { + m_fl.DumpCsv(stdout); + for (i=0; i<100; i++) { + fprintf(stdout,"\n"); + } + fflush(stdout); + } + + m_fl.generate_p_thread_info(get_cores_tx()); + CFlowGenListPerThread * lpt; + + for (i=0; i<get_cores_tx(); i++) { + lpt = m_fl.m_threads_info[i]; + //CNullIF * erf_vif = new CNullIF(); + CVirtualIF * erf_vif = &m_cores_vif[i+1]; + lpt->set_vif(erf_vif); + /* socket id */ + lpt->m_node_gen.m_socket_id =m_cores_vif[i+1].get_socket_id(); + + } + m_fl_was_init=true; + +} + + +//////////////////////////////////////////// + +static CGlobalPortCfg ports_cfg; + +static int latency_one_lcore(__attribute__((unused)) void *dummy) +{ + CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket; + physical_thread_id_t phy_id =rte_lcore_id(); + + + if ( lpsock->thread_phy_is_latency( phy_id ) ){ + ports_cfg.run_in_laterncy_core(); + }else{ + + if ( lpsock->thread_phy_is_master( phy_id ) ) { + ports_cfg.run_in_master(); + delay(1); + }else{ + delay((uint32_t)(1000.0*CGlobalInfo::m_options.m_duration)); + /* this core has stopped */ + ports_cfg.m_signal[ lpsock->thread_phy_to_virt( phy_id ) ]=1; + } + } + return 0; +} + + + + +static int slave_one_lcore(__attribute__((unused)) void *dummy) +{ + CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket; + physical_thread_id_t phy_id =rte_lcore_id(); + + + if ( lpsock->thread_phy_is_latency( phy_id ) ){ + ports_cfg.run_in_laterncy_core(); + }else{ + if ( lpsock->thread_phy_is_master( phy_id ) ) { + ports_cfg.run_in_master(); + delay(1); + }else{ + ports_cfg.run_in_core( lpsock->thread_phy_to_virt( phy_id ) ); + } + } + return 0; +} + + + +uint32_t get_cores_mask(uint32_t cores,int offset){ + int i; + + uint32_t res=1; + + uint32_t mask=(1<<(offset+1)); + for (i=0; i<(cores-1); i++) { + res |= mask ; + mask = mask <<1; + } + return (res); +} + + + + +int main(int argc , char * argv[]){ + + return ( main_test(argc , argv)); +} + + +int update_global_info_from_platform_file(){ + + CPlatformYamlInfo *cg=&global_platform_cfg_info; + + CGlobalInfo::m_socket.Create(&cg->m_platform); + + + if (!cg->m_info_exist) { + /* nothing to do ! */ + return 0; + } + + CGlobalInfo::m_options.prefix =cg->m_prefix; + CGlobalInfo::m_options.preview.setCores(cg->m_thread_per_dual_if); + + if ( cg->m_port_limit_exist ){ + CGlobalInfo::m_options.m_expected_portd =cg->m_port_limit; + } + + if ( cg->m_enable_zmq_pub_exist ){ + CGlobalInfo::m_options.preview.set_zmq_publish_enable(cg->m_enable_zmq_pub); + CGlobalInfo::m_options.m_zmq_port = cg->m_zmq_pub_port; + } + if ( cg->m_telnet_exist ){ + CGlobalInfo::m_options.m_telnet_port = cg->m_telnet_port; + } + + if ( cg->m_mac_info_exist ){ + int i; + /* cop the file info */ + + int port_size=cg->m_mac_info.size(); + + if ( port_size > BP_MAX_PORTS ){ + port_size = BP_MAX_PORTS; + } + for (i=0; i<port_size; i++){ + cg->m_mac_info[i].copy_src(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.src) ; + cg->m_mac_info[i].copy_dest(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.dest) ; + } + } + + /* mul by interface type */ + float mul=1.0; + if (cg->m_port_bandwidth_gb<10) { + cg->m_port_bandwidth_gb=10.0; + } + + mul = mul*(float)cg->m_port_bandwidth_gb/10.0; + mul= mul * (float)cg->m_port_limit/2.0; + + CGlobalInfo::m_memory_cfg.set(cg->m_memory,mul); + CGlobalInfo::m_memory_cfg.set_number_of_dp_cors( + CGlobalInfo::m_options.get_number_of_dp_cores_needed() ); + + return (0); +} + + +int update_dpdk_args(void){ + + uint32_t cores_number; + CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket; + CParserOption * lpop= &CGlobalInfo::m_options; + + lpsock->set_latency_thread_is_enabled(get_is_latency_thread_enable()); + lpsock->set_number_of_threads_per_ports(lpop->preview.getCores() ); + lpsock->set_number_of_dual_ports(lpop->get_expected_dual_ports()); + if ( !lpsock->sanity_check() ){ + printf(" ERROR in configuration file \n"); + return (-1); + } + + if ( CGlobalInfo::m_options.preview.getVMode() > 0 ) { + lpsock->dump(stdout); + } + + + sprintf(global_cores_str,"0x%x",lpsock->get_cores_mask()); + + /* set the DPDK options */ + global_dpdk_args_num =7; + + global_dpdk_args[0]=(char *)"xx"; + global_dpdk_args[1]=(char *)"-c"; + global_dpdk_args[2]=(char *)global_cores_str; + global_dpdk_args[3]=(char *)"-n"; + global_dpdk_args[4]=(char *)"4"; + + if ( CGlobalInfo::m_options.preview.getVMode() == 0 ) { + global_dpdk_args[5]=(char *)"--log-level"; + sprintf(global_loglevel_str,"%d",1); + global_dpdk_args[6]=(char *)global_loglevel_str; + }else{ + global_dpdk_args[5]=(char *)"--log-level"; + sprintf(global_loglevel_str,"%d",CGlobalInfo::m_options.preview.getVMode()+1); + global_dpdk_args[6]=(char *)global_loglevel_str; + } + + global_dpdk_args_num = 7; + + /* add white list */ + for (int i=0; i<(int)global_platform_cfg_info.m_if_list.size(); i++) { + global_dpdk_args[global_dpdk_args_num++]=(char *)"-w"; + global_dpdk_args[global_dpdk_args_num++]=(char *)global_platform_cfg_info.m_if_list[i].c_str(); + } + + + + if ( lpop->prefix.length() ){ + global_dpdk_args[global_dpdk_args_num++]=(char *)"--file-prefix"; + sprintf(global_prefix_str,"%s",lpop->prefix.c_str()); + global_dpdk_args[global_dpdk_args_num++]=(char *)global_prefix_str; + global_dpdk_args[global_dpdk_args_num++]=(char *)"-m"; + if (global_platform_cfg_info.m_limit_memory.length()) { + global_dpdk_args[global_dpdk_args_num++]=(char *)global_platform_cfg_info.m_limit_memory.c_str(); + }else{ + global_dpdk_args[global_dpdk_args_num++]=(char *)"1024"; + } + } + + + if ( CGlobalInfo::m_options.preview.getVMode() > 0 ) { + printf("args \n"); + int i; + for (i=0; i<global_dpdk_args_num; i++) { + printf(" %s \n",global_dpdk_args[i]); + } + } +} + + +int sim_load_list_of_cap_files(CParserOption * op){ + + CFlowGenList fl; + fl.Create(); + fl.load_from_yaml(op->cfg_file,1); + if ( op->preview.getVMode() >0 ) { + fl.DumpCsv(stdout); + } + uint32_t start= os_get_time_msec(); + + CErfIF erf_vif; + + fl.generate_p_thread_info(1); + CFlowGenListPerThread * lpt; + lpt=fl.m_threads_info[0]; + lpt->set_vif(&erf_vif); + + if ( (op->preview.getVMode() >1) || op->preview.getFileWrite() ) { + lpt->generate_erf(op->out_file,op->preview); + } + + lpt->m_node_gen.DumpHist(stdout); + + uint32_t stop= os_get_time_msec(); + printf(" d time = %ul %ul \n",stop-start,os_get_time_freq()); + fl.Delete(); + return (0); +} + + + + + + + + +int main_test(int argc , char * argv[]){ + + utl_termio_init(); + + int ret; + unsigned lcore_id; + printf("Starting T-Rex %s please wait ... \n",VERSION); + + CGlobalInfo::m_options.preview.clean(); + + if ( parse_options(argc, argv, &CGlobalInfo::m_options,true ) != 0){ + exit(-1); + } + + update_global_info_from_platform_file(); + + /* it is not a mistake , give the user higher priorty over the configuration file */ + parse_options(argc, argv, &CGlobalInfo::m_options ,false); + + + if ( CGlobalInfo::m_options.preview.getVMode() > 0){ + CGlobalInfo::m_options.dump(stdout); + CGlobalInfo::m_memory_cfg.Dump(stdout); + } + + update_dpdk_args(); + + CParserOption * po=&CGlobalInfo::m_options; + + + if ( CGlobalInfo::m_options.preview.getVMode() == 0 ) { + rte_set_log_level(1); + + } + uid_t uid; + uid = geteuid (); + if ( uid != 0 ) { + printf("ERROR you must run with superuser priviliges \n"); + printf("User id : %d \n",uid); + printf("try 'sudo' %s \n",argv[0]); + return (-1); + } + + + + ret = rte_eal_init(global_dpdk_args_num, (char **)global_dpdk_args); + if (ret < 0){ + printf(" You might need to run ./trex-cfg once \n"); + rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); + } + + + time_init(); + + /* check if we are in simulation mode */ + if ( CGlobalInfo::m_options.out_file != "" ){ + printf(" t-rex simulation mode into %s \n",CGlobalInfo::m_options.out_file.c_str()); + return ( sim_load_list_of_cap_files(&CGlobalInfo::m_options) ); + } + + + if ( !ports_cfg.Create() ){ + exit(1); + } + + if (po->preview.get_is_rx_check_enable() && (po->m_rx_check_sampe< get_min_sample_rate()) ) { + po->m_rx_check_sampe = get_min_sample_rate(); + printf("Warning rx check sample rate should be lower than %d setting it to %d\n",get_min_sample_rate(),get_min_sample_rate()); + } + + /* set dump mode */ + ports_cfg.m_io_modes.set_mode((CTrexGlobalIoMode::CliDumpMode)CGlobalInfo::m_options.m_io_mode); + + if ( !CGlobalInfo::m_options.is_latency_disabled() + && (CGlobalInfo::m_options.m_latency_prev>0) ){ + uint32_t pkts = CGlobalInfo::m_options.m_latency_prev* + CGlobalInfo::m_options.m_latency_rate; + printf("Start prev latency check - hack for Keren for %d sec \n",CGlobalInfo::m_options.m_latency_prev); + ports_cfg.m_mg.start(pkts); + printf("Delay now you can call command \n"); + delay(CGlobalInfo::m_options.m_latency_prev* 1000); + printf("Finish wating \n"); + ports_cfg.m_mg.reset(); + ports_cfg.reset_counters(); + } + + ports_cfg.start_send_master(); + + // TBD remove + //ports_cfg.test_latency(); + /* test seding */ + //while (1) { + //} + + + /* TBD_FDIR */ + #if 0 + printf(" test_send \n"); + ports_cfg.test_send(); + while (1) { + delay(10000); + } + #endif + + + + + //ports_cfg.test_latency(); + //return (0); + + + if ( CGlobalInfo::m_options.preview.getOnlyLatency() ){ + rte_eal_mp_remote_launch(latency_one_lcore, NULL, CALL_MASTER); + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + return -1; + } + ports_cfg.stop_master(); + + return (0); + } + + if ( CGlobalInfo::m_options.preview.getSingleCore() ) { + ports_cfg.run_in_core(1); + ports_cfg.stop_master(); + return (0); + } + + rte_eal_mp_remote_launch(slave_one_lcore, NULL, CALL_MASTER); + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + return -1; + } + ports_cfg.stop_master(); + ports_cfg.Delete(); + utl_termio_reset(); + + return (0); +} + + +////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// +// driver section +////////////////////////////////////////////////////////////////////////////////////////////// + +int CTRexExtendedDriverBase1G::wait_for_stable_link(){ + int i; + printf(" wait 10 sec "); + fflush(stdout); + for (i=0; i<10; i++) { + delay(1000); + printf("."); + fflush(stdout); + } + printf("\n"); + fflush(stdout); + return(0); +} + +int CTRexExtendedDriverBase1G::configure_drop_queue(CPhyEthIF * _if){ + _if->pci_reg_write( E1000_RXDCTL(0) , 0); + + /* enable filter to pass packet to rx queue 1 */ + + _if->pci_reg_write( E1000_IMIR(0), 0x00020000); + + _if->pci_reg_write( E1000_IMIREXT(0), 0x00081000); + + _if->pci_reg_write( E1000_TTQF(0), 0x00000084 /* protocol */ + | 0x00008100 /* enable */ + | 0xE0010000 /* RX queue is 1 */ + ); + return (0); +} + +void CTRexExtendedDriverBase1G::update_configuration(port_cfg_t * cfg){ + + cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH_1G; + cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; + cfg->m_tx_conf.tx_thresh.wthresh = 0; +} + +void CTRexExtendedDriverBase1G::update_global_config_fdir(port_cfg_t * cfg){ + cfg->update_global_config_fdir_10g_1g(); +} + + +int CTRexExtendedDriverBase1G::configure_rx_filter_rules(CPhyEthIF * _if){ + + uint16_t hops = get_rx_check_hops(); + uint16_t v4_hops = (hops << 8)&0xff00; + + /* 16 : 12 MAC , (2)0x0800,2 | DW0 , DW1 + 6 bytes , TTL , PROTO | DW2=0 , DW3=0x0000FF06 + */ + int i; + // IPv4: bytes being compared are {TTL, Protocol} + uint16_t ff_rules_v4[4]={ + 0xFF06 - v4_hops, + 0xFE11 - v4_hops, + 0xFF11 - v4_hops, + 0xFE06 - v4_hops, + } ; + // IPv6: bytes being compared are {NextHdr, HopLimit} + uint16_t ff_rules_v6[2]={ + 0x3CFF - hops, + 0x3CFE - hops, + } ; + uint16_t *ff_rules; + uint16_t num_rules; + uint32_t mask=0; + int rule_id; + + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ){ + ff_rules = &ff_rules_v6[0]; + num_rules = sizeof(ff_rules_v6)/sizeof(ff_rules_v6[0]); + }else{ + ff_rules = &ff_rules_v4[0]; + num_rules = sizeof(ff_rules_v4)/sizeof(ff_rules_v4[0]); + } + + uint8_t len = 24; + for (rule_id=0; rule_id<num_rules; rule_id++ ) { + /* clear rule all */ + for (i=0; i<0xff; i+=4) { + _if->pci_reg_write( (E1000_FHFT(rule_id)+i) , 0); + } + + if ( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ){ + len += 8; + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ){ + // IPv6 VLAN: NextHdr/HopLimit offset = 0x18 + _if->pci_reg_write( (E1000_FHFT(rule_id)+(3*16)+0) , PKT_NTOHS(ff_rules[rule_id]) ); + _if->pci_reg_write( (E1000_FHFT(rule_id)+(3*16)+8) , 0x03); /* MASK */ + }else{ + // IPv4 VLAN: TTL/Protocol offset = 0x1A + _if->pci_reg_write( (E1000_FHFT(rule_id)+(3*16)+0) , (PKT_NTOHS(ff_rules[rule_id])<<16) ); + _if->pci_reg_write( (E1000_FHFT(rule_id)+(3*16)+8) , 0x0C); /* MASK */ + } + }else{ + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ){ + // IPv6: NextHdr/HopLimit offset = 0x14 + _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16)+4) , PKT_NTOHS(ff_rules[rule_id]) ); + _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16)+8) , 0x30); /* MASK */ + }else{ + // IPv4: TTL/Protocol offset = 0x16 + _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16)+4) , (PKT_NTOHS(ff_rules[rule_id])<<16) ); + _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16)+8) , 0xC0); /* MASK */ + } + } + + // FLEX_PRIO[[18:16] = 1, RQUEUE[10:8] = 1 + _if->pci_reg_write( (E1000_FHFT(rule_id)+0xFC) , (1<<16) | (1<<8) | len); + + mask |=(1<<rule_id); + } + + /* enable all rules */ + _if->pci_reg_write(E1000_WUFC, (mask<<16) | (1<<14) ); +} + + +void CTRexExtendedDriverBase1G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){ + + int i; + uint64_t t=0; + + stats->ipackets += _if->pci_reg_read(E1000_GPRC) ; + + stats->ibytes += (_if->pci_reg_read(E1000_GORCL) ); + stats->ibytes += (((uint64_t)_if->pci_reg_read(E1000_GORCH))<<32); + + + stats->opackets += _if->pci_reg_read(E1000_GPTC); + stats->obytes += _if->pci_reg_read(E1000_GOTCL) ; + stats->obytes += ( (((uint64_t)_if->pci_reg_read(IXGBE_GOTCH))<<32) ); + + stats->f_ipackets += 0; + stats->f_ibytes += 0; + + + stats->ierrors += ( _if->pci_reg_read(E1000_RNBC) + + _if->pci_reg_read(E1000_CRCERRS) + + _if->pci_reg_read(E1000_ALGNERRC ) + + _if->pci_reg_read(E1000_SYMERRS ) + + _if->pci_reg_read(E1000_RXERRC ) + + + _if->pci_reg_read(E1000_ROC)+ + _if->pci_reg_read(E1000_RUC)+ + _if->pci_reg_read(E1000_RJC) + + + _if->pci_reg_read(E1000_XONRXC)+ + _if->pci_reg_read(E1000_XONTXC)+ + _if->pci_reg_read(E1000_XOFFRXC)+ + _if->pci_reg_read(E1000_XOFFTXC)+ + _if->pci_reg_read(E1000_FCRUC) + ); + + stats->oerrors += 0; + stats->imcasts = 0; + stats->rx_nombuf = 0; +} + +void CTRexExtendedDriverBase1G::clear_extended_stats(CPhyEthIF * _if){ +} + + + +void CTRexExtendedDriverBase10G::clear_extended_stats(CPhyEthIF * _if){ + _if->pci_reg_read(IXGBE_RXNFGPC); +} + +void CTRexExtendedDriverBase10G::update_global_config_fdir(port_cfg_t * cfg){ + cfg->update_global_config_fdir_10g_1g(); +} + +void CTRexExtendedDriverBase10G::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; +} + +int CTRexExtendedDriverBase10G::configure_rx_filter_rules(CPhyEthIF * _if){ + /* 10Gb/sec 82599 */ + uint8_t port_id=_if->get_rte_port_id(); + + uint16_t hops = get_rx_check_hops(); + uint16_t v4_hops = (hops << 8)&0xff00; + + + /* set the mask only for flex-data */ + rte_fdir_masks fdir_mask; + memset(&fdir_mask,0,sizeof(rte_fdir_masks)); + fdir_mask.flexbytes=1; + //fdir_mask.dst_port_mask=0xffff; /* enable of + int res; + res=rte_eth_dev_fdir_set_masks(port_id,&fdir_mask); + if (res!=0) { + rte_exit(EXIT_FAILURE, " ERROR rte_eth_dev_fdir_set_masks : %d \n",res); + } + + + // IPv4: bytes being compared are {TTL, Protocol} + uint16_t ff_rules_v4[4]={ + 0xFF11 - v4_hops, + 0xFE11 - v4_hops, + 0xFF06 - v4_hops, + 0xFE06 - v4_hops, + } ; + // IPv6: bytes being compared are {NextHdr, HopLimit} + uint16_t ff_rules_v6[4]={ + 0x3CFF - hops, + 0x3CFE - hops, + 0x3CFF - hops, + 0x3CFE - hops, + } ; + const rte_l4type ff_rules_type[4]={ + RTE_FDIR_L4TYPE_UDP, + RTE_FDIR_L4TYPE_UDP, + RTE_FDIR_L4TYPE_TCP, + RTE_FDIR_L4TYPE_TCP + } ; + + uint16_t *ff_rules; + uint16_t num_rules; + int rule_id; + + assert (sizeof(ff_rules_v4) == sizeof(ff_rules_v6)); + num_rules = sizeof(ff_rules_v4)/sizeof(ff_rules_v4[0]); + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ){ + ff_rules = &ff_rules_v6[0]; + }else{ + ff_rules = &ff_rules_v4[0]; + } + + for (rule_id=0; rule_id<num_rules; rule_id++ ) { + + rte_fdir_filter fdir_filter; + uint16_t ff_rule = ff_rules[rule_id]; + memset(&fdir_filter,0,sizeof(rte_fdir_filter)); + /* TOS/PROTO */ + if ( CGlobalInfo::m_options.preview.get_ipv6_mode_enable() ){ + fdir_filter.iptype = RTE_FDIR_IPTYPE_IPV6; + }else{ + fdir_filter.iptype = RTE_FDIR_IPTYPE_IPV4; + } + fdir_filter.flex_bytes = PKT_NTOHS(ff_rule); + fdir_filter.l4type = ff_rules_type[rule_id]; + + res=rte_eth_dev_fdir_add_perfect_filter(port_id, + &fdir_filter, + rule_id, 1,0); + if (res!=0) { + rte_exit(EXIT_FAILURE, " ERROR rte_eth_dev_fdir_add_perfect_filter : %d\n",res); + } + } +} + +int CTRexExtendedDriverBase10G::configure_drop_queue(CPhyEthIF * _if){ + + /* enable rule 0 SCTP -> queue 1 for latency */ + /* 1<<21 means that queue 1 is for SCTP */ + _if->pci_reg_write(IXGBE_L34T_IMIR(0),(1<<21)); + + _if->pci_reg_write(IXGBE_FTQF(0), + IXGBE_FTQF_PROTOCOL_SCTP| + (IXGBE_FTQF_PRIORITY_MASK<<IXGBE_FTQF_PRIORITY_SHIFT)| + ((0x0f)<<IXGBE_FTQF_5TUPLE_MASK_SHIFT)|IXGBE_FTQF_QUEUE_ENABLE); + + /* disable queue zero - default all traffic will go to here and will be dropped */ + + _if->pci_reg_write( IXGBE_RXDCTL(0) , 0); + return (0); +} + +void CTRexExtendedDriverBase10G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){ + + int i; + uint64_t t=0; + for (i=0; i<8;i++) { + t+=_if->pci_reg_read(IXGBE_MPC(i)); + } + + stats->ipackets += _if->pci_reg_read(IXGBE_GPRC) ; + + stats->ibytes += (_if->pci_reg_read(IXGBE_GORCL) +(((uint64_t)_if->pci_reg_read(IXGBE_GORCH))<<32)); + + + + stats->opackets += _if->pci_reg_read(IXGBE_GPTC); + stats->obytes += (_if->pci_reg_read(IXGBE_GOTCL) +(((uint64_t)_if->pci_reg_read(IXGBE_GOTCH))<<32)); + + stats->f_ipackets += _if->pci_reg_read(IXGBE_RXDGPC); + stats->f_ibytes += (_if->pci_reg_read(IXGBE_RXDGBCL) +(((uint64_t)_if->pci_reg_read(IXGBE_RXDGBCH))<<32)); + + + stats->ierrors += ( _if->pci_reg_read(IXGBE_RLEC) + + _if->pci_reg_read(IXGBE_ERRBC) + + _if->pci_reg_read(IXGBE_CRCERRS) + + _if->pci_reg_read(IXGBE_ILLERRC ) + + _if->pci_reg_read(IXGBE_ROC)+ + _if->pci_reg_read(IXGBE_RUC)+t); + + stats->oerrors += 0; + stats->imcasts = 0; + stats->rx_nombuf = 0; + +} + +int CTRexExtendedDriverBase10G::wait_for_stable_link(){ + delay(2000); + return (0); +} + +//////////////////////////////////////////////////////////////////////////////// + + +void CTRexExtendedDriverBase40G::clear_extended_stats(CPhyEthIF * _if){ + + rte_eth_stats_reset(_if->get_port_id()); + +} + +void CTRexExtendedDriverBase40G::update_configuration(port_cfg_t * cfg){ + cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH; + cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; + cfg->m_tx_conf.tx_thresh.wthresh = TX_WTHRESH; + cfg->update_global_config_fdir_40g(); +} + + + +void CTRexExtendedDriverBase40G::add_rules(CPhyEthIF * _if, + enum rte_eth_flow_type type, + uint8_t ttl){ + uint8_t port_id = _if->get_port_id(); + 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)); + + filter.action.rx_queue =1; + filter.action.behavior =RTE_ETH_FDIR_ACCEPT; + filter.action.report_status =RTE_ETH_FDIR_NO_REPORT_STATUS; + filter.soft_id=0; + + filter.input.flow_type = type; + filter.input.ttl=ttl; + + /* any SCTP move to queue number 1 */ + ret=rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, + RTE_ETH_FILTER_ADD, (void*)&filter); + + if ( ret !=0 ){ + rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_ctrl" + "err=%d, port=%u \n", + ret, port_id); + } +} + + +int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if){ + uint16_t hops = get_rx_check_hops(); + int i; + for (i=0; i<2; i++) { + uint8_t ttl=0xff-i-hops; + add_rules(_if,RTE_ETH_FLOW_TYPE_UDPV4,ttl); + add_rules(_if,RTE_ETH_FLOW_TYPE_TCPV4,ttl); + add_rules(_if,RTE_ETH_FLOW_TYPE_UDPV6,ttl); + add_rules(_if,RTE_ETH_FLOW_TYPE_TCPV6,ttl); + } +} + + +int CTRexExtendedDriverBase40G::configure_drop_queue(CPhyEthIF * _if){ + + add_rules(_if,RTE_ETH_FLOW_TYPE_SCTPV4,0); + return (0); +} + +void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){ + + struct rte_eth_stats stats1; + rte_eth_stats_get(_if->get_port_id(), &stats1); + + + stats->ipackets = stats1.ipackets; + stats->ibytes = stats1.ibytes; + + stats->opackets = stats1.opackets; + stats->obytes = stats1.obytes; + + stats->f_ipackets = 0; + stats->f_ibytes = 0; + + + stats->ierrors = stats1.ierrors + stats1.imissed + stats1.ibadcrc + + stats1.ibadlen + + stats1.ierrors + + stats1.oerrors + + stats1.imcasts + + stats1.rx_nombuf + + stats1.tx_pause_xon + + stats1.rx_pause_xon + + stats1.tx_pause_xoff+ + stats1.rx_pause_xoff ; + + + stats->oerrors = stats1.oerrors;; + stats->imcasts = 0; + stats->rx_nombuf = stats1.rx_nombuf; + +} + +int CTRexExtendedDriverBase40G::wait_for_stable_link(){ + delay(2000); + return (0); +} + +///////////////////////////////////////////////////////////////////// + + +void CTRexExtendedDriverBase1GVm::update_configuration(port_cfg_t * cfg){ + struct rte_eth_dev_info dev_info; + rte_eth_dev_info_get((uint8_t) 0,&dev_info); + + cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH_1G; + cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; + cfg->m_tx_conf.tx_thresh.wthresh = 0; + cfg->m_tx_conf.txq_flags=dev_info.default_txconf.txq_flags; + +} + + +int CTRexExtendedDriverBase1GVm::configure_rx_filter_rules(CPhyEthIF * _if){ + return (0); +} + +void CTRexExtendedDriverBase1GVm::clear_extended_stats(CPhyEthIF * _if){ + + rte_eth_stats_reset(_if->get_port_id()); + +} + +int CTRexExtendedDriverBase1GVm::configure_drop_queue(CPhyEthIF * _if){ + + + return (0); +} + +void CTRexExtendedDriverBase1GVm::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){ + + struct rte_eth_stats stats1; + rte_eth_stats_get(_if->get_port_id(), &stats1); + + + stats->ipackets = stats1.ipackets; + stats->ibytes = stats1.ibytes; + + stats->opackets = stats1.opackets; + stats->obytes = stats1.obytes; + + stats->f_ipackets = 0; + stats->f_ibytes = 0; + + + stats->ierrors = stats1.ierrors + stats1.imissed + stats1.ibadcrc + + stats1.ibadlen + + stats1.ierrors + + stats1.oerrors + + stats1.imcasts + + stats1.rx_nombuf + + stats1.tx_pause_xon + + stats1.rx_pause_xon + + stats1.tx_pause_xoff+ + stats1.rx_pause_xoff ; + + + stats->oerrors = stats1.oerrors;; + stats->imcasts = 0; + stats->rx_nombuf = stats1.rx_nombuf; + +} + +int CTRexExtendedDriverBase1GVm::wait_for_stable_link(){ + delay(10); + return (0); +} + + + +/** + * convert chain of mbuf to one big mbuf + * + * @param m + * + * @return + */ +struct rte_mbuf * rte_mbuf_convert_to_one_seg(struct rte_mbuf *m){ + unsigned int len; + struct rte_mbuf * r; + struct rte_mbuf * old_m; + old_m=m; + + len=rte_pktmbuf_pkt_len(m); + /* allocate one big mbuf*/ + r = CGlobalInfo::pktmbuf_alloc(0,len); + assert(r); + if (r==0) { + rte_pktmbuf_free(m); + return(r); + } + char *p=rte_pktmbuf_append(r,len); + + while ( m ) { + len = m->data_len; + assert(len); + memcpy(p,(char *)m->buf_addr, len); + p+=len; + m = m->next; + } + rte_pktmbuf_free(old_m); + return(r); +} + + |