main_dpdk.cpp revision a933bd1a
1/*
2  Hanoh Haim
3  Cisco Systems, Inc.
4*/
5
6/*
7  Copyright (c) 2015-2017 Cisco Systems, Inc.
8
9  Licensed under the Apache License, Version 2.0 (the "License");
10  you may not use this file except in compliance with the License.
11  You may obtain a copy of the License at
12
13  http://www.apache.org/licenses/LICENSE-2.0
14
15  Unless required by applicable law or agreed to in writing, software
16  distributed under the License is distributed on an "AS IS" BASIS,
17  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  See the License for the specific language governing permissions and
19  limitations under the License.
20*/
21#include <assert.h>
22#include <pthread.h>
23#include <signal.h>
24#include <pwd.h>
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
28#include <zmq.h>
29#include <rte_common.h>
30#include <rte_log.h>
31#include <rte_memory.h>
32#include <rte_memcpy.h>
33#include <rte_memzone.h>
34#include <rte_tailq.h>
35#include <rte_eal.h>
36#include <rte_per_lcore.h>
37#include <rte_launch.h>
38#include <rte_atomic.h>
39#include <rte_cycles.h>
40#include <rte_prefetch.h>
41#include <rte_lcore.h>
42#include <rte_per_lcore.h>
43#include <rte_branch_prediction.h>
44#include <rte_interrupts.h>
45#include <rte_pci.h>
46#include <rte_debug.h>
47#include <rte_ether.h>
48#include <rte_ethdev.h>
49#include <rte_ring.h>
50#include <rte_mempool.h>
51#include <rte_mbuf.h>
52#include <rte_random.h>
53#include <rte_version.h>
54#include <rte_ip.h>
55
56#include "bp_sim.h"
57#include "os_time.h"
58#include "common/arg/SimpleGlob.h"
59#include "common/arg/SimpleOpt.h"
60#include "common/basic_utils.h"
61#include "stateless/cp/trex_stateless.h"
62#include "stateless/dp/trex_stream_node.h"
63#include "stateless/messaging/trex_stateless_messaging.h"
64#include "stateless/rx/trex_stateless_rx_core.h"
65#include "publisher/trex_publisher.h"
66#include "../linux_dpdk/version.h"
67extern "C" {
68#include "dpdk/drivers/net/ixgbe/base/ixgbe_type.h"
69#include "dpdk_funcs.h"
70}
71#include "dpdk/drivers/net/e1000/base/e1000_regs.h"
72#include "global_io_mode.h"
73#include "utl_term_io.h"
74#include "msg_manager.h"
75#include "platform_cfg.h"
76#include "pre_test.h"
77#include "stateful_rx_core.h"
78#include "debug.h"
79#include "pkt_gen.h"
80#include "trex_port_attr.h"
81#include "internal_api/trex_platform_api.h"
82#include "main_dpdk.h"
83#include "trex_watchdog.h"
84
85#define RX_CHECK_MIX_SAMPLE_RATE 8
86#define RX_CHECK_MIX_SAMPLE_RATE_1G 2
87
88#define MAX_PKT_BURST   32
89
90#define BP_MAX_CORES 32
91#define BP_MAX_TX_QUEUE 16
92#define BP_MASTER_AND_LATENCY 2
93
94#define RX_DESC_NUM_DROP_Q 64
95#define RX_DESC_NUM_DATA_Q 1024
96#define RX_DESC_NUM_DROP_Q_MLX 8
97#define RX_DESC_NUM_DATA_Q_VM 512
98#define TX_DESC_NUM 512
99
100typedef struct rte_mbuf * (*rte_mbuf_convert_to_one_seg_t)(struct rte_mbuf *m);
101struct rte_mbuf *  rte_mbuf_convert_to_one_seg(struct rte_mbuf *m);
102extern "C" int rte_eth_dev_get_port_by_addr(const struct rte_pci_addr *addr, uint8_t *port_id);
103void set_driver();
104void reorder_dpdk_ports();
105
106static int max_stat_hw_id_seen = 0;
107static int max_stat_hw_id_seen_payload = 0;
108
109static inline int get_is_rx_thread_enabled() {
110    return ((CGlobalInfo::m_options.is_rx_enabled() || CGlobalInfo::m_options.is_stateless()) ?1:0);
111}
112
113struct port_cfg_t;
114
115#define MAX_DPDK_ARGS 50
116static CPlatformYamlInfo global_platform_cfg_info;
117static int global_dpdk_args_num ;
118static char * global_dpdk_args[MAX_DPDK_ARGS];
119static char global_cores_str[100];
120static char global_prefix_str[100];
121static char global_loglevel_str[20];
122static char global_master_id_str[10];
123static char global_mlx5_so_id_str[50];
124static char global_mlx4_so_id_str[50];
125static char global_image_postfix[10];
126#define TREX_NAME "_t-rex-64"
127
128class CTRexExtendedDriverBase {
129protected:
130    enum {
131        // Is there HW support for dropping packets arriving to certain queue?
132        TREX_DRV_CAP_DROP_Q = 0x1,
133        /* Does this NIC type support automatic packet dropping in case of a link down?
134           in case it is supported the packets will be dropped, else there would be a back pressure to tx queues
135           this interface is used as a workaround to let TRex work without link in stateless mode, driver that
136           does not support that will be failed at init time because it will cause watchdog due to watchdog hang */
137        TREX_DRV_CAP_DROP_PKTS_IF_LNK_DOWN = 0x2,
138        // Does the driver support changing MAC address?
139        TREX_DRV_CAP_MAC_ADDR_CHG = 0x4,
140        /* Mellanox driver does not work well with the DPDK port reorder we do */
141        TREX_DRV_CAP_NO_PORT_REORDER_POSSIBLE = 0x8,
142        // Does driver support flow control change
143        TREX_DRV_FLOW_CTRL_CHG = 0x10,
144    } trex_drv_cap;
145
146public:
147    virtual int get_min_sample_rate(void)=0;
148    virtual void update_configuration(port_cfg_t * cfg)=0;
149    virtual void update_global_config_fdir(port_cfg_t * cfg)=0;
150    virtual int configure_rx_filter_rules(CPhyEthIF * _if)=0;
151    virtual int add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint16_t l3, uint8_t l4
152                                          , uint8_t ipv6_next_h, uint16_t id) {return 0;}
153    bool is_hardware_support_drop_queue() {
154        return ((m_cap & TREX_DRV_CAP_DROP_Q) != 0);
155    }
156    bool hardware_support_mac_change() {
157        return ((m_cap & TREX_DRV_CAP_MAC_ADDR_CHG) != 0);
158    }
159    bool drop_packets_incase_of_linkdown() {
160        return ((m_cap & TREX_DRV_CAP_DROP_PKTS_IF_LNK_DOWN) != 0);
161    }
162    bool supports_port_reorder() {
163        // Since only Mellanox does not support, logic here is reveresed compared to other flags.
164        // Put this only if not supported.
165        return ((m_cap & TREX_DRV_CAP_NO_PORT_REORDER_POSSIBLE) == 0);
166    }
167    bool flow_ctrl_chg_supp() {
168        return ((m_cap & TREX_DRV_FLOW_CTRL_CHG) != 0);
169    }
170    virtual int stop_queue(CPhyEthIF * _if, uint16_t q_num);
171    void get_extended_stats_fixed(CPhyEthIF * _if, CPhyEthIFStats *stats, int fix_i, int fix_o);
172    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0;
173    virtual void clear_extended_stats(CPhyEthIF * _if)=0;
174    virtual int  wait_for_stable_link();
175    virtual void wait_after_link_up();
176    virtual bool hw_rx_stat_supported(){return false;}
177    virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes
178                             , int min, int max) {return -1;}
179    virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) {}
180    virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd) { return -1;}
181    virtual int get_stat_counters_num() {return 0;}
182    virtual int get_rx_stat_capabilities() {return 0;}
183    virtual int verify_fw_ver(int i) {return 0;}
184    virtual CFlowStatParser *get_flow_stat_parser();
185    virtual int set_rcv_all(CPhyEthIF * _if, bool set_on)=0;
186    virtual TRexPortAttr * create_port_attr(uint8_t port_id) = 0;
187
188    virtual void get_dpdk_drv_params(CTrexDpdkParams &p) {
189        p.rx_data_q_num = 1;
190        p.rx_drop_q_num = 1;
191        p.rx_desc_num_data_q = RX_DESC_NUM_DATA_Q;
192        p.rx_desc_num_drop_q = RX_DESC_NUM_DROP_Q;
193        p.tx_desc_num = TX_DESC_NUM;
194    }
195
196protected:
197    // flags describing interface capabilities
198    uint32_t m_cap;
199};
200
201
202class CTRexExtendedDriverBase1G : public CTRexExtendedDriverBase {
203
204public:
205    CTRexExtendedDriverBase1G(){
206        m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_FLOW_CTRL_CHG;
207    }
208
209    TRexPortAttr * create_port_attr(uint8_t port_id) {
210        return new DpdkTRexPortAttr(port_id, false, true);
211    }
212
213    static CTRexExtendedDriverBase * create(){
214        return ( new CTRexExtendedDriverBase1G() );
215    }
216
217    virtual void update_global_config_fdir(port_cfg_t * cfg);
218
219    virtual int get_min_sample_rate(void){
220        return ( RX_CHECK_MIX_SAMPLE_RATE_1G);
221    }
222    virtual void update_configuration(port_cfg_t * cfg);
223    virtual int stop_queue(CPhyEthIF * _if, uint16_t q_num);
224    virtual int configure_rx_filter_rules(CPhyEthIF * _if);
225    virtual int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
226    virtual int configure_rx_filter_rules_stateless(CPhyEthIF * _if);
227    virtual void clear_rx_filter_rules(CPhyEthIF * _if);
228    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
229    virtual void clear_extended_stats(CPhyEthIF * _if);
230    virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd) {return 0;}
231    virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
232    virtual int get_rx_stat_capabilities() {
233        return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
234            | TrexPlatformApi::IF_STAT_PAYLOAD;
235    }
236    virtual int wait_for_stable_link();
237    virtual void wait_after_link_up();
238    virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
239};
240
241// Base for all virtual drivers. No constructor. Should not create object from this type.
242class CTRexExtendedDriverVirtBase : public CTRexExtendedDriverBase {
243public:
244    TRexPortAttr * create_port_attr(uint8_t port_id) {
245        return new DpdkTRexPortAttr(port_id, true, true);
246    }
247    virtual void update_global_config_fdir(port_cfg_t * cfg) {}
248
249    virtual int get_min_sample_rate(void){
250        return ( RX_CHECK_MIX_SAMPLE_RATE_1G);
251    }
252    virtual void get_dpdk_drv_params(CTrexDpdkParams &p) {
253        p.rx_data_q_num = 1;
254        p.rx_drop_q_num = 0;
255        p.rx_desc_num_data_q = RX_DESC_NUM_DATA_Q_VM;
256        p.rx_desc_num_drop_q = RX_DESC_NUM_DROP_Q;
257        p.tx_desc_num = TX_DESC_NUM;
258    }
259
260    virtual void update_configuration(port_cfg_t * cfg);
261    virtual int configure_rx_filter_rules(CPhyEthIF * _if);
262    virtual int stop_queue(CPhyEthIF * _if, uint16_t q_num);
263    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0;
264    virtual void clear_extended_stats(CPhyEthIF * _if);
265    virtual int wait_for_stable_link();
266    virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
267    virtual int get_rx_stat_capabilities() {
268        return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
269            | TrexPlatformApi::IF_STAT_PAYLOAD;
270    }
271    virtual int set_rcv_all(CPhyEthIF * _if, bool set_on) {return 0;}
272    CFlowStatParser *get_flow_stat_parser();
273};
274
275class CTRexExtendedDriverVirtio : public CTRexExtendedDriverVirtBase {
276public:
277    CTRexExtendedDriverVirtio() {
278        CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE);
279        m_cap = /*TREX_DRV_CAP_DROP_Q  | TREX_DRV_CAP_MAC_ADDR_CHG */ 0;
280    }
281    static CTRexExtendedDriverBase * create(){
282        return ( new CTRexExtendedDriverVirtio() );
283    }
284    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
285};
286
287class CTRexExtendedDriverVmxnet3 : public CTRexExtendedDriverVirtBase {
288public:
289    CTRexExtendedDriverVmxnet3(){
290        CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE);
291        m_cap = /*TREX_DRV_CAP_DROP_Q  | TREX_DRV_CAP_MAC_ADDR_CHG*/0;
292    }
293
294    static CTRexExtendedDriverBase * create() {
295        return ( new CTRexExtendedDriverVmxnet3() );
296    }
297    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
298    virtual void update_configuration(port_cfg_t * cfg);
299};
300
301class CTRexExtendedDriverI40evf : public CTRexExtendedDriverVirtBase {
302public:
303    CTRexExtendedDriverI40evf(){
304        CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE);
305        m_cap = /*TREX_DRV_CAP_DROP_Q  | TREX_DRV_CAP_MAC_ADDR_CHG */ TREX_DRV_FLOW_CTRL_CHG;
306    }
307    virtual void get_extended_stats(CPhyEthIF * _if, CPhyEthIFStats *stats) {
308        get_extended_stats_fixed(_if, stats, 4, 4);
309    }
310    virtual void update_configuration(port_cfg_t * cfg);
311    static CTRexExtendedDriverBase * create() {
312        return ( new CTRexExtendedDriverI40evf() );
313    }
314};
315
316class CTRexExtendedDriverIxgbevf : public CTRexExtendedDriverI40evf {
317
318public:
319    CTRexExtendedDriverIxgbevf(){
320        CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE);
321        m_cap = /*TREX_DRV_CAP_DROP_Q  | TREX_DRV_CAP_MAC_ADDR_CHG */ TREX_DRV_FLOW_CTRL_CHG;
322    }
323    virtual void get_extended_stats(CPhyEthIF * _if, CPhyEthIFStats *stats) {
324        get_extended_stats_fixed(_if, stats, 4, 4);
325    }
326
327    static CTRexExtendedDriverBase * create() {
328        return ( new CTRexExtendedDriverIxgbevf() );
329    }
330};
331
332class CTRexExtendedDriverBaseE1000 : public CTRexExtendedDriverVirtBase {
333    CTRexExtendedDriverBaseE1000() {
334        // E1000 driver is only relevant in VM in our case
335        CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE);
336        m_cap = /*TREX_DRV_CAP_DROP_Q  | TREX_DRV_CAP_MAC_ADDR_CHG */0;
337    }
338public:
339    static CTRexExtendedDriverBase * create() {
340        return ( new CTRexExtendedDriverBaseE1000() );
341    }
342    // e1000 driver handing us packets with ethernet CRC, so we need to chop them
343    virtual void update_configuration(port_cfg_t * cfg);
344    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
345
346};
347
348class CTRexExtendedDriverBase10G : public CTRexExtendedDriverBase {
349public:
350    CTRexExtendedDriverBase10G(){
351        m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_FLOW_CTRL_CHG;
352    }
353
354    TRexPortAttr * create_port_attr(uint8_t port_id) {
355        return new DpdkTRexPortAttr(port_id, false, true);
356    }
357
358    static CTRexExtendedDriverBase * create(){
359        return ( new CTRexExtendedDriverBase10G() );
360    }
361
362    virtual void update_global_config_fdir(port_cfg_t * cfg);
363
364    virtual int get_min_sample_rate(void){
365        return (RX_CHECK_MIX_SAMPLE_RATE);
366    }
367    virtual void update_configuration(port_cfg_t * cfg);
368    virtual int configure_rx_filter_rules(CPhyEthIF * _if);
369    virtual int configure_rx_filter_rules_stateless(CPhyEthIF * _if);
370    virtual int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
371    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
372    virtual void clear_extended_stats(CPhyEthIF * _if);
373    virtual int wait_for_stable_link();
374    virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
375    virtual int get_rx_stat_capabilities() {
376        return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
377            | TrexPlatformApi::IF_STAT_PAYLOAD;
378    }
379    virtual CFlowStatParser *get_flow_stat_parser();
380    int add_del_eth_filter(CPhyEthIF * _if, bool is_add, uint16_t ethertype);
381    virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
382};
383
384class CTRexExtendedDriverBase40G : public CTRexExtendedDriverBase {
385public:
386    CTRexExtendedDriverBase40G(){
387        // Since we support only 128 counters per if, it is OK to configure here 4 statically.
388        // If we want to support more counters in case of card having less interfaces, we
389        // Will have to identify the number of interfaces dynamically.
390        m_if_per_card = 4;
391        m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_CAP_DROP_PKTS_IF_LNK_DOWN
392            | TREX_DRV_FLOW_CTRL_CHG;
393    }
394
395    TRexPortAttr * create_port_attr(uint8_t port_id) {
396        // disabling flow control on 40G using DPDK API causes the interface to malfunction
397        return new DpdkTRexPortAttr(port_id, false, false);
398    }
399
400    static CTRexExtendedDriverBase * create(){
401        return ( new CTRexExtendedDriverBase40G() );
402    }
403
404    virtual void update_global_config_fdir(port_cfg_t * cfg){
405    }
406    virtual int get_min_sample_rate(void){
407        return (RX_CHECK_MIX_SAMPLE_RATE);
408    }
409    virtual void update_configuration(port_cfg_t * cfg);
410    virtual int configure_rx_filter_rules(CPhyEthIF * _if);
411    virtual int add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint16_t l3_proto
412                                          , uint8_t l4_proto, uint8_t ipv6_next_h, uint16_t id);
413    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
414    virtual void clear_extended_stats(CPhyEthIF * _if);
415    virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len);
416    virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max);
417    virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
418    virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
419    virtual int get_rx_stat_capabilities() {
420        uint32_t ret = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
421        // HW counters on x710 does not support coutning bytes.
422        if ( CGlobalInfo::m_options.preview.get_disable_hw_flow_stat()
423             || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
424             || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
425            ret |= TrexPlatformApi::IF_STAT_RX_BYTES_COUNT;
426        }
427        return ret;
428    }
429    virtual int wait_for_stable_link();
430    virtual bool hw_rx_stat_supported(){
431        if (CGlobalInfo::m_options.preview.get_disable_hw_flow_stat()
432            || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
433            || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
434            return false;
435        } else {
436            return true;
437        }
438    }
439    virtual int verify_fw_ver(int i);
440    virtual CFlowStatParser *get_flow_stat_parser();
441    virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
442
443private:
444    virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint8_t ttl
445                               , uint16_t ip_id, uint8_t l4_proto, int queue, uint16_t stat_idx);
446    virtual int add_del_eth_type_rule(uint8_t port_id, enum rte_filter_op op, uint16_t eth_type);
447    virtual int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
448
449private:
450    uint8_t m_if_per_card;
451};
452
453class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase {
454public:
455    CTRexExtendedDriverBaseVIC(){
456        m_cap = TREX_DRV_CAP_DROP_Q  | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_FLOW_CTRL_CHG;
457    }
458
459    TRexPortAttr * create_port_attr(uint8_t port_id) {
460        return new DpdkTRexPortAttr(port_id, false, false);
461    }
462
463    static CTRexExtendedDriverBase * create(){
464        return ( new CTRexExtendedDriverBaseVIC() );
465    }
466    virtual void update_global_config_fdir(port_cfg_t * cfg){
467    }
468    void clear_extended_stats(CPhyEthIF * _if);
469    void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
470
471    virtual int get_min_sample_rate(void){
472        return (RX_CHECK_MIX_SAMPLE_RATE);
473    }
474
475    virtual int verify_fw_ver(int i);
476
477    virtual void update_configuration(port_cfg_t * cfg);
478
479    virtual int configure_rx_filter_rules(CPhyEthIF * _if);
480    virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len);
481    virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max);
482    virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
483    virtual int get_rx_stat_capabilities() {
484        return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
485    }
486    virtual CFlowStatParser *get_flow_stat_parser();
487    virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
488    virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
489
490private:
491
492    virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint16_t id
493                               , uint8_t l4_proto, uint8_t tos, int queue);
494    virtual int add_del_eth_type_rule(uint8_t port_id, enum rte_filter_op op, uint16_t eth_type);
495    virtual int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
496
497};
498
499
500class CTRexExtendedDriverBaseMlnx5G : public CTRexExtendedDriverBase {
501public:
502    CTRexExtendedDriverBaseMlnx5G(){
503        m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG
504            | TREX_DRV_CAP_NO_PORT_REORDER_POSSIBLE | TREX_DRV_FLOW_CTRL_CHG;
505        CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_MANY_DROP_Q);
506    }
507
508    TRexPortAttr * create_port_attr(uint8_t port_id) {
509        // disabling flow control on 40G using DPDK API causes the interface to malfunction
510        return new DpdkTRexPortAttr(port_id, false, false);
511    }
512
513    static CTRexExtendedDriverBase * create(){
514        return ( new CTRexExtendedDriverBaseMlnx5G() );
515    }
516
517    virtual void update_global_config_fdir(port_cfg_t * cfg){
518    }
519
520    virtual int get_min_sample_rate(void){
521        return (RX_CHECK_MIX_SAMPLE_RATE);
522    }
523    virtual void get_dpdk_drv_params(CTrexDpdkParams &p) {
524        p.rx_data_q_num = 1;
525        /* Mellanox ConnectX-4 can drop only 35MPPS per Rx queue.
526         * to workaround this issue we will create multi rx queue and enable RSS. for Queue1 we will disable RSS
527         * return zero for disable patch and rx queues number for enable.
528        */
529        p.rx_drop_q_num = 4;
530        p.rx_desc_num_data_q = RX_DESC_NUM_DATA_Q;
531        p.rx_desc_num_drop_q = RX_DESC_NUM_DROP_Q_MLX;
532        p.tx_desc_num = TX_DESC_NUM;
533    }
534    virtual void update_configuration(port_cfg_t * cfg);
535    virtual int configure_rx_filter_rules(CPhyEthIF * _if);
536    virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
537    virtual void clear_extended_stats(CPhyEthIF * _if);
538    virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len);
539    virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max);
540    virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
541    virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
542    virtual int get_rx_stat_capabilities() {
543        return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
544    }
545    virtual int wait_for_stable_link();
546    // disabling flow control on 40G using DPDK API causes the interface to malfunction
547    virtual bool flow_control_disable_supported(){return false;}
548    virtual CFlowStatParser *get_flow_stat_parser();
549    virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
550
551private:
552    virtual void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint16_t ip_id, uint8_t l4_proto
553                               , int queue);
554    virtual int add_del_rx_filter_rules(CPhyEthIF * _if, bool set_on);
555};
556
557typedef CTRexExtendedDriverBase * (*create_object_t) (void);
558
559
560class CTRexExtendedDriverRec {
561public:
562    std::string         m_driver_name;
563    create_object_t     m_constructor;
564};
565
566class CTRexExtendedDriverDb {
567public:
568
569    const std::string & get_driver_name() {
570        return m_driver_name;
571    }
572
573    bool is_driver_exists(std::string name);
574
575
576
577    void set_driver_name(std::string name){
578        m_driver_was_set=true;
579        m_driver_name=name;
580        printf(" set driver name %s \n",name.c_str());
581        m_drv=create_driver(m_driver_name);
582        assert(m_drv);
583    }
584
585    CTRexExtendedDriverBase * get_drv(){
586        if (!m_driver_was_set) {
587            printf(" ERROR too early to use this object !\n");
588            printf(" need to set the right driver \n");
589            assert(0);
590        }
591        assert(m_drv);
592        return (m_drv);
593    }
594
595public:
596
597    static CTRexExtendedDriverDb * Ins();
598
599private:
600    CTRexExtendedDriverBase * create_driver(std::string name);
601
602    CTRexExtendedDriverDb(){
603        register_driver(std::string("net_ixgbe"),CTRexExtendedDriverBase10G::create);
604        register_driver(std::string("net_e1000_igb"),CTRexExtendedDriverBase1G::create);
605        register_driver(std::string("net_i40e"),CTRexExtendedDriverBase40G::create);
606        register_driver(std::string("net_enic"),CTRexExtendedDriverBaseVIC::create);
607        register_driver(std::string("net_mlx5"),CTRexExtendedDriverBaseMlnx5G::create);
608
609        /* virtual devices */
610        register_driver(std::string("net_e1000_em"), CTRexExtendedDriverBaseE1000::create);
611        register_driver(std::string("net_vmxnet3"), CTRexExtendedDriverVmxnet3::create);
612        register_driver(std::string("net_virtio"), CTRexExtendedDriverVirtio::create);
613        register_driver(std::string("net_i40e_vf"), CTRexExtendedDriverI40evf::create);
614        register_driver(std::string("net_ixgbe_vf"), CTRexExtendedDriverIxgbevf::create);
615
616        m_driver_was_set=false;
617        m_drv=0;
618        m_driver_name="";
619    }
620    void register_driver(std::string name,create_object_t func);
621    static CTRexExtendedDriverDb * m_ins;
622    bool        m_driver_was_set;
623    std::string m_driver_name;
624    CTRexExtendedDriverBase * m_drv;
625    std::vector <CTRexExtendedDriverRec*>     m_list;
626
627};
628
629CTRexExtendedDriverDb * CTRexExtendedDriverDb::m_ins;
630
631
632void CTRexExtendedDriverDb::register_driver(std::string name,
633                                            create_object_t func){
634    CTRexExtendedDriverRec * rec;
635    rec = new CTRexExtendedDriverRec();
636    rec->m_driver_name=name;
637    rec->m_constructor=func;
638    m_list.push_back(rec);
639}
640
641
642bool CTRexExtendedDriverDb::is_driver_exists(std::string name){
643    int i;
644    for (i=0; i<(int)m_list.size(); i++) {
645        if (m_list[i]->m_driver_name == name) {
646            return (true);
647        }
648    }
649    return (false);
650}
651
652
653CTRexExtendedDriverBase * CTRexExtendedDriverDb::create_driver(std::string name){
654    int i;
655    for (i=0; i<(int)m_list.size(); i++) {
656        if (m_list[i]->m_driver_name == name) {
657            return ( m_list[i]->m_constructor() );
658        }
659    }
660    return( (CTRexExtendedDriverBase *)0);
661}
662
663
664
665CTRexExtendedDriverDb * CTRexExtendedDriverDb::Ins(){
666    if (!m_ins) {
667        m_ins = new CTRexExtendedDriverDb();
668    }
669    return (m_ins);
670}
671
672static CTRexExtendedDriverBase *  get_ex_drv(){
673
674    return ( CTRexExtendedDriverDb::Ins()->get_drv());
675}
676
677static inline int get_min_sample_rate(void){
678    return ( get_ex_drv()->get_min_sample_rate());
679}
680
681// cores =0==1,1*2,2,3,4,5,6
682// An enum for all the option types
683enum { OPT_HELP,
684       OPT_MODE_BATCH,
685       OPT_MODE_INTERACTIVE,
686       OPT_NODE_DUMP,
687       OPT_DUMP_INTERFACES,
688       OPT_UT,
689       OPT_CORES,
690       OPT_SINGLE_CORE,
691       OPT_FLIP_CLIENT_SERVER,
692       OPT_FLOW_FLIP_CLIENT_SERVER,
693       OPT_FLOW_FLIP_CLIENT_SERVER_SIDE,
694       OPT_RATE_MULT,
695       OPT_DURATION,
696       OPT_PLATFORM_FACTOR,
697       OPT_PUB_DISABLE,
698       OPT_LIMT_NUM_OF_PORTS,
699       OPT_PLAT_CFG_FILE,
700       OPT_MBUF_FACTOR,
701       OPT_LATENCY,
702       OPT_NO_CLEAN_FLOW_CLOSE,
703       OPT_LATENCY_MASK,
704       OPT_ONLY_LATENCY,
705       OPT_LATENCY_PREVIEW ,
706       OPT_WAIT_BEFORE_TRAFFIC,
707       OPT_PCAP,
708       OPT_RX_CHECK,
709       OPT_IO_MODE,
710       OPT_IPV6,
711       OPT_LEARN,
712       OPT_LEARN_MODE,
713       OPT_LEARN_VERIFY,
714       OPT_L_PKT_MODE,
715       OPT_NO_FLOW_CONTROL,
716       OPT_NO_HW_FLOW_STAT,
717       OPT_X710_RESET_THRESHOLD,
718       OPT_VLAN,
719       OPT_RX_CHECK_HOPS,
720       OPT_CLIENT_CFG_FILE,
721       OPT_NO_KEYBOARD_INPUT,
722       OPT_VIRT_ONE_TX_RX_QUEUE,
723       OPT_PREFIX,
724       OPT_SEND_DEBUG_PKT,
725       OPT_NO_WATCHDOG,
726       OPT_ALLOW_COREDUMP,
727       OPT_CHECKSUM_OFFLOAD,
728       OPT_CLOSE,
729       OPT_ARP_REF_PER,
730       OPT_NO_OFED_CHECK,
731       OPT_NO_SCAPY_SERVER,
732       OPT_ACTIVE_FLOW,
733       OPT_RT,
734       OPT_MLX4_SO,
735       OPT_MLX5_SO
736};
737
738/* these are the argument types:
739   SO_NONE --    no argument needed
740   SO_REQ_SEP -- single required argument
741   SO_MULTI --   multiple arguments needed
742*/
743static CSimpleOpt::SOption parser_options[] =
744    {
745        { OPT_HELP,                   "-?",                SO_NONE    },
746        { OPT_HELP,                   "-h",                SO_NONE    },
747        { OPT_HELP,                   "--help",            SO_NONE    },
748        { OPT_UT,                     "--ut",              SO_NONE    },
749        { OPT_MODE_BATCH,             "-f",                SO_REQ_SEP },
750        { OPT_MODE_INTERACTIVE,       "-i",                SO_NONE    },
751        { OPT_PLAT_CFG_FILE,          "--cfg",             SO_REQ_SEP },
752        { OPT_SINGLE_CORE,            "-s",                SO_NONE    },
753        { OPT_FLIP_CLIENT_SERVER,     "--flip",            SO_NONE    },
754        { OPT_FLOW_FLIP_CLIENT_SERVER,"-p",                SO_NONE    },
755        { OPT_FLOW_FLIP_CLIENT_SERVER_SIDE, "-e",          SO_NONE    },
756        { OPT_NO_CLEAN_FLOW_CLOSE,    "--nc",              SO_NONE    },
757        { OPT_LIMT_NUM_OF_PORTS,      "--limit-ports",     SO_REQ_SEP },
758        { OPT_CORES,                  "-c",                SO_REQ_SEP },
759        { OPT_NODE_DUMP,              "-v",                SO_REQ_SEP },
760        { OPT_DUMP_INTERFACES,        "--dump-interfaces", SO_MULTI   },
761        { OPT_LATENCY,                "-l",                SO_REQ_SEP },
762        { OPT_DURATION,               "-d",                SO_REQ_SEP },
763        { OPT_PLATFORM_FACTOR,        "-pm",               SO_REQ_SEP },
764        { OPT_PUB_DISABLE,            "-pubd",             SO_NONE    },
765        { OPT_RATE_MULT,              "-m",                SO_REQ_SEP },
766        { OPT_LATENCY_MASK,           "--lm",              SO_REQ_SEP },
767        { OPT_ONLY_LATENCY,           "--lo",              SO_NONE    },
768        { OPT_LATENCY_PREVIEW,        "-k",                SO_REQ_SEP },
769        { OPT_WAIT_BEFORE_TRAFFIC,    "-w",                SO_REQ_SEP },
770        { OPT_PCAP,                   "--pcap",            SO_NONE    },
771        { OPT_RX_CHECK,               "--rx-check",        SO_REQ_SEP },
772        { OPT_IO_MODE,                "--iom",             SO_REQ_SEP },
773        { OPT_RX_CHECK_HOPS,          "--hops",            SO_REQ_SEP },
774        { OPT_IPV6,                   "--ipv6",            SO_NONE    },
775        { OPT_LEARN,                  "--learn",           SO_NONE    },
776        { OPT_LEARN_MODE,             "--learn-mode",      SO_REQ_SEP },
777        { OPT_LEARN_VERIFY,           "--learn-verify",    SO_NONE    },
778        { OPT_L_PKT_MODE,             "--l-pkt-mode",      SO_REQ_SEP },
779        { OPT_NO_FLOW_CONTROL,        "--no-flow-control-change", SO_NONE },
780        { OPT_NO_HW_FLOW_STAT,        "--no-hw-flow-stat", SO_NONE },
781        { OPT_X710_RESET_THRESHOLD,   "--x710-reset-threshold", SO_REQ_SEP },
782        { OPT_VLAN,                   "--vlan",            SO_NONE    },
783        { OPT_CLIENT_CFG_FILE,        "--client_cfg",      SO_REQ_SEP },
784        { OPT_CLIENT_CFG_FILE,        "--client-cfg",      SO_REQ_SEP },
785        { OPT_NO_KEYBOARD_INPUT,      "--no-key",          SO_NONE    },
786        { OPT_VIRT_ONE_TX_RX_QUEUE,   "--software",        SO_NONE    },
787        { OPT_PREFIX,                 "--prefix",          SO_REQ_SEP },
788        { OPT_SEND_DEBUG_PKT,         "--send-debug-pkt",  SO_REQ_SEP },
789        { OPT_MBUF_FACTOR,            "--mbuf-factor",     SO_REQ_SEP },
790        { OPT_NO_WATCHDOG,            "--no-watchdog",     SO_NONE    },
791        { OPT_ALLOW_COREDUMP,         "--allow-coredump",  SO_NONE    },
792        { OPT_CHECKSUM_OFFLOAD,       "--checksum-offload", SO_NONE   },
793        { OPT_ACTIVE_FLOW,            "--active-flows",   SO_REQ_SEP  },
794        { OPT_MLX5_SO,                "--mlx5-so", SO_NONE    },
795        { OPT_MLX4_SO,                "--mlx4-so", SO_NONE    },
796        { OPT_CLOSE,                  "--close-at-end",    SO_NONE    },
797        { OPT_ARP_REF_PER,            "--arp-refresh-period", SO_REQ_SEP },
798        { OPT_NO_OFED_CHECK,          "--no-ofed-check",   SO_NONE    },
799        { OPT_NO_SCAPY_SERVER,        "--no-scapy-server", SO_NONE    },
800        { OPT_RT,                     "--rt",              SO_NONE    },
801        SO_END_OF_OPTIONS
802    };
803
804static int usage(){
805
806    printf(" Usage: t-rex-64 [mode] <options>\n\n");
807    printf(" mode is one of:\n");
808    printf("   -f <file> : YAML file with traffic template configuration (Will run TRex in 'stateful' mode)\n");
809    printf("   -i        : Run TRex in 'stateless' mode\n");
810    printf("\n");
811
812    printf(" Available options are:\n");
813    printf(" --active-flows             : An experimental switch to scale up or down the number of active flows.  \n");
814    printf("                              It is not accurate due to the quantization of flow scheduler and in some case does not work. \n");
815    printf("                              Example --active-flows 500000 wil set the ballpark of the active flow to be ~0.5M \n");
816    printf(" --allow-coredump           : Allow creation of core dump \n");
817    printf(" --arp-refresh-period       : Period in seconds between sending of gratuitous ARP for our addresses. Value of 0 means 'never send' \n");
818    printf(" -c <num>>                  : Number of hardware threads to allocate for each port pair. Overrides the 'c' argument from config file \n");
819    printf(" --cfg <file>               : Use file as TRex config file instead of the default /etc/trex_cfg.yaml \n");
820    printf(" --checksum-offload         : Enable IP, TCP and UDP tx checksum offloading, using DPDK. This requires all used interfaces to support this \n");
821    printf(" --client_cfg <file>        : YAML file describing clients configuration \n");
822    printf(" --close-at-end             : Call rte_eth_dev_stop and close at exit. Calling these functions caused link down issues in older versions, \n");
823    printf("                               so we do not call them by default for now. Leaving this as option in case someone thinks it is helpful for him \n");
824    printf("                               This it temporary option. Will be removed in the future \n");
825    printf(" -d                         : Duration of the test in sec (default is 3600). Look also at --nc \n");
826    printf(" -e                         : Like -p but src/dst IP will be chosen according to the port (i.e. on client port send all packets with client src and server dest, and vice versa on server port \n");
827    printf(" --flip                     : Each flow will be sent both from client to server and server to client. This can acheive better port utilization when flow traffic is asymmetric \n");
828    printf(" --hops <hops>              : If rx check is enabled, the hop number can be assigned. See manual for details \n");
829    printf(" --iom  <mode>              : IO mode  for server output [0- silent, 1- normal , 2- short] \n");
830    printf(" --ipv6                     : Work in ipv6 mode \n");
831    printf(" -k  <num>                  : Run 'warm up' traffic for num seconds before starting the test. \n");
832    printf(" -l <rate>                  : In parallel to the test, run latency check, sending packets at rate/sec from each interface \n");
833    printf(" --l-pkt-mode <0-3>         : Set mode for sending latency packets \n");
834    printf("      0 (default)    send SCTP packets  \n");
835    printf("      1              Send ICMP request packets  \n");
836    printf("      2              Send ICMP requests from client side, and response from server side (for working with firewall) \n");
837    printf("      3              Send ICMP requests with sequence ID 0 from both sides \n");
838    printf("    Rate of zero means no latency check \n");
839    printf(" --learn (deprecated). Replaced by --learn-mode. To get older behaviour, use --learn-mode 2 \n");
840    printf(" --learn-mode [1-3]         : Used for working in NAT environments. Dynamically learn the NAT translation done by the DUT \n");
841    printf("      1    In case of TCP flow, use TCP ACK in first SYN to pass NAT translation information. Initial SYN packet must be first packet in the TCP flow \n");
842    printf("           In case of UDP stream, NAT translation information will pass in IP ID field of first packet in flow. This means that this field is changed by TRex\n");
843    printf("      2    Add special IP option to pass NAT translation information to first packet of each flow. Will not work on certain firewalls if they drop packets with IP options \n");
844    printf("      3    Like 1, but without support for sequence number randomization in server->client direction. Performance (flow/second) better than 1 \n");
845    printf(" --learn-verify             : Test the NAT translation mechanism. Should be used when there is no NAT in the setup \n");
846    printf(" --limit-ports              : Limit number of ports used. Must be even number (TRex always uses port pairs) \n");
847    printf(" --lm                       : Hex mask of cores that should send traffic \n");
848    printf("    For example: Value of 0x5 will cause only ports 0 and 2 to send traffic \n");
849    printf(" --lo                       : Only run latency test \n");
850    printf(" -m <num>                   : Rate multiplier.  Multiply basic rate of templates by this number \n");
851    printf(" --mbuf-factor              : Factor for packet memory \n");
852    printf(" --nc                       : If set, will not wait for all flows to be closed, before terminating - see manual for more information \n");
853    printf(" --no-flow-control-change   : By default TRex disables flow-control. If this option is given, it does not touch it \n");
854    printf(" --no-hw-flow-stat          : Relevant only for Intel x710 stateless mode. Do not use HW counters for flow stats\n");
855    printf("                            : Enabling this will support lower traffic rate, but will also report RX byte count statistics. See manual for more details\n");
856    printf(" --no-key                   : Daemon mode, don't get input from keyboard \n");
857    printf(" --no-ofed-check            : Disable the check of OFED version \n");
858    printf(" --no-scapy-server          : Disable Scapy server implicit start at stateless \n");
859    printf(" --no-watchdog              : Disable watchdog \n");
860    printf(" --rt                       : Run TRex DP/RX cores in realtime priority \n");
861    printf(" -p                         : Send all flow packets from the same interface (choosed randomly between client ad server ports) without changing their src/dst IP \n");
862    printf(" -pm                        : Platform factor. If you have splitter in the setup, you can multiply the total results by this factor \n");
863    printf("    e.g --pm 2.0 will multiply all the results bps in this factor \n");
864    printf(" --prefix <nam>             : For running multi TRex instances on the same machine. Each instance should have different name \n");
865    printf(" -pubd                      : Disable monitors publishers \n");
866    printf(" --rx-check  <rate>         : Enable rx check. TRex will sample flows at 1/rate and check order, latency and more \n");
867    printf(" -s                         : Single core. Run only one data path core. For debug \n");
868    printf(" --send-debug-pkt <proto>   : Do not run traffic generator. Just send debug packet and dump receive queues \n");
869    printf("    Supported protocols are 1 for icmp, 2 for UDP, 3 for TCP, 4 for ARP, 5 for 9K UDP \n");
870    printf(" --software                 : Do not configure any hardare rules. In this mode we used 1 core, and one RX queue and one TX queue per port\n");
871    printf(" -v <verbosity level>       : The higher the value, print more debug information \n");
872    printf(" --vlan                     : Relevant only for stateless mode with Intel 82599 10G NIC \n");
873    printf("                              When configuring flow stat and latency per stream rules, assume all streams uses VLAN \n");
874    printf(" -w  <num>                  : Wait num seconds between init of interfaces and sending traffic, default is 1 \n");
875
876    printf("\n");
877    printf(" Examples: ");
878    printf(" basic trex run for 20 sec and multiplier of 10 \n");
879    printf("  t-rex-64 -f cap2/dns.yaml -m 10 -d 20 \n");
880    printf("\n\n");
881    printf(" Copyright (c) 2015-2017 Cisco Systems, Inc.    \n");
882    printf("                                                                  \n");
883    printf(" Licensed under the Apache License, Version 2.0 (the 'License') \n");
884    printf(" you may not use this file except in compliance with the License. \n");
885    printf(" You may obtain a copy of the License at                          \n");
886    printf("                                                                  \n");
887    printf("    http://www.apache.org/licenses/LICENSE-2.0                    \n");
888    printf("                                                                  \n");
889    printf(" Unless required by applicable law or agreed to in writing, software \n");
890    printf(" distributed under the License is distributed on an \"AS IS\" BASIS,   \n");
891    printf(" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n");
892    printf(" See the License for the specific language governing permissions and      \n");
893    printf(" limitations under the License.                                           \n");
894    printf(" \n");
895    printf(" Open Source Components / Libraries \n");
896    printf(" DPDK       (BSD)       \n");
897    printf(" YAML-CPP   (BSD)       \n");
898    printf(" JSONCPP    (MIT)       \n");
899    printf(" \n");
900    printf(" Open Source Binaries \n");
901    printf(" ZMQ        (LGPL v3plus) \n");
902    printf(" \n");
903    printf(" Version : %s   \n",VERSION_BUILD_NUM);
904    printf(" DPDK version : %s   \n",rte_version());
905    printf(" User    : %s   \n",VERSION_USER);
906    printf(" Date    : %s , %s \n",get_build_date(),get_build_time());
907    printf(" Uuid    : %s    \n",VERSION_UIID);
908    printf(" Git SHA : %s    \n",VERSION_GIT_SHA);
909    return (0);
910}
911
912
913int gtest_main(int argc, char **argv) ;
914
915static void parse_err(const std::string &msg) {
916    std::cout << "\nArgument Parsing Error: \n\n" << "*** "<< msg << "\n\n";
917    exit(-1);
918}
919
920static int parse_options(int argc, char *argv[], CParserOption* po, bool first_time ) {
921    CSimpleOpt args(argc, argv, parser_options);
922
923    bool latency_was_set=false;
924    (void)latency_was_set;
925    char ** rgpszArg = NULL;
926    bool opt_vlan_was_set = false;
927
928    int a=0;
929    int node_dump=0;
930
931    po->preview.setFileWrite(true);
932    po->preview.setRealTime(true);
933    uint32_t tmp_data;
934    float tmp_double;
935
936    po->m_run_mode = CParserOption::RUN_MODE_INVALID;
937
938    while ( args.Next() ){
939        if (args.LastError() == SO_SUCCESS) {
940            switch (args.OptionId()) {
941
942            case OPT_UT :
943                parse_err("Supported only in simulation");
944                break;
945
946            case OPT_HELP:
947                usage();
948                return -1;
949
950            case OPT_MODE_BATCH:
951                if (po->m_run_mode != CParserOption::RUN_MODE_INVALID) {
952                    parse_err("Please specify single run mode");
953                }
954                po->m_run_mode = CParserOption::RUN_MODE_BATCH;
955                po->cfg_file = args.OptionArg();
956                break;
957
958            case OPT_MODE_INTERACTIVE:
959                if (po->m_run_mode != CParserOption::RUN_MODE_INVALID) {
960                    parse_err("Please specify single run mode");
961                }
962                po->m_run_mode = CParserOption::RUN_MODE_INTERACTIVE;
963                break;
964
965            case OPT_NO_KEYBOARD_INPUT  :
966                po->preview.set_no_keyboard(true);
967                break;
968
969            case OPT_CLIENT_CFG_FILE :
970                po->client_cfg_file = args.OptionArg();
971                break;
972
973            case OPT_PLAT_CFG_FILE :
974                po->platform_cfg_file = args.OptionArg();
975                break;
976
977            case OPT_SINGLE_CORE :
978                po->preview.setSingleCore(true);
979                break;
980
981            case OPT_IPV6:
982                po->preview.set_ipv6_mode_enable(true);
983                break;
984
985            case OPT_RT:
986                po->preview.set_rt_prio_mode(true);
987                break;
988
989            case OPT_MLX5_SO:
990                po->preview.set_mlx5_so_mode(true);
991                break;
992
993            case OPT_MLX4_SO:
994                po->preview.set_mlx4_so_mode(true);
995                break;
996
997            case OPT_LEARN :
998                po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
999                break;
1000
1001            case OPT_LEARN_MODE :
1002                sscanf(args.OptionArg(),"%d", &tmp_data);
1003                if (! po->is_valid_opt_val(tmp_data, CParserOption::LEARN_MODE_DISABLED, CParserOption::LEARN_MODE_MAX, "--learn-mode")) {
1004                    exit(-1);
1005                }
1006                po->m_learn_mode = (uint8_t)tmp_data;
1007                break;
1008
1009            case OPT_LEARN_VERIFY :
1010                // must configure learn_mode for learn verify to work. If different learn mode will be given later, it will be set instead.
1011                if (po->m_learn_mode == 0) {
1012                    po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
1013                }
1014                po->preview.set_learn_and_verify_mode_enable(true);
1015                break;
1016
1017            case OPT_L_PKT_MODE :
1018                sscanf(args.OptionArg(),"%d", &tmp_data);
1019                if (! po->is_valid_opt_val(tmp_data, 0, L_PKT_SUBMODE_0_SEQ, "--l-pkt-mode")) {
1020                    exit(-1);
1021                }
1022                po->m_l_pkt_mode=(uint8_t)tmp_data;
1023                break;
1024
1025            case OPT_NO_HW_FLOW_STAT:
1026                po->preview.set_disable_hw_flow_stat(true);
1027                break;
1028            case OPT_NO_FLOW_CONTROL:
1029                po->preview.set_disable_flow_control_setting(true);
1030                break;
1031            case OPT_X710_RESET_THRESHOLD:
1032                po->set_x710_fdir_reset_threshold(atoi(args.OptionArg()));
1033                break;
1034            case OPT_VLAN:
1035                opt_vlan_was_set = true;
1036                break;
1037            case OPT_LIMT_NUM_OF_PORTS :
1038                po->m_expected_portd =atoi(args.OptionArg());
1039                break;
1040            case  OPT_CORES  :
1041                po->preview.setCores(atoi(args.OptionArg()));
1042                break;
1043            case OPT_FLIP_CLIENT_SERVER :
1044                po->preview.setClientServerFlip(true);
1045                break;
1046            case OPT_NO_CLEAN_FLOW_CLOSE :
1047                po->preview.setNoCleanFlowClose(true);
1048                break;
1049            case OPT_FLOW_FLIP_CLIENT_SERVER :
1050                po->preview.setClientServerFlowFlip(true);
1051                break;
1052            case OPT_FLOW_FLIP_CLIENT_SERVER_SIDE:
1053                po->preview.setClientServerFlowFlipAddr(true);
1054                break;
1055            case OPT_NODE_DUMP:
1056                a=atoi(args.OptionArg());
1057                node_dump=1;
1058                po->preview.setFileWrite(false);
1059                break;
1060            case OPT_DUMP_INTERFACES:
1061                if (first_time) {
1062                    rgpszArg = args.MultiArg(1);
1063                    while (rgpszArg != NULL) {
1064                        po->dump_interfaces.push_back(rgpszArg[0]);
1065                        rgpszArg = args.MultiArg(1);
1066                    }
1067                }
1068                if (po->m_run_mode != CParserOption::RUN_MODE_INVALID) {
1069                    parse_err("Please specify single run mode (-i for stateless, or -f <file> for stateful");
1070                }
1071                po->m_run_mode = CParserOption::RUN_MODE_DUMP_INFO;
1072                break;
1073            case OPT_MBUF_FACTOR:
1074                sscanf(args.OptionArg(),"%f", &po->m_mbuf_factor);
1075                break;
1076            case OPT_RATE_MULT :
1077                sscanf(args.OptionArg(),"%f", &po->m_factor);
1078                break;
1079            case OPT_DURATION :
1080                sscanf(args.OptionArg(),"%f", &po->m_duration);
1081                break;
1082            case OPT_PUB_DISABLE:
1083                po->preview.set_zmq_publish_enable(false);
1084                break;
1085            case OPT_PLATFORM_FACTOR:
1086                sscanf(args.OptionArg(),"%f", &po->m_platform_factor);
1087                break;
1088            case OPT_LATENCY :
1089                latency_was_set=true;
1090                sscanf(args.OptionArg(),"%d", &po->m_latency_rate);
1091                break;
1092            case OPT_LATENCY_MASK :
1093                sscanf(args.OptionArg(),"%x", &po->m_latency_mask);
1094                break;
1095            case OPT_ONLY_LATENCY :
1096                po->preview.setOnlyLatency(true);
1097                break;
1098            case OPT_NO_WATCHDOG :
1099                po->preview.setWDDisable(true);
1100                break;
1101            case OPT_ALLOW_COREDUMP :
1102                po->preview.setCoreDumpEnable(true);
1103                break;
1104            case  OPT_LATENCY_PREVIEW :
1105                sscanf(args.OptionArg(),"%d", &po->m_latency_prev);
1106                break;
1107            case  OPT_WAIT_BEFORE_TRAFFIC :
1108                sscanf(args.OptionArg(),"%d", &po->m_wait_before_traffic);
1109                break;
1110            case OPT_PCAP:
1111                po->preview.set_pcap_mode_enable(true);
1112                break;
1113            case OPT_ACTIVE_FLOW:
1114                sscanf(args.OptionArg(),"%f", &tmp_double);
1115                po->m_active_flows=(uint32_t)tmp_double;
1116                break;
1117            case OPT_RX_CHECK :
1118                sscanf(args.OptionArg(),"%d", &tmp_data);
1119                po->m_rx_check_sample=(uint16_t)tmp_data;
1120                po->preview.set_rx_check_enable(true);
1121                break;
1122            case OPT_RX_CHECK_HOPS :
1123                sscanf(args.OptionArg(),"%d", &tmp_data);
1124                po->m_rx_check_hops = (uint16_t)tmp_data;
1125                break;
1126            case OPT_IO_MODE :
1127                sscanf(args.OptionArg(),"%d", &tmp_data);
1128                po->m_io_mode=(uint16_t)tmp_data;
1129                break;
1130
1131            case OPT_VIRT_ONE_TX_RX_QUEUE:
1132                CGlobalInfo::set_queues_mode(CGlobalInfo::Q_MODE_ONE_QUEUE);
1133                po->preview.setCores(1); // Only one TX core supported in software mode currently
1134                break;
1135
1136            case OPT_PREFIX:
1137                po->prefix = args.OptionArg();
1138                break;
1139
1140            case OPT_SEND_DEBUG_PKT:
1141                sscanf(args.OptionArg(),"%d", &tmp_data);
1142                po->m_debug_pkt_proto = (uint8_t)tmp_data;
1143                break;
1144
1145            case OPT_CHECKSUM_OFFLOAD:
1146                po->preview.setChecksumOffloadEnable(true);
1147                break;
1148
1149            case OPT_CLOSE:
1150                po->preview.setCloseEnable(true);
1151                break;
1152            case  OPT_ARP_REF_PER:
1153                sscanf(args.OptionArg(),"%d", &tmp_data);
1154                po->m_arp_ref_per=(uint16_t)tmp_data;
1155                break;
1156            case OPT_NO_OFED_CHECK:
1157                break;
1158            case OPT_NO_SCAPY_SERVER:
1159                break;
1160
1161            default:
1162                printf("Error: option %s is not handled.\n\n", args.OptionText());
1163                return -1;
1164                break;
1165            } // End of switch
1166        }// End of IF
1167        else {
1168            if (args.LastError() == SO_OPT_INVALID) {
1169                printf("Error: option %s is not recognized.\n\n", args.OptionText());
1170            } else if (args.LastError() == SO_ARG_MISSING) {
1171                printf("Error: option %s is expected to have argument.\n\n", args.OptionText());
1172            }
1173            usage();
1174            return -1;
1175        }
1176    } // End of while
1177
1178
1179    if ((po->m_run_mode ==  CParserOption::RUN_MODE_INVALID) ) {
1180        parse_err("Please provide single run mode. -f <file> for stateful or -i for stateless (interactive)");
1181    }
1182
1183    if (CGlobalInfo::is_learn_mode() && po->preview.get_ipv6_mode_enable()) {
1184        parse_err("--learn mode is not supported with --ipv6, beacuse there is no such thing as NAT66 (ipv6 to ipv6 translation) \n" \
1185                  "If you think it is important, please open a defect or write to TRex mailing list\n");
1186    }
1187
1188    if (po->preview.get_is_rx_check_enable() ||  po->is_latency_enabled() || CGlobalInfo::is_learn_mode()
1189        || (CGlobalInfo::m_options.m_arp_ref_per != 0)
1190        || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
1191        || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
1192        po->set_rx_enabled();
1193    }
1194
1195    if ( node_dump ){
1196        po->preview.setVMode(a);
1197    }
1198
1199    /* if we have a platform factor we need to devided by it so we can still work with normalized yaml profile  */
1200    po->m_factor = po->m_factor/po->m_platform_factor;
1201
1202    uint32_t cores=po->preview.getCores();
1203    if ( cores > ((BP_MAX_CORES)/2-1) ) {
1204        fprintf(stderr, " Error: maximum supported core number is: %d \n",((BP_MAX_CORES)/2-1));
1205        return -1;
1206    }
1207
1208
1209    if ( first_time ){
1210        /* only first time read the configuration file */
1211        if ( po->platform_cfg_file.length() >0  ) {
1212            if ( node_dump ){
1213                printf("Using configuration file %s \n",po->platform_cfg_file.c_str());
1214            }
1215            global_platform_cfg_info.load_from_yaml_file(po->platform_cfg_file);
1216            if ( node_dump ){
1217                global_platform_cfg_info.Dump(stdout);
1218            }
1219        }else{
1220            if ( utl_is_file_exists("/etc/trex_cfg.yaml") ){
1221                if ( node_dump ){
1222                    printf("Using configuration file /etc/trex_cfg.yaml \n");
1223                }
1224                global_platform_cfg_info.load_from_yaml_file("/etc/trex_cfg.yaml");
1225                if ( node_dump ){
1226                    global_platform_cfg_info.Dump(stdout);
1227                }
1228            }
1229        }
1230    }
1231
1232    if ( get_is_stateless() ) {
1233        if ( opt_vlan_was_set ) {
1234            // Only purpose of this in stateless is for configuring the 82599 rules correctly
1235            po->preview.set_vlan_mode(CPreviewMode::VLAN_MODE_NORMAL);
1236        }
1237        if (CGlobalInfo::m_options.client_cfg_file != "") {
1238            parse_err("Client config file is not supported with interactive (stateless) mode ");
1239        }
1240        if ( po->m_duration ) {
1241            parse_err("Duration is not supported with interactive (stateless) mode ");
1242        }
1243
1244        if ( po->preview.get_is_rx_check_enable() ) {
1245            parse_err("Rx check is not supported with interactive (stateless) mode ");
1246        }
1247
1248        if  ( (po->is_latency_enabled()) || (po->preview.getOnlyLatency()) ){
1249            parse_err("Latency check is not supported with interactive (stateless) mode ");
1250        }
1251
1252        if ( po->preview.getSingleCore() ){
1253            parse_err("Single core is not supported with interactive (stateless) mode ");
1254        }
1255
1256    } else {
1257        if ( !po->m_duration ) {
1258            po->m_duration = 3600.0;
1259        }
1260        if ( global_platform_cfg_info.m_tw.m_info_exist ){
1261
1262            CTimerWheelYamlInfo *lp=&global_platform_cfg_info.m_tw;
1263            std::string  err;
1264            if (!lp->Verify(err)){
1265                parse_err(err);
1266            }
1267
1268            po->set_tw_bucket_time_in_usec(lp->m_bucket_time_usec);
1269            po->set_tw_buckets(lp->m_buckets);
1270            po->set_tw_levels(lp->m_levels);
1271        }
1272    }
1273
1274    return 0;
1275}
1276
1277static int parse_options_wrapper(int argc, char *argv[], CParserOption* po, bool first_time ) {
1278    // copy, as arg parser sometimes changes the argv
1279    char ** argv_copy = (char **) malloc(sizeof(char *) * argc);
1280    for(int i=0; i<argc; i++) {
1281        argv_copy[i] = strdup(argv[i]);
1282    }
1283    int ret = parse_options(argc, argv_copy, po, first_time);
1284
1285    // free
1286    for(int i=0; i<argc; i++) {
1287        free(argv_copy[i]);
1288    }
1289    free(argv_copy);
1290    return ret;
1291}
1292
1293int main_test(int argc , char * argv[]);
1294
1295
1296#define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
1297#define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
1298#define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
1299
1300/*
1301 * These default values are optimized for use with the Intel(R) 82599 10 GbE
1302 * Controller and the DPDK ixgbe PMD. Consider using other values for other
1303 * network controllers and/or network drivers.
1304 */
1305#define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
1306#define TX_HTHRESH 0  /**< Default values of TX host threshold reg. */
1307#define TX_WTHRESH 0  /**< Default values of TX write-back threshold reg. */
1308
1309#define TX_WTHRESH_1G 1  /**< Default values of TX write-back threshold reg. */
1310#define TX_PTHRESH_1G 1 /**< Default values of TX prefetch threshold reg. */
1311
1312
1313struct port_cfg_t {
1314public:
1315    port_cfg_t(){
1316        memset(&m_port_conf,0,sizeof(m_port_conf));
1317        memset(&m_rx_conf,0,sizeof(m_rx_conf));
1318        memset(&m_tx_conf,0,sizeof(m_tx_conf));
1319        memset(&m_rx_drop_conf,0,sizeof(m_rx_drop_conf));
1320
1321        m_rx_conf.rx_thresh.pthresh = RX_PTHRESH;
1322        m_rx_conf.rx_thresh.hthresh = RX_HTHRESH;
1323        m_rx_conf.rx_thresh.wthresh = RX_WTHRESH;
1324        m_rx_conf.rx_free_thresh =32;
1325
1326        m_rx_drop_conf.rx_thresh.pthresh = 0;
1327        m_rx_drop_conf.rx_thresh.hthresh = 0;
1328        m_rx_drop_conf.rx_thresh.wthresh = 0;
1329        m_rx_drop_conf.rx_free_thresh =32;
1330        m_rx_drop_conf.rx_drop_en=1;
1331
1332        m_tx_conf.tx_thresh.pthresh = TX_PTHRESH;
1333        m_tx_conf.tx_thresh.hthresh = TX_HTHRESH;
1334        m_tx_conf.tx_thresh.wthresh = TX_WTHRESH;
1335
1336        m_port_conf.rxmode.jumbo_frame=1;
1337        m_port_conf.rxmode.max_rx_pkt_len =9*1024+22;
1338        m_port_conf.rxmode.hw_strip_crc=1;
1339    }
1340
1341    inline void update_var(void){
1342        get_ex_drv()->update_configuration(this);
1343    }
1344
1345    inline void update_global_config_fdir(void){
1346        get_ex_drv()->update_global_config_fdir(this);
1347    }
1348
1349    struct rte_eth_conf     m_port_conf;
1350    struct rte_eth_rxconf   m_rx_conf;
1351    struct rte_eth_rxconf   m_rx_drop_conf;
1352    struct rte_eth_txconf   m_tx_conf;
1353};
1354
1355
1356/* this object is per core / per port / per queue
1357   each core will have 2 ports to send to
1358
1359
1360   port0                                port1
1361
1362   0,1,2,3,..15 out queue ( per core )       0,1,2,3,..15 out queue ( per core )
1363
1364*/
1365
1366
1367typedef struct cnt_name_ {
1368    uint32_t offset;
1369    char * name;
1370}cnt_name_t ;
1371
1372#define MY_REG(a) {a,(char *)#a}
1373
1374void CPhyEthIFStats::Clear() {
1375    ipackets = 0;
1376    ibytes = 0;
1377    f_ipackets = 0;
1378    f_ibytes = 0;
1379    opackets = 0;
1380    obytes = 0;
1381    ierrors = 0;
1382    oerrors = 0;
1383    imcasts = 0;
1384    rx_nombuf = 0;
1385    memset(&m_prev_stats, 0, sizeof(m_prev_stats));
1386    memset(m_rx_per_flow_pkts, 0, sizeof(m_rx_per_flow_pkts));
1387    memset(m_rx_per_flow_bytes, 0, sizeof(m_rx_per_flow_bytes));
1388}
1389
1390// dump all counters (even ones that equal 0)
1391void CPhyEthIFStats::DumpAll(FILE *fd) {
1392#define DP_A4(f) printf(" %-40s : %llu \n",#f, (unsigned long long)f)
1393#define DP_A(f) if (f) printf(" %-40s : %llu \n",#f, (unsigned long long)f)
1394    DP_A4(opackets);
1395    DP_A4(obytes);
1396    DP_A4(ipackets);
1397    DP_A4(ibytes);
1398    DP_A(ierrors);
1399    DP_A(oerrors);
1400}
1401
1402// dump all non zero counters
1403void CPhyEthIFStats::Dump(FILE *fd) {
1404    DP_A(opackets);
1405    DP_A(obytes);
1406    DP_A(f_ipackets);
1407    DP_A(f_ibytes);
1408    DP_A(ipackets);
1409    DP_A(ibytes);
1410    DP_A(ierrors);
1411    DP_A(oerrors);
1412    DP_A(imcasts);
1413    DP_A(rx_nombuf);
1414}
1415
1416void CPhyEthIgnoreStats::dump(FILE *fd) {
1417    DP_A4(opackets);
1418    DP_A4(obytes);
1419    DP_A4(ipackets);
1420    DP_A4(ibytes);
1421    DP_A4(m_tx_arp);
1422    DP_A4(m_rx_arp);
1423}
1424
1425// Clear the RX queue of an interface, dropping all packets
1426void CPhyEthIF::flush_rx_queue(void){
1427
1428    rte_mbuf_t * rx_pkts[32];
1429    int j=0;
1430    uint16_t cnt=0;
1431
1432    while (true) {
1433        j++;
1434        cnt = rx_burst(m_rx_queue,rx_pkts,32);
1435        if ( cnt ) {
1436            int i;
1437            for (i=0; i<(int)cnt;i++) {
1438                rte_mbuf_t * m=rx_pkts[i];
1439                /*printf("rx--\n");
1440                  rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m));*/
1441                rte_pktmbuf_free(m);
1442            }
1443        }
1444        if ( ((cnt==0) && (j>10)) || (j>15) ) {
1445            break;
1446        }
1447    }
1448    if (cnt>0) {
1449        printf(" Warning can't flush rx-queue for port %d \n",(int)get_port_id());
1450    }
1451}
1452
1453
1454void CPhyEthIF::dump_stats_extended(FILE *fd){
1455
1456    cnt_name_t reg[]={
1457        MY_REG(IXGBE_GPTC), /* total packet */
1458        MY_REG(IXGBE_GOTCL), /* total bytes */
1459        MY_REG(IXGBE_GOTCH),
1460
1461        MY_REG(IXGBE_GPRC),
1462        MY_REG(IXGBE_GORCL),
1463        MY_REG(IXGBE_GORCH),
1464
1465
1466
1467        MY_REG(IXGBE_RXNFGPC),
1468        MY_REG(IXGBE_RXNFGBCL),
1469        MY_REG(IXGBE_RXNFGBCH),
1470        MY_REG(IXGBE_RXDGPC  ),
1471        MY_REG(IXGBE_RXDGBCL ),
1472        MY_REG(IXGBE_RXDGBCH  ),
1473        MY_REG(IXGBE_RXDDGPC ),
1474        MY_REG(IXGBE_RXDDGBCL ),
1475        MY_REG(IXGBE_RXDDGBCH  ),
1476        MY_REG(IXGBE_RXLPBKGPC ),
1477        MY_REG(IXGBE_RXLPBKGBCL),
1478        MY_REG(IXGBE_RXLPBKGBCH ),
1479        MY_REG(IXGBE_RXDLPBKGPC ),
1480        MY_REG(IXGBE_RXDLPBKGBCL),
1481        MY_REG(IXGBE_RXDLPBKGBCH ),
1482        MY_REG(IXGBE_TXDGPC      ),
1483        MY_REG(IXGBE_TXDGBCL     ),
1484        MY_REG(IXGBE_TXDGBCH     ),
1485        MY_REG(IXGBE_FDIRUSTAT ),
1486        MY_REG(IXGBE_FDIRFSTAT ),
1487        MY_REG(IXGBE_FDIRMATCH ),
1488        MY_REG(IXGBE_FDIRMISS )
1489
1490    };
1491    fprintf (fd," extended counters \n");
1492    int i;
1493    for (i=0; i<sizeof(reg)/sizeof(reg[0]); i++) {
1494        cnt_name_t *lp=&reg[i];
1495        uint32_t c=pci_reg_read(lp->offset);
1496        // xl710 bug. Counter values are -559038737 when they should be 0
1497        if (c && c != -559038737 ) {
1498            fprintf (fd," %s  : %d \n",lp->name,c);
1499        }
1500    }
1501}
1502
1503int CPhyEthIF::get_rx_stat_capabilities() {
1504    return get_ex_drv()->get_rx_stat_capabilities();
1505}
1506
1507
1508
1509void CPhyEthIF::configure(uint16_t nb_rx_queue,
1510                          uint16_t nb_tx_queue,
1511                          const struct rte_eth_conf *eth_conf){
1512    int ret;
1513    ret = rte_eth_dev_configure(m_port_id,
1514                                nb_rx_queue,
1515                                nb_tx_queue,
1516                                eth_conf);
1517
1518    if (ret < 0)
1519        rte_exit(EXIT_FAILURE, "Cannot configure device: "
1520                 "err=%d, port=%u\n",
1521                 ret, m_port_id);
1522
1523    /* get device info */
1524    rte_eth_dev_info_get(m_port_id, &m_dev_info);
1525
1526    if (CGlobalInfo::m_options.preview.getChecksumOffloadEnable()) {
1527        /* check if the device supports TCP and UDP checksum offloading */
1528        if ((m_dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM) == 0) {
1529            rte_exit(EXIT_FAILURE, "Device does not support UDP checksum offload: "
1530                     "port=%u\n",
1531                     m_port_id);
1532        }
1533        if ((m_dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) == 0) {
1534            rte_exit(EXIT_FAILURE, "Device does not support TCP checksum offload: "
1535                     "port=%u\n",
1536                     m_port_id);
1537        }
1538    }
1539}
1540
1541/*
1542  rx-queue 0 is the default queue. All traffic not going to queue 1
1543  will be dropped as queue 0 is disabled
1544  rx-queue 1 - Latency measurement packets and other features that need software processing will go here.
1545*/
1546void CPhyEthIF::configure_rx_duplicate_rules(){
1547    if ( get_is_rx_filter_enable() ){
1548        get_ex_drv()->configure_rx_filter_rules(this);
1549    }
1550}
1551
1552int CPhyEthIF::set_port_rcv_all(bool is_rcv) {
1553    // In these modes we are always receiving all packets anyway.
1554    switch (CGlobalInfo::get_queues_mode()) {
1555    case CGlobalInfo::Q_MODE_ONE_QUEUE:
1556        // In this mode we are always receiving all packets anyway.
1557        break;
1558    case CGlobalInfo::Q_MODE_RSS:
1559        //todo: need to send announcment to all tx cores
1560        //todo: need new function set_all_ports rcv all, to be able to send less tx messages
1561        break;
1562    default:
1563        get_ex_drv()->set_rcv_all(this, is_rcv);
1564        break;
1565    }
1566
1567    return 0;
1568}
1569
1570void CPhyEthIF::stop_rx_drop_queue() {
1571    // In debug mode, we want to see all packets. Don't want to disable any queue.
1572    if ( (CGlobalInfo::get_queues_mode() != CGlobalInfo::Q_MODE_NORMAL)
1573         || (CGlobalInfo::m_options.m_debug_pkt_proto != 0)) {
1574        return;
1575    }
1576    if ( CGlobalInfo::m_options.is_rx_enabled() ) {
1577        if ( (!get_ex_drv()->is_hardware_support_drop_queue())  ) {
1578            printf(" ERROR latency feature is not supported with current hardware  \n");
1579            exit(1);
1580        }
1581    }
1582    // OK to only stop MAIN_DPDK_DROP_Q here. The only driver in which there are
1583    // more than 1 drop q is Mellanox. stop_queue does not work in this case anyway.
1584    get_ex_drv()->stop_queue(this, MAIN_DPDK_DROP_Q);
1585}
1586
1587
1588void CPhyEthIF::rx_queue_setup(uint16_t rx_queue_id,
1589                               uint16_t nb_rx_desc,
1590                               unsigned int socket_id,
1591                               const struct rte_eth_rxconf *rx_conf,
1592                               struct rte_mempool *mb_pool){
1593
1594    int ret = rte_eth_rx_queue_setup(m_port_id , rx_queue_id,
1595                                     nb_rx_desc,
1596                                     socket_id,
1597                                     rx_conf,
1598                                     mb_pool);
1599    if (ret < 0)
1600        rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: "
1601                 "err=%d, port=%u\n",
1602                 ret, m_port_id);
1603}
1604
1605
1606
1607void CPhyEthIF::tx_queue_setup(uint16_t tx_queue_id,
1608                               uint16_t nb_tx_desc,
1609                               unsigned int socket_id,
1610                               const struct rte_eth_txconf *tx_conf){
1611
1612    int ret = rte_eth_tx_queue_setup( m_port_id,
1613                                      tx_queue_id,
1614                                      nb_tx_desc,
1615                                      socket_id,
1616                                      tx_conf);
1617    if (ret < 0)
1618        rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: "
1619                 "err=%d, port=%u queue=%u\n",
1620                 ret, m_port_id, tx_queue_id);
1621
1622}
1623
1624void CPhyEthIF::stop(){
1625    if (CGlobalInfo::m_options.preview.getCloseEnable()) {
1626        rte_eth_dev_stop(m_port_id);
1627        rte_eth_dev_close(m_port_id);
1628    }
1629}
1630
1631void CPhyEthIF::start(){
1632
1633    get_ex_drv()->clear_extended_stats(this);
1634
1635    int ret;
1636
1637    m_bw_tx.reset();
1638    m_bw_rx.reset();
1639
1640    m_stats.Clear();
1641    int i;
1642    for (i=0;i<10; i++ ) {
1643        ret = rte_eth_dev_start(m_port_id);
1644        if (ret==0) {
1645            return;
1646        }
1647        delay(1000);
1648    }
1649    if (ret < 0)
1650        rte_exit(EXIT_FAILURE, "rte_eth_dev_start: "
1651                 "err=%d, port=%u\n",
1652                 ret, m_port_id);
1653
1654}
1655
1656// Disabling flow control on interface
1657void CPhyEthIF::disable_flow_control(){
1658    int ret;
1659    // see trex-64 issue with loopback on the same NIC
1660    struct rte_eth_fc_conf fc_conf;
1661    memset(&fc_conf,0,sizeof(fc_conf));
1662    fc_conf.mode=RTE_FC_NONE;
1663    fc_conf.autoneg=1;
1664    fc_conf.pause_time=100;
1665    int i;
1666    for (i=0; i<5; i++) {
1667        ret=rte_eth_dev_flow_ctrl_set(m_port_id,&fc_conf);
1668        if (ret==0) {
1669            break;
1670        }
1671        delay(1000);
1672    }
1673    if (ret < 0)
1674        rte_exit(EXIT_FAILURE, "rte_eth_dev_flow_ctrl_set: "
1675                 "err=%d, port=%u\n probably link is down. Please check your link activity, or skip flow-control disabling, using: --no-flow-control-change option\n",
1676                 ret, m_port_id);
1677}
1678
1679/*
1680Get user friendly devices description from saved env. var
1681Changes certain attributes based on description
1682*/
1683void DpdkTRexPortAttr::update_description(){
1684    struct rte_pci_addr pci_addr;
1685    char pci[16];
1686    char * envvar;
1687    std::string pci_envvar_name;
1688    pci_addr = rte_eth_devices[m_port_id].device->devargs->pci.addr;
1689    snprintf(pci, sizeof(pci), "%04x:%02x:%02x.%d", pci_addr.domain, pci_addr.bus, pci_addr.devid, pci_addr.function);
1690    intf_info_st.pci_addr = pci;
1691    pci_envvar_name = "pci" + intf_info_st.pci_addr;
1692    std::replace(pci_envvar_name.begin(), pci_envvar_name.end(), ':', '_');
1693    std::replace(pci_envvar_name.begin(), pci_envvar_name.end(), '.', '_');
1694    envvar = std::getenv(pci_envvar_name.c_str());
1695    if (envvar) {
1696        intf_info_st.description = envvar;
1697    } else {
1698        intf_info_st.description = "Unknown";
1699    }
1700    if (intf_info_st.description.find("82599ES") != std::string::npos) { // works for 82599EB etc. DPDK does not distinguish them
1701        flag_is_link_change_supported = false;
1702    }
1703    if (intf_info_st.description.find("82545EM") != std::string::npos) { // in virtual E1000, DPDK claims fc is supported, but it's not
1704        flag_is_fc_change_supported = false;
1705        flag_is_led_change_supported = false;
1706    }
1707    if ( CGlobalInfo::m_options.preview.getVMode() > 0){
1708        printf("port %d desc: %s\n", m_port_id, intf_info_st.description.c_str());
1709    }
1710}
1711
1712int DpdkTRexPortAttr::set_led(bool on){
1713    if (on) {
1714        return rte_eth_led_on(m_port_id);
1715    }else{
1716        return rte_eth_led_off(m_port_id);
1717    }
1718}
1719
1720int DpdkTRexPortAttr::get_flow_ctrl(int &mode) {
1721    int ret = rte_eth_dev_flow_ctrl_get(m_port_id, &fc_conf_tmp);
1722    if (ret) {
1723        mode = -1;
1724        return ret;
1725    }
1726    mode = (int) fc_conf_tmp.mode;
1727    return 0;
1728}
1729
1730int DpdkTRexPortAttr::set_flow_ctrl(int mode) {
1731    if (!flag_is_fc_change_supported) {
1732        return -ENOTSUP;
1733    }
1734    int ret = rte_eth_dev_flow_ctrl_get(m_port_id, &fc_conf_tmp);
1735    if (ret) {
1736        return ret;
1737    }
1738    fc_conf_tmp.mode = (enum rte_eth_fc_mode) mode;
1739    return rte_eth_dev_flow_ctrl_set(m_port_id, &fc_conf_tmp);
1740}
1741
1742void DpdkTRexPortAttr::reset_xstats() {
1743    rte_eth_xstats_reset(m_port_id);
1744}
1745
1746int DpdkTRexPortAttr::get_xstats_values(xstats_values_t &xstats_values) {
1747    int size = rte_eth_xstats_get(m_port_id, NULL, 0);
1748    if (size < 0) {
1749        return size;
1750    }
1751    xstats_values_tmp.resize(size);
1752    xstats_values.resize(size);
1753    size = rte_eth_xstats_get(m_port_id, xstats_values_tmp.data(), size);
1754    if (size < 0) {
1755        return size;
1756    }
1757    for (int i=0; i<size; i++) {
1758        xstats_values[xstats_values_tmp[i].id] = xstats_values_tmp[i].value;
1759    }
1760    return 0;
1761}
1762
1763int DpdkTRexPortAttr::get_xstats_names(xstats_names_t &xstats_names){
1764    int size = rte_eth_xstats_get_names(m_port_id, NULL, 0);
1765    if (size < 0) {
1766        return size;
1767    }
1768    xstats_names_tmp.resize(size);
1769    xstats_names.resize(size);
1770    size = rte_eth_xstats_get_names(m_port_id, xstats_names_tmp.data(), size);
1771    if (size < 0) {
1772        return size;
1773    }
1774    for (int i=0; i<size; i++) {
1775        xstats_names[i] = xstats_names_tmp[i].name;
1776    }
1777    return 0;
1778}
1779
1780void DpdkTRexPortAttr::dump_link(FILE *fd){
1781    fprintf(fd,"port : %d \n",(int)m_port_id);
1782    fprintf(fd,"------------\n");
1783
1784    fprintf(fd,"link         : ");
1785    if (m_link.link_status) {
1786        fprintf(fd," link : Link Up - speed %u Mbps - %s\n",
1787                (unsigned) m_link.link_speed,
1788                (m_link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
1789                ("full-duplex") : ("half-duplex\n"));
1790    } else {
1791        fprintf(fd," Link Down\n");
1792    }
1793    fprintf(fd,"promiscuous  : %d \n",get_promiscuous());
1794}
1795
1796void DpdkTRexPortAttr::update_device_info(){
1797    rte_eth_dev_info_get(m_port_id, &dev_info);
1798}
1799
1800void DpdkTRexPortAttr::get_supported_speeds(supp_speeds_t &supp_speeds){
1801    uint32_t speed_capa = dev_info.speed_capa;
1802    if (speed_capa & ETH_LINK_SPEED_1G)
1803        supp_speeds.push_back(ETH_SPEED_NUM_1G);
1804    if (speed_capa & ETH_LINK_SPEED_10G)
1805        supp_speeds.push_back(ETH_SPEED_NUM_10G);
1806    if (speed_capa & ETH_LINK_SPEED_40G)
1807        supp_speeds.push_back(ETH_SPEED_NUM_40G);
1808    if (speed_capa & ETH_LINK_SPEED_100G)
1809        supp_speeds.push_back(ETH_SPEED_NUM_100G);
1810}
1811
1812void DpdkTRexPortAttr::update_link_status(){
1813    rte_eth_link_get(m_port_id, &m_link);
1814}
1815
1816bool DpdkTRexPortAttr::update_link_status_nowait(){
1817    rte_eth_link new_link;
1818    bool changed = false;
1819    rte_eth_link_get_nowait(m_port_id, &new_link);
1820
1821    if (new_link.link_speed != m_link.link_speed ||
1822                new_link.link_duplex != m_link.link_duplex ||
1823                    new_link.link_autoneg != m_link.link_autoneg ||
1824                        new_link.link_status != m_link.link_status) {
1825        changed = true;
1826
1827        /* in case of link status change - notify the dest object */
1828        if (new_link.link_status != m_link.link_status) {
1829            on_link_down();
1830        }
1831    }
1832
1833    m_link = new_link;
1834    return changed;
1835}
1836
1837int DpdkTRexPortAttr::add_mac(char * mac){
1838    struct ether_addr mac_addr;
1839    for (int i=0; i<6;i++) {
1840        mac_addr.addr_bytes[i] =mac[i];
1841    }
1842
1843    if ( get_ex_drv()->hardware_support_mac_change() ) {
1844        if ( rte_eth_dev_mac_addr_add(m_port_id, &mac_addr,0) != 0) {
1845            printf("Failed setting MAC for port %d \n", m_port_id);
1846            exit(-1);
1847        }
1848    }
1849
1850    return 0;
1851}
1852
1853int DpdkTRexPortAttr::set_promiscuous(bool enable){
1854    if (enable) {
1855        rte_eth_promiscuous_enable(m_port_id);
1856    }else{
1857        rte_eth_promiscuous_disable(m_port_id);
1858    }
1859    return 0;
1860}
1861
1862int DpdkTRexPortAttr::set_multicast(bool enable){
1863    if (enable) {
1864        rte_eth_allmulticast_enable(m_port_id);
1865    }else{
1866        rte_eth_allmulticast_disable(m_port_id);
1867    }
1868    return 0;
1869}
1870
1871int DpdkTRexPortAttr::set_link_up(bool up){
1872    if (up) {
1873        return rte_eth_dev_set_link_up(m_port_id);
1874    }else{
1875        return rte_eth_dev_set_link_down(m_port_id);
1876    }
1877}
1878
1879bool DpdkTRexPortAttr::get_promiscuous(){
1880    int ret=rte_eth_promiscuous_get(m_port_id);
1881    if (ret<0) {
1882        rte_exit(EXIT_FAILURE, "rte_eth_promiscuous_get: "
1883                 "err=%d, port=%u\n",
1884                 ret, m_port_id);
1885
1886    }
1887    return ( ret?true:false);
1888}
1889
1890bool DpdkTRexPortAttr::get_multicast(){
1891    int ret=rte_eth_allmulticast_get(m_port_id);
1892    if (ret<0) {
1893        rte_exit(EXIT_FAILURE, "rte_eth_allmulticast_get: "
1894                 "err=%d, port=%u\n",
1895                 ret, m_port_id);
1896
1897    }
1898    return ( ret?true:false);
1899}
1900
1901
1902void DpdkTRexPortAttr::get_hw_src_mac(struct ether_addr *mac_addr){
1903    rte_eth_macaddr_get(m_port_id , mac_addr);
1904}
1905
1906int CPhyEthIF::dump_fdir_global_stats(FILE *fd) {
1907    return get_ex_drv()->dump_fdir_global_stats(this, fd);
1908}
1909
1910void dump_hw_state(FILE *fd,struct ixgbe_hw_stats *hs ){
1911
1912#define DP_A1(f) if (hs->f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)hs->f)
1913#define DP_A2(f,m) for (i=0;i<m; i++) { if (hs->f[i]) fprintf(fd," %-40s[%d] : %llu \n",#f,i, (unsigned long long)hs->f[i]); }
1914    int i;
1915
1916    //for (i=0;i<8; i++) { if (hs->mpc[i]) fprintf(fd," %-40s[%d] : %llu \n","mpc",i,hs->mpc[i]); }
1917    DP_A2(mpc,8);
1918    DP_A1(crcerrs);
1919    DP_A1(illerrc);
1920    //DP_A1(errbc);
1921    DP_A1(mspdc);
1922    DP_A1(mpctotal);
1923    DP_A1(mlfc);
1924    DP_A1(mrfc);
1925    DP_A1(rlec);
1926    //DP_A1(lxontxc);
1927    //DP_A1(lxonrxc);
1928    //DP_A1(lxofftxc);
1929    //DP_A1(lxoffrxc);
1930    //DP_A2(pxontxc,8);
1931    //DP_A2(pxonrxc,8);
1932    //DP_A2(pxofftxc,8);
1933    //DP_A2(pxoffrxc,8);
1934
1935    //DP_A1(prc64);
1936    //DP_A1(prc127);
1937    //DP_A1(prc255);
1938    // DP_A1(prc511);
1939    //DP_A1(prc1023);
1940    //DP_A1(prc1522);
1941
1942    DP_A1(gprc);
1943    DP_A1(bprc);
1944    DP_A1(mprc);
1945    DP_A1(gptc);
1946    DP_A1(gorc);
1947    DP_A1(gotc);
1948    DP_A2(rnbc,8);
1949    DP_A1(ruc);
1950    DP_A1(rfc);
1951    DP_A1(roc);
1952    DP_A1(rjc);
1953    DP_A1(mngprc);
1954    DP_A1(mngpdc);
1955    DP_A1(mngptc);
1956    DP_A1(tor);
1957    DP_A1(tpr);
1958    DP_A1(tpt);
1959    DP_A1(ptc64);
1960    DP_A1(ptc127);
1961    DP_A1(ptc255);
1962    DP_A1(ptc511);
1963    DP_A1(ptc1023);
1964    DP_A1(ptc1522);
1965    DP_A1(mptc);
1966    DP_A1(bptc);
1967    DP_A1(xec);
1968    DP_A2(qprc,16);
1969    DP_A2(qptc,16);
1970    DP_A2(qbrc,16);
1971    DP_A2(qbtc,16);
1972    DP_A2(qprdc,16);
1973    DP_A2(pxon2offc,8);
1974    DP_A1(fdirustat_add);
1975    DP_A1(fdirustat_remove);
1976    DP_A1(fdirfstat_fadd);
1977    DP_A1(fdirfstat_fremove);
1978    DP_A1(fdirmatch);
1979    DP_A1(fdirmiss);
1980    DP_A1(fccrc);
1981    DP_A1(fclast);
1982    DP_A1(fcoerpdc);
1983    DP_A1(fcoeprc);
1984    DP_A1(fcoeptc);
1985    DP_A1(fcoedwrc);
1986    DP_A1(fcoedwtc);
1987    DP_A1(fcoe_noddp);
1988    DP_A1(fcoe_noddp_ext_buff);
1989    DP_A1(ldpcec);
1990    DP_A1(pcrc8ec);
1991    DP_A1(b2ospc);
1992    DP_A1(b2ogprc);
1993    DP_A1(o2bgptc);
1994    DP_A1(o2bspc);
1995}
1996
1997void CPhyEthIF::set_ignore_stats_base(CPreTestStats &pre_stats) {
1998    // reading m_stats, so drivers saving prev in m_stats will be updated.
1999    // Actually, we want m_stats to be cleared
2000    get_ex_drv()->get_extended_stats(this, &m_stats);
2001
2002    m_ignore_stats.ipackets = m_stats.ipackets;
2003    m_ignore_stats.ibytes = m_stats.ibytes;
2004    m_ignore_stats.opackets = m_stats.opackets;
2005    m_ignore_stats.obytes = m_stats.obytes;
2006    m_stats.ipackets = 0;
2007    m_stats.opackets = 0;
2008    m_stats.ibytes = 0;
2009    m_stats.obytes = 0;
2010
2011    m_ignore_stats.m_tx_arp = pre_stats.m_tx_arp;
2012    m_ignore_stats.m_rx_arp = pre_stats.m_rx_arp;
2013
2014    if (CGlobalInfo::m_options.preview.getVMode() >= 3) {
2015        fprintf(stdout, "Pre test statistics for port %d\n", get_port_id());
2016        m_ignore_stats.dump(stdout);
2017    }
2018}
2019
2020void CPhyEthIF::dump_stats(FILE *fd){
2021
2022    update_counters();
2023
2024    fprintf(fd,"port : %d \n",(int)m_port_id);
2025    fprintf(fd,"------------\n");
2026    m_stats.DumpAll(fd);
2027    //m_stats.Dump(fd);
2028    printf (" Tx : %.1fMb/sec  \n",m_last_tx_rate);
2029    //printf (" Rx : %.1fMb/sec  \n",m_last_rx_rate);
2030}
2031
2032void CPhyEthIF::stats_clear(){
2033    rte_eth_stats_reset(m_port_id);
2034    m_stats.Clear();
2035}
2036
2037class CCorePerPort  {
2038public:
2039    CCorePerPort (){
2040        m_tx_queue_id=0;
2041        m_len=0;
2042        int i;
2043        for (i=0; i<MAX_PKT_BURST; i++) {
2044            m_table[i]=0;
2045        }
2046        m_port=0;
2047    }
2048    uint8_t                 m_tx_queue_id;
2049    uint8_t                 m_tx_queue_id_lat; // q id for tx of latency pkts
2050    uint16_t                m_len;
2051    rte_mbuf_t *            m_table[MAX_PKT_BURST];
2052    CPhyEthIF  *            m_port;
2053};
2054
2055
2056#define MAX_MBUF_CACHE 100
2057
2058
2059/* per core/gbe queue port for trasmitt */
2060class CCoreEthIF : public CVirtualIF {
2061public:
2062    enum {
2063     INVALID_Q_ID = 255
2064    };
2065
2066public:
2067
2068    CCoreEthIF(){
2069        m_mbuf_cache=0;
2070    }
2071
2072    bool Create(uint8_t             core_id,
2073                uint8_t            tx_client_queue_id,
2074                CPhyEthIF  *        tx_client_port,
2075                uint8_t            tx_server_queue_id,
2076                CPhyEthIF  *        tx_server_port,
2077                uint8_t             tx_q_id_lat);
2078    void Delete();
2079
2080    virtual int open_file(std::string file_name){
2081        return (0);
2082    }
2083
2084    virtual int close_file(void){
2085        return (flush_tx_queue());
2086    }
2087    __attribute__ ((noinline)) int send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * node_sl
2088                                                       , CCorePerPort *  lp_port
2089                                                       , CVirtualIFPerSideStats  * lp_stats, bool is_const);
2090    virtual int send_node(CGenNode * node);
2091    virtual void send_one_pkt(pkt_dir_t dir, rte_mbuf_t *m);
2092    virtual int flush_tx_queue(void);
2093    __attribute__ ((noinline)) void handle_slowpath_features(CGenNode *node, rte_mbuf_t *m, uint8_t *p, pkt_dir_t dir);
2094
2095    void apply_client_cfg(const ClientCfgBase *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p);
2096
2097    bool process_rx_pkt(pkt_dir_t   dir,rte_mbuf_t * m);
2098
2099    virtual int update_mac_addr_from_global_cfg(pkt_dir_t       dir, uint8_t * p);
2100
2101    virtual pkt_dir_t port_id_to_dir(uint8_t port_id);
2102    void GetCoreCounters(CVirtualIFPerSideStats *stats);
2103    void DumpCoreStats(FILE *fd);
2104    void DumpIfStats(FILE *fd);
2105    static void DumpIfCfgHeader(FILE *fd);
2106    void DumpIfCfg(FILE *fd);
2107
2108    socket_id_t get_socket_id(){
2109        return ( CGlobalInfo::m_socket.port_to_socket( m_ports[0].m_port->get_port_id() ) );
2110    }
2111
2112    const CCorePerPort * get_ports() {
2113        return m_ports;
2114    }
2115
2116protected:
2117
2118    int send_burst(CCorePerPort * lp_port,
2119                   uint16_t len,
2120                   CVirtualIFPerSideStats  * lp_stats);
2121    int send_pkt(CCorePerPort * lp_port,
2122                 rte_mbuf_t *m,
2123                 CVirtualIFPerSideStats  * lp_stats);
2124    int send_pkt_lat(CCorePerPort * lp_port,
2125                 rte_mbuf_t *m,
2126                 CVirtualIFPerSideStats  * lp_stats);
2127
2128protected:
2129    uint8_t      m_core_id;
2130    uint16_t     m_mbuf_cache;
2131    CCorePerPort m_ports[CS_NUM]; /* each core has 2 tx queues 1. client side and server side */
2132    CNodeRing *  m_ring_to_rx;
2133
2134} __rte_cache_aligned; ;
2135
2136class CCoreEthIFStateless : public CCoreEthIF {
2137public:
2138    virtual int send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * node_sl, CCorePerPort *  lp_port
2139                                    , CVirtualIFPerSideStats  * lp_stats, bool is_const);
2140
2141    /**
2142     * fast path version
2143     */
2144    virtual int send_node(CGenNode *node);
2145
2146    /**
2147     * slow path version
2148     */
2149    virtual int send_node_service_mode(CGenNode *node);
2150
2151protected:
2152    template <bool SERVICE_MODE> inline int send_node_common(CGenNode *no);
2153
2154    inline rte_mbuf_t * generate_node_pkt(CGenNodeStateless *node_sl)   __attribute__ ((always_inline));
2155    inline int send_node_packet(CGenNodeStateless      *node_sl,
2156                                rte_mbuf_t             *m,
2157                                CCorePerPort           *lp_port,
2158                                CVirtualIFPerSideStats *lp_stats)   __attribute__ ((always_inline));
2159
2160    rte_mbuf_t * generate_slow_path_node_pkt(CGenNodeStateless *node_sl);
2161};
2162
2163bool CCoreEthIF::Create(uint8_t             core_id,
2164                        uint8_t             tx_client_queue_id,
2165                        CPhyEthIF  *        tx_client_port,
2166                        uint8_t             tx_server_queue_id,
2167                        CPhyEthIF  *        tx_server_port,
2168                        uint8_t tx_q_id_lat ) {
2169    m_ports[CLIENT_SIDE].m_tx_queue_id = tx_client_queue_id;
2170    m_ports[CLIENT_SIDE].m_port        = tx_client_port;
2171    m_ports[CLIENT_SIDE].m_tx_queue_id_lat = tx_q_id_lat;
2172    m_ports[SERVER_SIDE].m_tx_queue_id = tx_server_queue_id;
2173    m_ports[SERVER_SIDE].m_port        = tx_server_port;
2174    m_ports[SERVER_SIDE].m_tx_queue_id_lat = tx_q_id_lat;
2175    m_core_id = core_id;
2176
2177    CMessagingManager * rx_dp=CMsgIns::Ins()->getRxDp();
2178    m_ring_to_rx = rx_dp->getRingDpToCp(core_id-1);
2179    assert( m_ring_to_rx);
2180    return (true);
2181}
2182
2183int CCoreEthIF::flush_tx_queue(void){
2184    /* flush both sides */
2185    pkt_dir_t dir;
2186    for (dir = CLIENT_SIDE; dir < CS_NUM; dir++) {
2187        CCorePerPort * lp_port = &m_ports[dir];
2188        CVirtualIFPerSideStats  * lp_stats = &m_stats[dir];
2189        if ( likely(lp_port->m_len > 0) ) {
2190            send_burst(lp_port, lp_port->m_len, lp_stats);
2191            lp_port->m_len = 0;
2192        }
2193    }
2194
2195    return 0;
2196}
2197
2198void CCoreEthIF::GetCoreCounters(CVirtualIFPerSideStats *stats){
2199    stats->Clear();
2200    pkt_dir_t   dir ;
2201    for (dir=CLIENT_SIDE; dir<CS_NUM; dir++) {
2202        stats->Add(&m_stats[dir]);
2203    }
2204}
2205
2206void CCoreEthIF::DumpCoreStats(FILE *fd){
2207    fprintf (fd,"------------------------ \n");
2208    fprintf (fd," per core stats core id : %d  \n",m_core_id);
2209    fprintf (fd,"------------------------ \n");
2210
2211    CVirtualIFPerSideStats stats;
2212    GetCoreCounters(&stats);
2213    stats.Dump(stdout);
2214}
2215
2216void CCoreEthIF::DumpIfCfgHeader(FILE *fd){
2217    fprintf (fd," core, c-port, c-queue, s-port, s-queue, lat-queue\n");
2218    fprintf (fd," ------------------------------------------\n");
2219}
2220
2221void CCoreEthIF::DumpIfCfg(FILE *fd){
2222    fprintf (fd," %d   %6u %6u  %6u  %6u %6u  \n",m_core_id,
2223             m_ports[CLIENT_SIDE].m_port->get_port_id(),
2224             m_ports[CLIENT_SIDE].m_tx_queue_id,
2225             m_ports[SERVER_SIDE].m_port->get_port_id(),
2226             m_ports[SERVER_SIDE].m_tx_queue_id,
2227             m_ports[SERVER_SIDE].m_tx_queue_id_lat
2228             );
2229}
2230
2231
2232void CCoreEthIF::DumpIfStats(FILE *fd){
2233
2234    fprintf (fd,"------------------------ \n");
2235    fprintf (fd," per core per if stats id : %d  \n",m_core_id);
2236    fprintf (fd,"------------------------ \n");
2237
2238    const char * t[]={"client","server"};
2239    pkt_dir_t   dir ;
2240    for (dir=CLIENT_SIDE; dir<CS_NUM; dir++) {
2241        CCorePerPort * lp=&m_ports[dir];
2242        CVirtualIFPerSideStats * lpstats = &m_stats[dir];
2243        fprintf (fd," port %d, queue id :%d  - %s \n",lp->m_port->get_port_id(),lp->m_tx_queue_id,t[dir] );
2244        fprintf (fd," ---------------------------- \n");
2245        lpstats->Dump(fd);
2246    }
2247}
2248
2249#define DELAY_IF_NEEDED
2250
2251int CCoreEthIF::send_burst(CCorePerPort * lp_port,
2252                           uint16_t len,
2253                           CVirtualIFPerSideStats  * lp_stats){
2254
2255#ifdef DEBUG_SEND_BURST
2256    if (CGlobalInfo::m_options.preview.getVMode() > 10) {
2257        fprintf(stdout, "send_burst port:%d queue:%d len:%d\n", lp_port->m_port->get_rte_port_id()
2258                , lp_port->m_tx_queue_id, len);
2259        for (int i = 0; i < lp_port->m_len; i++) {
2260            fprintf(stdout, "packet %d:\n", i);
2261            rte_mbuf_t *m = lp_port->m_table[i];
2262            utl_DumpBuffer(stdout, rte_pktmbuf_mtod(m, uint8_t*), rte_pktmbuf_pkt_len(m), 0);
2263        }
2264    }
2265#endif
2266
2267    uint16_t ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id,lp_port->m_table,len);
2268#ifdef DELAY_IF_NEEDED
2269    while ( unlikely( ret<len ) ){
2270        rte_delay_us(1);
2271        lp_stats->m_tx_queue_full += 1;
2272        uint16_t ret1=lp_port->m_port->tx_burst(lp_port->m_tx_queue_id,
2273                                                &lp_port->m_table[ret],
2274                                                len-ret);
2275        ret+=ret1;
2276    }
2277#else
2278    /* CPU has burst of packets larger than TX can send. Need to drop packets */
2279    if ( unlikely(ret < len) ) {
2280        lp_stats->m_tx_drop += (len-ret);
2281        uint16_t i;
2282        for (i=ret; i<len;i++) {
2283            rte_mbuf_t * m=lp_port->m_table[i];
2284            rte_pktmbuf_free(m);
2285        }
2286    }
2287#endif
2288
2289    return (0);
2290}
2291
2292
2293int CCoreEthIF::send_pkt(CCorePerPort * lp_port,
2294                         rte_mbuf_t      *m,
2295                         CVirtualIFPerSideStats  * lp_stats
2296                         ){
2297
2298    uint16_t len = lp_port->m_len;
2299    lp_port->m_table[len]=m;
2300    len++;
2301
2302    /* enough pkts to be sent */
2303    if (unlikely(len == MAX_PKT_BURST)) {
2304        send_burst(lp_port, MAX_PKT_BURST,lp_stats);
2305        len = 0;
2306    }
2307    lp_port->m_len = len;
2308
2309    return (0);
2310}
2311
2312int CCoreEthIF::send_pkt_lat(CCorePerPort *lp_port, rte_mbuf_t *m, CVirtualIFPerSideStats *lp_stats) {
2313    // We allow sending only from first core of each port. This is serious internal bug otherwise.
2314    assert(lp_port->m_tx_queue_id_lat != INVALID_Q_ID);
2315
2316    int ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id_lat, &m, 1);
2317
2318#ifdef DELAY_IF_NEEDED
2319    while ( unlikely( ret != 1 ) ){
2320        rte_delay_us(1);
2321        lp_stats->m_tx_queue_full += 1;
2322        ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id_lat, &m, 1);
2323    }
2324
2325#else
2326    if ( unlikely( ret != 1 ) ) {
2327        lp_stats->m_tx_drop ++;
2328        rte_pktmbuf_free(m);
2329        return 0;
2330    }
2331
2332#endif
2333
2334    return ret;
2335}
2336
2337void CCoreEthIF::send_one_pkt(pkt_dir_t       dir,
2338                              rte_mbuf_t      *m){
2339    CCorePerPort *  lp_port=&m_ports[dir];
2340    CVirtualIFPerSideStats  * lp_stats = &m_stats[dir];
2341    send_pkt(lp_port,m,lp_stats);
2342    /* flush */
2343    send_burst(lp_port,lp_port->m_len,lp_stats);
2344    lp_port->m_len = 0;
2345}
2346
2347int CCoreEthIFStateless::send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * node_sl, CCorePerPort *  lp_port
2348                                             , CVirtualIFPerSideStats  * lp_stats, bool is_const) {
2349    // Defining this makes 10% percent packet loss. 1% packet reorder.
2350# ifdef ERR_CNTRS_TEST
2351    static int temp=1;
2352    temp++;
2353#endif
2354
2355    uint16_t hw_id = node_sl->get_stat_hw_id();
2356    rte_mbuf *mi;
2357    struct flow_stat_payload_header *fsp_head = NULL;
2358
2359    if (hw_id >= MAX_FLOW_STATS) {
2360        // payload rule hw_ids are in the range right above ip id rules
2361        uint16_t hw_id_payload = hw_id - MAX_FLOW_STATS;
2362        if (hw_id_payload > max_stat_hw_id_seen_payload) {
2363            max_stat_hw_id_seen_payload = hw_id_payload;
2364        }
2365
2366        mi = node_sl->alloc_flow_stat_mbuf(m, fsp_head, is_const);
2367        fsp_head->seq = lp_stats->m_lat_data[hw_id_payload].get_seq_num();
2368        fsp_head->hw_id = hw_id_payload;
2369        fsp_head->flow_seq = lp_stats->m_lat_data[hw_id_payload].get_flow_seq();
2370        fsp_head->magic = FLOW_STAT_PAYLOAD_MAGIC;
2371
2372        lp_stats->m_lat_data[hw_id_payload].inc_seq_num();
2373#ifdef ERR_CNTRS_TEST
2374        if (temp % 10 == 0) {
2375            fsp_head->seq = lp_stats->m_lat_data[hw_id_payload].inc_seq_num();
2376        }
2377        if ((temp - 1) % 100 == 0) {
2378            fsp_head->seq = lp_stats->m_lat_data[hw_id_payload].get_seq_num() - 4;
2379        }
2380#endif
2381    } else {
2382        // ip id rule
2383        if (hw_id > max_stat_hw_id_seen) {
2384            max_stat_hw_id_seen = hw_id;
2385        }
2386        mi = m;
2387    }
2388    tx_per_flow_t *lp_s = &lp_stats->m_tx_per_flow[hw_id];
2389    lp_s->add_pkts(1);
2390    lp_s->add_bytes(mi->pkt_len + 4); // We add 4 because of ethernet CRC
2391
2392    if (hw_id >= MAX_FLOW_STATS) {
2393        fsp_head->time_stamp = os_get_hr_tick_64();
2394        send_pkt_lat(lp_port, mi, lp_stats);
2395    } else {
2396        send_pkt(lp_port, mi, lp_stats);
2397    }
2398    return 0;
2399}
2400
2401inline rte_mbuf_t *
2402CCoreEthIFStateless::generate_node_pkt(CGenNodeStateless *node_sl) {
2403    if (unlikely(node_sl->get_is_slow_path())) {
2404        return generate_slow_path_node_pkt(node_sl);
2405    }
2406
2407    /* check that we have mbuf  */
2408    rte_mbuf_t *m;
2409
2410    if ( likely(node_sl->is_cache_mbuf_array()) ) {
2411        m = node_sl->cache_mbuf_array_get_cur();
2412        rte_pktmbuf_refcnt_update(m,1);
2413    }else{
2414        m = node_sl->get_cache_mbuf();
2415
2416        if (m) {
2417            /* cache case */
2418            rte_pktmbuf_refcnt_update(m,1);
2419        }else{
2420            m=node_sl->alloc_node_with_vm();
2421            assert(m);
2422        }
2423    }
2424
2425    return m;
2426}
2427
2428inline int
2429CCoreEthIFStateless::send_node_packet(CGenNodeStateless      *node_sl,
2430                                      rte_mbuf_t             *m,
2431                                      CCorePerPort           *lp_port,
2432                                      CVirtualIFPerSideStats *lp_stats) {
2433
2434    if (unlikely(node_sl->is_stat_needed())) {
2435        if ( unlikely(node_sl->is_cache_mbuf_array()) ) {
2436            // No support for latency + cache. If user asks for cache on latency stream, we change cache to 0.
2437            // assert here just to make sure.
2438            assert(1);
2439        }
2440        return send_node_flow_stat(m, node_sl, lp_port, lp_stats, (node_sl->get_cache_mbuf()) ? true : false);
2441    } else {
2442        return send_pkt(lp_port, m, lp_stats);
2443    }
2444}
2445
2446int CCoreEthIFStateless::send_node(CGenNode *node) {
2447    return send_node_common<false>(node);
2448}
2449
2450int CCoreEthIFStateless::send_node_service_mode(CGenNode *node) {
2451    return send_node_common<true>(node);
2452}
2453
2454/**
2455 * this is the common function and it is templated
2456 * for two compiler evaluation for performance
2457 *
2458 */
2459template <bool SERVICE_MODE>
2460int CCoreEthIFStateless::send_node_common(CGenNode *node) {
2461    CGenNodeStateless * node_sl = (CGenNodeStateless *) node;
2462
2463    pkt_dir_t dir                     = (pkt_dir_t)node_sl->get_mbuf_cache_dir();
2464    CCorePerPort *lp_port             = &m_ports[dir];
2465    CVirtualIFPerSideStats *lp_stats  = &m_stats[dir];
2466
2467    /* generate packet (can never fail) */
2468    rte_mbuf_t *m = generate_node_pkt(node_sl);
2469
2470    /* template boolean - this will be removed at compile time */
2471    if (SERVICE_MODE) {
2472        TrexStatelessCaptureMngr::getInstance().handle_pkt_tx(m, lp_port->m_port->get_port_id());
2473    }
2474
2475    /* send */
2476    return send_node_packet(node_sl, m, lp_port, lp_stats);
2477}
2478
2479/**
2480 * slow path code goes here
2481 *
2482 */
2483rte_mbuf_t *
2484CCoreEthIFStateless::generate_slow_path_node_pkt(CGenNodeStateless *node_sl) {
2485
2486    if (node_sl->m_type == CGenNode::PCAP_PKT) {
2487        CGenNodePCAP *pcap_node = (CGenNodePCAP *)node_sl;
2488        return pcap_node->get_pkt();
2489    }
2490
2491    /* unhandled case of slow path node */
2492    assert(0);
2493    return (NULL);
2494}
2495
2496void CCoreEthIF::apply_client_cfg(const ClientCfgBase *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p) {
2497
2498    assert(cfg);
2499
2500    /* take the right direction config */
2501    const ClientCfgDirBase &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
2502
2503    /* dst mac */
2504    if (cfg_dir.has_dst_mac_addr()) {
2505        memcpy(p, cfg_dir.get_dst_mac_addr(), 6);
2506    }
2507
2508    /* src mac */
2509    if (cfg_dir.has_src_mac_addr()) {
2510        memcpy(p + 6, cfg_dir.get_src_mac_addr(), 6);
2511    }
2512
2513    /* VLAN */
2514    if (cfg_dir.has_vlan()) {
2515        add_vlan(m, cfg_dir.get_vlan());
2516    }
2517}
2518
2519/**
2520 * slow path features goes here (avoid multiple IFs)
2521 *
2522 */
2523void CCoreEthIF::handle_slowpath_features(CGenNode *node, rte_mbuf_t *m, uint8_t *p, pkt_dir_t dir) {
2524
2525
2526    /* MAC ovverride */
2527    if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_overide_enable() ) ) {
2528        /* client side */
2529        if ( node->is_initiator_pkt() ) {
2530            *((uint32_t*)(p+6)) = PKT_NTOHL(node->m_src_ip);
2531        }
2532    }
2533
2534    /* flag is faster than checking the node pointer (another cacheline) */
2535    if ( unlikely(CGlobalInfo::m_options.preview.get_is_client_cfg_enable() ) ) {
2536        apply_client_cfg(node->m_client_cfg, m, dir, p);
2537    }
2538
2539}
2540
2541int CCoreEthIF::send_node(CGenNode * node) {
2542
2543#ifdef OPT_REPEAT_MBUF
2544
2545    if ( unlikely( node->get_cache_mbuf() !=NULL ) ) {
2546        pkt_dir_t       dir;
2547        rte_mbuf_t *    m=node->get_cache_mbuf();
2548        dir=(pkt_dir_t)node->get_mbuf_cache_dir();
2549        CCorePerPort *  lp_port=&m_ports[dir];
2550        CVirtualIFPerSideStats  * lp_stats = &m_stats[dir];
2551        rte_pktmbuf_refcnt_update(m,1);
2552        send_pkt(lp_port,m,lp_stats);
2553        return (0);
2554    }
2555#endif
2556
2557    CFlowPktInfo *  lp=node->m_pkt_info;
2558    rte_mbuf_t *    m=lp->generate_new_mbuf(node);
2559
2560    pkt_dir_t       dir;
2561    bool            single_port;
2562
2563    dir         = node->cur_interface_dir();
2564    single_port = node->get_is_all_flow_from_same_dir() ;
2565
2566
2567    if ( unlikely(CGlobalInfo::m_options.preview.get_vlan_mode()
2568                  != CPreviewMode::VLAN_MODE_NONE) ) {
2569        uint16_t vlan_id=0;
2570
2571        if (CGlobalInfo::m_options.preview.get_vlan_mode()
2572            == CPreviewMode::VLAN_MODE_LOAD_BALANCE) {
2573            /* which vlan to choose 0 or 1*/
2574            uint8_t vlan_port = (node->m_src_ip & 1);
2575            vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port];
2576            if (likely( vlan_id > 0 ) ) {
2577                dir = dir ^ vlan_port;
2578            } else {
2579                /* both from the same dir but with VLAN0 */
2580                vlan_id = CGlobalInfo::m_options.m_vlan_port[0];
2581            }
2582        } else if (CGlobalInfo::m_options.preview.get_vlan_mode()
2583            == CPreviewMode::VLAN_MODE_NORMAL) {
2584            CCorePerPort *lp_port = &m_ports[dir];
2585            uint8_t port_id = lp_port->m_port->get_port_id();
2586            vlan_id = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan();
2587        }
2588
2589        add_vlan(m, vlan_id);
2590    }
2591
2592    CCorePerPort *lp_port = &m_ports[dir];
2593    CVirtualIFPerSideStats *lp_stats = &m_stats[dir];
2594
2595    if (unlikely(m==0)) {
2596        lp_stats->m_tx_alloc_error++;
2597        return(0);
2598    }
2599
2600    /* update mac addr dest/src 12 bytes */
2601    uint8_t *p   = rte_pktmbuf_mtod(m, uint8_t*);
2602    uint8_t p_id = lp_port->m_port->get_port_id();
2603
2604    memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12);
2605
2606     /* when slowpath features are on */
2607    if ( unlikely( CGlobalInfo::m_options.preview.get_is_slowpath_features_on() ) ) {
2608        handle_slowpath_features(node, m, p, dir);
2609    }
2610
2611
2612    if ( unlikely( node->is_rx_check_enabled() ) ) {
2613        lp_stats->m_tx_rx_check_pkt++;
2614        lp->do_generate_new_mbuf_rxcheck(m, node, single_port);
2615        lp_stats->m_template.inc_template( node->get_template_id( ));
2616    }else{
2617
2618#ifdef OPT_REPEAT_MBUF
2619        // cache only if it is not sample as this is more complex mbuf struct
2620        if ( unlikely( node->can_cache_mbuf() ) ) {
2621            if ( !CGlobalInfo::m_options.preview.isMbufCacheDisabled() ){
2622                m_mbuf_cache++;
2623                if (m_mbuf_cache < MAX_MBUF_CACHE) {
2624                    /* limit the number of object to cache */
2625                    node->set_mbuf_cache_dir( dir);
2626                    node->set_cache_mbuf(m);
2627                    rte_pktmbuf_refcnt_update(m,1);
2628                }
2629            }
2630        }
2631#endif
2632
2633    }
2634
2635    /*printf("send packet -- \n");
2636      rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m));*/
2637
2638    /* send the packet */
2639    send_pkt(lp_port,m,lp_stats);
2640    return (0);
2641}
2642
2643
2644int CCoreEthIF::update_mac_addr_from_global_cfg(pkt_dir_t  dir, uint8_t * p){
2645    assert(p);
2646    assert(dir<2);
2647
2648    CCorePerPort *  lp_port=&m_ports[dir];
2649    uint8_t p_id=lp_port->m_port->get_port_id();
2650    memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12);
2651    return (0);
2652}
2653
2654pkt_dir_t
2655CCoreEthIF::port_id_to_dir(uint8_t port_id) {
2656
2657    for (pkt_dir_t dir = 0; dir < CS_NUM; dir++) {
2658        if (m_ports[dir].m_port->get_port_id() == port_id) {
2659            return dir;
2660        }
2661    }
2662
2663    return (CS_INVALID);
2664}
2665
2666class CLatencyHWPort : public CPortLatencyHWBase {
2667public:
2668    void Create(CPhyEthIF  * p,
2669                uint8_t tx_queue,
2670                uint8_t rx_queue){
2671        m_port=p;
2672        m_tx_queue_id=tx_queue;
2673        m_rx_queue_id=rx_queue;
2674    }
2675
2676    virtual int tx(rte_mbuf_t *m) {
2677        rte_mbuf_t *tx_pkts[2];
2678
2679        tx_pkts[0] = m;
2680        uint8_t vlan_mode = CGlobalInfo::m_options.preview.get_vlan_mode();
2681        if ( likely( vlan_mode != CPreviewMode::VLAN_MODE_NONE) ) {
2682            if ( vlan_mode == CPreviewMode::VLAN_MODE_LOAD_BALANCE ) {
2683                add_vlan(m, CGlobalInfo::m_options.m_vlan_port[0]);
2684            } else if (vlan_mode == CPreviewMode::VLAN_MODE_NORMAL) {
2685                uint8_t port_id = m_port->get_rte_port_id();
2686                add_vlan(m, CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan());
2687            }
2688        }
2689        uint16_t res=m_port->tx_burst(m_tx_queue_id,tx_pkts,1);
2690        if ( res == 0 ) {
2691            rte_pktmbuf_free(m);
2692            //printf(" queue is full for latency packet !!\n");
2693            return (-1);
2694
2695        }
2696#if 0
2697        fprintf(stdout," ==> %f.03 send packet ..\n",now_sec());
2698        uint8_t *p1=rte_pktmbuf_mtod(m, uint8_t*);
2699        uint16_t pkt_size1=rte_pktmbuf_pkt_len(m);
2700        utl_DumpBuffer(stdout,p1,pkt_size1,0);
2701#endif
2702
2703        return (0);
2704    }
2705
2706
2707    /* nothing special with HW implementation */
2708    virtual int tx_latency(rte_mbuf_t *m) {
2709        return tx(m);
2710    }
2711
2712    virtual rte_mbuf_t * rx(){
2713        rte_mbuf_t * rx_pkts[1];
2714        uint16_t cnt=m_port->rx_burst(m_rx_queue_id,rx_pkts,1);
2715        if (cnt) {
2716            return (rx_pkts[0]);
2717        }else{
2718            return (0);
2719        }
2720    }
2721
2722
2723    virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts,
2724                              uint16_t nb_pkts){
2725        uint16_t cnt=m_port->rx_burst(m_rx_queue_id,rx_pkts,nb_pkts);
2726        return (cnt);
2727    }
2728
2729
2730private:
2731    CPhyEthIF  * m_port;
2732    uint8_t      m_tx_queue_id ;
2733    uint8_t      m_rx_queue_id;
2734};
2735
2736
2737class CLatencyVmPort : public CPortLatencyHWBase {
2738public:
2739    void Create(uint8_t port_index,
2740                CNodeRing *ring,
2741                CLatencyManager *mgr,
2742                CPhyEthIF  *p) {
2743
2744        m_dir        = (port_index % 2);
2745        m_ring_to_dp = ring;
2746        m_mgr        = mgr;
2747        m_port       = p;
2748    }
2749
2750
2751    virtual int tx(rte_mbuf_t *m) {
2752        return tx_common(m, false);
2753    }
2754
2755    virtual int tx_latency(rte_mbuf_t *m) {
2756        return tx_common(m, true);
2757    }
2758
2759    virtual rte_mbuf_t * rx() {
2760        rte_mbuf_t * rx_pkts[1];
2761        uint16_t cnt = m_port->rx_burst(0, rx_pkts, 1);
2762        if (cnt) {
2763            return (rx_pkts[0]);
2764        } else {
2765            return (0);
2766        }
2767    }
2768
2769    virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, uint16_t nb_pkts) {
2770        uint16_t cnt = m_port->rx_burst(0, rx_pkts, nb_pkts);
2771        return (cnt);
2772    }
2773
2774private:
2775      virtual int tx_common(rte_mbuf_t *m, bool fix_timestamp) {
2776
2777
2778        uint8_t vlan_mode = CGlobalInfo::m_options.preview.get_vlan_mode();
2779        if ( likely( vlan_mode != CPreviewMode::VLAN_MODE_NONE) ) {
2780            if ( vlan_mode == CPreviewMode::VLAN_MODE_LOAD_BALANCE ) {
2781                add_vlan(m, CGlobalInfo::m_options.m_vlan_port[0]);
2782            } else if (vlan_mode == CPreviewMode::VLAN_MODE_NORMAL) {
2783                uint8_t port_id = m_port->get_rte_port_id();
2784                add_vlan(m, CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan());
2785            }
2786        }
2787
2788        /* allocate node */
2789        CGenNodeLatencyPktInfo *node=(CGenNodeLatencyPktInfo * )CGlobalInfo::create_node();
2790        if (!node) {
2791            return (-1);
2792        }
2793
2794        node->m_msg_type = CGenNodeMsgBase::LATENCY_PKT;
2795        node->m_dir      = m_dir;
2796        node->m_pkt      = m;
2797
2798        if (fix_timestamp) {
2799            node->m_latency_offset = m_mgr->get_latency_header_offset();
2800            node->m_update_ts = 1;
2801        } else {
2802            node->m_update_ts = 0;
2803        }
2804
2805        if ( m_ring_to_dp->Enqueue((CGenNode*)node) != 0 ){
2806            return (-1);
2807        }
2808
2809        return (0);
2810    }
2811
2812    CPhyEthIF  * m_port;
2813    uint8_t                          m_dir;
2814    CNodeRing *                      m_ring_to_dp;   /* ring dp -> latency thread */
2815    CLatencyManager *                m_mgr;
2816};
2817
2818
2819
2820class CPerPortStats {
2821public:
2822    uint64_t opackets;
2823    uint64_t obytes;
2824    uint64_t ipackets;
2825    uint64_t ibytes;
2826    uint64_t ierrors;
2827    uint64_t oerrors;
2828    tx_per_flow_t m_tx_per_flow[MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD];
2829    tx_per_flow_t m_prev_tx_per_flow[MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD];
2830
2831    float     m_total_tx_bps;
2832    float     m_total_tx_pps;
2833
2834    float     m_total_rx_bps;
2835    float     m_total_rx_pps;
2836
2837    float     m_cpu_util;
2838    bool      m_link_up = true;
2839    bool      m_link_was_down = false;
2840};
2841
2842class CGlobalStats {
2843public:
2844    enum DumpFormat {
2845        dmpSTANDARD,
2846        dmpTABLE
2847    };
2848
2849    uint64_t  m_total_tx_pkts;
2850    uint64_t  m_total_rx_pkts;
2851    uint64_t  m_total_tx_bytes;
2852    uint64_t  m_total_rx_bytes;
2853
2854    uint64_t  m_total_alloc_error;
2855    uint64_t  m_total_queue_full;
2856    uint64_t  m_total_queue_drop;
2857
2858    uint64_t  m_total_clients;
2859    uint64_t  m_total_servers;
2860    uint64_t  m_active_sockets;
2861
2862    uint64_t  m_total_nat_time_out;
2863    uint64_t  m_total_nat_time_out_wait_ack;
2864    uint64_t  m_total_nat_no_fid  ;
2865    uint64_t  m_total_nat_active  ;
2866    uint64_t  m_total_nat_syn_wait;
2867    uint64_t  m_total_nat_open    ;
2868    uint64_t  m_total_nat_learn_error    ;
2869
2870    CPerTxthreadTemplateInfo m_template;
2871
2872    float     m_socket_util;
2873
2874    float m_platform_factor;
2875    float m_tx_bps;
2876    float m_rx_bps;
2877    float m_tx_pps;
2878    float m_rx_pps;
2879    float m_tx_cps;
2880    float m_tx_expected_cps;
2881    float m_tx_expected_pps;
2882    float m_tx_expected_bps;
2883    float m_rx_drop_bps;
2884    float m_active_flows;
2885    float m_open_flows;
2886    float m_cpu_util;
2887    float m_cpu_util_raw;
2888    float m_rx_cpu_util;
2889    float m_bw_per_core;
2890    uint8_t m_threads;
2891
2892    uint32_t      m_num_of_ports;
2893    CPerPortStats m_port[TREX_MAX_PORTS];
2894public:
2895    void Dump(FILE *fd,DumpFormat mode);
2896    void DumpAllPorts(FILE *fd);
2897    void dump_json(std::string & json, bool baseline);
2898private:
2899    std::string get_field(const char *name, float &f);
2900    std::string get_field(const char *name, uint64_t &f);
2901    std::string get_field_port(int port, const char *name, float &f);
2902    std::string get_field_port(int port, const char *name, uint64_t &f);
2903
2904};
2905
2906std::string CGlobalStats::get_field(const char *name, float &f){
2907    char buff[200];
2908    if(f <= -10.0 or f >= 10.0)
2909        snprintf(buff, sizeof(buff), "\"%s\":%.1f,",name,f);
2910    else
2911        snprintf(buff, sizeof(buff), "\"%s\":%.3e,",name,f);
2912    return (std::string(buff));
2913}
2914
2915std::string CGlobalStats::get_field(const char *name, uint64_t &f){
2916    char buff[200];
2917    snprintf(buff,  sizeof(buff), "\"%s\":%llu,", name, (unsigned long long)f);
2918    return (std::string(buff));
2919}
2920
2921std::string CGlobalStats::get_field_port(int port, const char *name, float &f){
2922    char buff[200];
2923    if(f <= -10.0 or f >= 10.0)
2924        snprintf(buff,  sizeof(buff), "\"%s-%d\":%.1f,", name, port, f);
2925    else
2926        snprintf(buff, sizeof(buff), "\"%s-%d\":%.3e,", name, port, f);
2927    return (std::string(buff));
2928}
2929
2930std::string CGlobalStats::get_field_port(int port, const char *name, uint64_t &f){
2931    char buff[200];
2932    snprintf(buff, sizeof(buff), "\"%s-%d\":%llu,",name, port, (unsigned long long)f);
2933    return (std::string(buff));
2934}
2935
2936
2937void CGlobalStats::dump_json(std::string & json, bool baseline){
2938    /* refactor this to JSON */
2939
2940    json="{\"name\":\"trex-global\",\"type\":0,";
2941    if (baseline) {
2942        json += "\"baseline\": true,";
2943    }
2944
2945    json +="\"data\":{";
2946
2947    char ts_buff[200];
2948    snprintf(ts_buff , sizeof(ts_buff), "\"ts\":{\"value\":%lu, \"freq\":%lu},", os_get_hr_tick_64(), os_get_hr_freq());
2949    json+= std::string(ts_buff);
2950
2951#define GET_FIELD(f) get_field(#f, f)
2952#define GET_FIELD_PORT(p,f) get_field_port(p, #f, lp->f)
2953
2954    json+=GET_FIELD(m_cpu_util);
2955    json+=GET_FIELD(m_cpu_util_raw);
2956    json+=GET_FIELD(m_bw_per_core);
2957    json+=GET_FIELD(m_rx_cpu_util);
2958    json+=GET_FIELD(m_platform_factor);
2959    json+=GET_FIELD(m_tx_bps);
2960    json+=GET_FIELD(m_rx_bps);
2961    json+=GET_FIELD(m_tx_pps);
2962    json+=GET_FIELD(m_rx_pps);
2963    json+=GET_FIELD(m_tx_cps);
2964    json+=GET_FIELD(m_tx_expected_cps);
2965    json+=GET_FIELD(m_tx_expected_pps);
2966    json+=GET_FIELD(m_tx_expected_bps);
2967    json+=GET_FIELD(m_total_alloc_error);
2968    json+=GET_FIELD(m_total_queue_full);
2969    json+=GET_FIELD(m_total_queue_drop);
2970    json+=GET_FIELD(m_rx_drop_bps);
2971    json+=GET_FIELD(m_active_flows);
2972    json+=GET_FIELD(m_open_flows);
2973
2974    json+=GET_FIELD(m_total_tx_pkts);
2975    json+=GET_FIELD(m_total_rx_pkts);
2976    json+=GET_FIELD(m_total_tx_bytes);
2977    json+=GET_FIELD(m_total_rx_bytes);
2978
2979    json+=GET_FIELD(m_total_clients);
2980    json+=GET_FIELD(m_total_servers);
2981    json+=GET_FIELD(m_active_sockets);
2982    json+=GET_FIELD(m_socket_util);
2983
2984    json+=GET_FIELD(m_total_nat_time_out);
2985    json+=GET_FIELD(m_total_nat_time_out_wait_ack);
2986    json+=GET_FIELD(m_total_nat_no_fid );
2987    json+=GET_FIELD(m_total_nat_active );
2988    json+=GET_FIELD(m_total_nat_syn_wait);
2989    json+=GET_FIELD(m_total_nat_open   );
2990    json+=GET_FIELD(m_total_nat_learn_error);
2991
2992    int i;
2993    for (i=0; i<(int)m_num_of_ports; i++) {
2994        CPerPortStats * lp=&m_port[i];
2995        json+=GET_FIELD_PORT(i,opackets) ;
2996        json+=GET_FIELD_PORT(i,obytes)   ;
2997        json+=GET_FIELD_PORT(i,ipackets) ;
2998        json+=GET_FIELD_PORT(i,ibytes)   ;
2999        json+=GET_FIELD_PORT(i,ierrors)  ;
3000        json+=GET_FIELD_PORT(i,oerrors)  ;
3001        json+=GET_FIELD_PORT(i,m_total_tx_bps);
3002        json+=GET_FIELD_PORT(i,m_total_tx_pps);
3003        json+=GET_FIELD_PORT(i,m_total_rx_bps);
3004        json+=GET_FIELD_PORT(i,m_total_rx_pps);
3005        json+=GET_FIELD_PORT(i,m_cpu_util);
3006    }
3007    json+=m_template.dump_as_json("template");
3008    json+="\"unknown\":0}}"  ;
3009}
3010
3011void CGlobalStats::DumpAllPorts(FILE *fd){
3012
3013    //fprintf (fd," Total-Tx-Pkts   : %s  \n",double_to_human_str((double)m_total_tx_pkts,"pkts",KBYE_1000).c_str());
3014    //fprintf (fd," Total-Rx-Pkts   : %s  \n",double_to_human_str((double)m_total_rx_pkts,"pkts",KBYE_1000).c_str());
3015
3016    //fprintf (fd," Total-Tx-Bytes  : %s  \n",double_to_human_str((double)m_total_tx_bytes,"bytes",KBYE_1000).c_str());
3017    //fprintf (fd," Total-Rx-Bytes  : %s  \n",double_to_human_str((double)m_total_rx_bytes,"bytes",KBYE_1000).c_str());
3018
3019
3020
3021    fprintf (fd," Cpu Utilization : %2.1f  %%  %2.1f Gb/core \n",m_cpu_util,m_bw_per_core);
3022    fprintf (fd," Platform_factor : %2.1f  \n",m_platform_factor);
3023    fprintf (fd," Total-Tx        : %s  ",double_to_human_str(m_tx_bps,"bps",KBYE_1000).c_str());
3024    if ( CGlobalInfo::is_learn_mode() ) {
3025        fprintf (fd," NAT time out    : %8llu", (unsigned long long)m_total_nat_time_out);
3026        if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
3027            fprintf (fd," (%llu in wait for syn+ack)\n", (unsigned long long)m_total_nat_time_out_wait_ack);
3028        } else {
3029            fprintf (fd, "\n");
3030        }
3031    }else{
3032        fprintf (fd,"\n");
3033    }
3034
3035
3036    fprintf (fd," Total-Rx        : %s  ",double_to_human_str(m_rx_bps,"bps",KBYE_1000).c_str());
3037    if ( CGlobalInfo::is_learn_mode() ) {
3038        fprintf (fd," NAT aged flow id: %8llu \n", (unsigned long long)m_total_nat_no_fid);
3039    }else{
3040        fprintf (fd,"\n");
3041    }
3042
3043    fprintf (fd," Total-PPS       : %s  ",double_to_human_str(m_tx_pps,"pps",KBYE_1000).c_str());
3044    if ( CGlobalInfo::is_learn_mode() ) {
3045        fprintf (fd," Total NAT active: %8llu", (unsigned long long)m_total_nat_active);
3046        if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
3047            fprintf (fd," (%llu waiting for syn)\n", (unsigned long long)m_total_nat_syn_wait);
3048        } else {
3049            fprintf (fd, "\n");
3050        }
3051    }else{
3052        fprintf (fd,"\n");
3053    }
3054
3055    fprintf (fd," Total-CPS       : %s  ",double_to_human_str(m_tx_cps,"cps",KBYE_1000).c_str());
3056    if ( CGlobalInfo::is_learn_mode() ) {
3057        fprintf (fd," Total NAT opened: %8llu \n", (unsigned long long)m_total_nat_open);
3058    }else{
3059        fprintf (fd,"\n");
3060    }
3061    fprintf (fd,"\n");
3062    fprintf (fd," Expected-PPS    : %s  ",double_to_human_str(m_tx_expected_pps,"pps",KBYE_1000).c_str());
3063    if ( CGlobalInfo::is_learn_verify_mode() ) {
3064        fprintf (fd," NAT learn errors: %8llu \n", (unsigned long long)m_total_nat_learn_error);
3065    }else{
3066        fprintf (fd,"\n");
3067    }
3068    fprintf (fd," Expected-CPS    : %s  \n",double_to_human_str(m_tx_expected_cps,"cps",KBYE_1000).c_str());
3069    fprintf (fd," Expected-BPS    : %s  \n",double_to_human_str(m_tx_expected_bps,"bps",KBYE_1000).c_str());
3070    fprintf (fd,"\n");
3071    fprintf (fd," Active-flows    : %8llu  Clients : %8llu   Socket-util : %3.4f %%    \n",
3072             (unsigned long long)m_active_flows,
3073             (unsigned long long)m_total_clients,
3074             m_socket_util);
3075    fprintf (fd," Open-flows      : %8llu  Servers : %8llu   Socket : %8llu Socket/Clients :  %.1f \n",
3076             (unsigned long long)m_open_flows,
3077             (unsigned long long)m_total_servers,
3078             (unsigned long long)m_active_sockets,
3079             (float)m_active_sockets/(float)m_total_clients);
3080
3081    if (m_total_alloc_error) {
3082        fprintf (fd," Total_alloc_err  : %llu         \n", (unsigned long long)m_total_alloc_error);
3083    }
3084    if ( m_total_queue_full ){
3085        fprintf (fd," Total_queue_full : %llu         \n", (unsigned long long)m_total_queue_full);
3086    }
3087    if (m_total_queue_drop) {
3088        fprintf (fd," Total_queue_drop : %llu         \n", (unsigned long long)m_total_queue_drop);
3089    }
3090
3091    //m_template.Dump(fd);
3092
3093    fprintf (fd," drop-rate       : %s   \n",double_to_human_str(m_rx_drop_bps,"bps",KBYE_1000).c_str() );
3094}
3095
3096
3097void CGlobalStats::Dump(FILE *fd,DumpFormat mode){
3098    int i;
3099    int port_to_show=m_num_of_ports;
3100    if (port_to_show>4) {
3101        port_to_show=4;
3102        fprintf (fd," per port - limited to 4   \n");
3103    }
3104
3105
3106    if ( mode== dmpSTANDARD ){
3107        fprintf (fd," --------------- \n");
3108        for (i=0; i<(int)port_to_show; i++) {
3109            CPerPortStats * lp=&m_port[i];
3110            fprintf(fd,"port : %d ",(int)i);
3111            if ( ! lp->m_link_up ) {
3112                fprintf(fd," (link DOWN)");
3113            }
3114            fprintf(fd,"\n------------\n");
3115#define GS_DP_A4(f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)lp->f)
3116#define GS_DP_A(f) if (lp->f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)lp->f)
3117            GS_DP_A4(opackets);
3118            GS_DP_A4(obytes);
3119            GS_DP_A4(ipackets);
3120            GS_DP_A4(ibytes);
3121            GS_DP_A(ierrors);
3122            GS_DP_A(oerrors);
3123            fprintf (fd," Tx : %s  \n",double_to_human_str((double)lp->m_total_tx_bps,"bps",KBYE_1000).c_str());
3124        }
3125    }else{
3126        fprintf(fd," %10s ","ports");
3127        for (i=0; i<(int)port_to_show; i++) {
3128            CPerPortStats * lp=&m_port[i];
3129            if ( lp->m_link_up ) {
3130                fprintf(fd,"| %15d ",i);
3131            } else {
3132                std::string port_with_state = "(link DOWN) " + std::to_string(i);
3133                fprintf(fd,"| %15s ",port_with_state.c_str());
3134            }
3135        }
3136        fprintf(fd,"\n");
3137        fprintf(fd," -----------------------------------------------------------------------------------------\n");
3138        std::string names[]={"opackets","obytes","ipackets","ibytes","ierrors","oerrors","Tx Bw"
3139        };
3140        for (i=0; i<7; i++) {
3141            fprintf(fd," %10s ",names[i].c_str());
3142            int j=0;
3143            for (j=0; j<port_to_show;j++) {
3144                CPerPortStats * lp=&m_port[j];
3145                uint64_t cnt;
3146                switch (i) {
3147                case 0:
3148                    cnt=lp->opackets;
3149                    fprintf(fd,"| %15lu ",cnt);
3150
3151                    break;
3152                case 1:
3153                    cnt=lp->obytes;
3154                    fprintf(fd,"| %15lu ",cnt);
3155
3156                    break;
3157                case 2:
3158                    cnt=lp->ipackets;
3159                    fprintf(fd,"| %15lu ",cnt);
3160
3161                    break;
3162                case 3:
3163                    cnt=lp->ibytes;
3164                    fprintf(fd,"| %15lu ",cnt);
3165
3166                    break;
3167                case 4:
3168                    cnt=lp->ierrors;
3169                    fprintf(fd,"| %15lu ",cnt);
3170
3171                    break;
3172                case 5:
3173                    cnt=lp->oerrors;
3174                    fprintf(fd,"| %15lu ",cnt);
3175
3176                    break;
3177                case 6:
3178                    fprintf(fd,"| %15s ",double_to_human_str((double)lp->m_total_tx_bps,"bps",KBYE_1000).c_str());
3179                    break;
3180                default:
3181                    cnt=0xffffff;
3182                }
3183            } /* ports */
3184            fprintf(fd, "\n");
3185        }/* fields*/
3186    }
3187
3188
3189}
3190
3191class CGlobalTRex  {
3192
3193public:
3194
3195    /**
3196     * different types of shutdown causes
3197     */
3198    typedef enum {
3199        SHUTDOWN_NONE,
3200        SHUTDOWN_TEST_ENDED,
3201        SHUTDOWN_CTRL_C,
3202        SHUTDOWN_SIGINT,
3203        SHUTDOWN_SIGTERM,
3204        SHUTDOWN_RPC_REQ
3205    } shutdown_rc_e;
3206
3207    CGlobalTRex (){
3208        m_max_ports=4;
3209        m_max_cores=1;
3210        m_cores_to_dual_ports=0;
3211        m_max_queues_per_port=0;
3212        m_fl_was_init=false;
3213        m_expected_pps=0.0;
3214        m_expected_cps=0.0;
3215        m_expected_bps=0.0;
3216        m_trex_stateless = NULL;
3217        m_mark_for_shutdown = SHUTDOWN_NONE;
3218    }
3219
3220    bool Create();
3221    void Delete();
3222    int  ixgbe_prob_init();
3223    int  cores_prob_init();
3224    int  queues_prob_init();
3225    int  ixgbe_start();
3226    int  ixgbe_rx_queue_flush();
3227    void rx_stf_conf();
3228    void rx_sl_configure();
3229    bool is_all_links_are_up(bool dump=false);
3230    void pre_test();
3231
3232    /**
3233     * mark for shutdown
3234     * on the next check - the control plane will
3235     * call shutdown()
3236     */
3237    void mark_for_shutdown(shutdown_rc_e rc) {
3238
3239        if (is_marked_for_shutdown()) {
3240            return;
3241        }
3242
3243        m_mark_for_shutdown = rc;
3244    }
3245
3246private:
3247    void register_signals();
3248
3249    /* try to stop all datapath cores and RX core */
3250    void try_stop_all_cores();
3251    /* send message to all dp cores */
3252    int  send_message_all_dp(TrexStatelessCpToDpMsgBase *msg);
3253    int  send_message_to_rx(TrexStatelessCpToRxMsgBase *msg);
3254    void check_for_dp_message_from_core(int thread_id);
3255
3256    bool is_marked_for_shutdown() const {
3257        return (m_mark_for_shutdown != SHUTDOWN_NONE);
3258    }
3259
3260    /**
3261     * shutdown sequence
3262     *
3263     */
3264    void shutdown();
3265
3266public:
3267    void check_for_dp_messages();
3268    int start_master_statefull();
3269    int start_master_stateless();
3270    int run_in_core(virtual_thread_id_t virt_core_id);
3271    int core_for_rx(){
3272        if ( (! get_is_rx_thread_enabled()) ) {
3273            return -1;
3274        }else{
3275            return m_max_cores - 1;
3276        }
3277    }
3278    int run_in_rx_core();
3279    int run_in_master();
3280
3281    void handle_fast_path();
3282    void handle_slow_path();
3283
3284    int stop_master();
3285    /* return the minimum number of dp cores needed to support the active ports
3286       this is for c==1 or  m_cores_mul==1
3287    */
3288    int get_base_num_cores(){
3289        return (m_max_ports>>1);
3290    }
3291
3292    int get_cores_tx(){
3293        /* 0 - master
3294           num_of_cores -
3295           last for latency */
3296        if ( (! get_is_rx_thread_enabled()) ) {
3297            return (m_max_cores - 1 );
3298        } else {
3299            return (m_max_cores - BP_MASTER_AND_LATENCY );
3300        }
3301    }
3302
3303private:
3304    bool is_all_cores_finished();
3305
3306public:
3307
3308    void publish_async_data(bool sync_now, bool baseline = false);
3309    void publish_async_barrier(uint32_t key);
3310    void publish_async_port_attr_changed(uint8_t port_id);
3311
3312    void dump_stats(FILE *fd,
3313                    CGlobalStats::DumpFormat format);
3314    void dump_template_info(std::string & json);
3315    bool sanity_check();
3316    void update_stats(void);
3317    tx_per_flow_t get_flow_tx_stats(uint8_t port, uint16_t hw_id);
3318    tx_per_flow_t clear_flow_tx_stats(uint8_t port, uint16_t index, bool is_lat);
3319    void get_stats(CGlobalStats & stats);
3320    float get_cpu_util_per_interface(uint8_t port_id);
3321    void dump_post_test_stats(FILE *fd);
3322    void dump_config(FILE *fd);
3323    void dump_links_status(FILE *fd);
3324
3325    bool lookup_port_by_mac(const uint8_t *mac, uint8_t &port_id);
3326
3327public:
3328    port_cfg_t  m_port_cfg;
3329    uint32_t    m_max_ports;    /* active number of ports supported options are  2,4,8,10,12  */
3330    uint32_t    m_max_cores;    /* current number of cores , include master and latency  ==> ( master)1+c*(m_max_ports>>1)+1( latency )  */
3331    uint32_t    m_cores_mul;    /* how cores multipler given  c=4 ==> m_cores_mul */
3332    uint32_t    m_max_queues_per_port; // Number of TX queues per port
3333    uint32_t    m_cores_to_dual_ports; /* number of TX cores allocated for each port pair */
3334    uint16_t    m_rx_core_tx_q_id; /* TX q used by rx core */
3335    // statistic
3336    CPPSMeasure  m_cps;
3337    float        m_expected_pps;
3338    float        m_expected_cps;
3339    float        m_expected_bps;//bps
3340    float        m_last_total_cps;
3341
3342    CPhyEthIF   m_ports[TREX_MAX_PORTS];
3343    CCoreEthIF          m_cores_vif_sf[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserved - stateful */
3344    CCoreEthIFStateless m_cores_vif_sl[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserved - stateless*/
3345    CCoreEthIF *        m_cores_vif[BP_MAX_CORES];
3346    CParserOption m_po ;
3347    CFlowGenList  m_fl;
3348    bool          m_fl_was_init;
3349    volatile uint8_t       m_signal[BP_MAX_CORES] __rte_cache_aligned ; // Signal to main core when DP thread finished
3350    volatile bool m_sl_rx_running; // Signal main core when RX thread finished
3351    CLatencyManager     m_mg; // statefull RX core
3352    CRxCoreStateless    m_rx_sl; // stateless RX core
3353    CTrexGlobalIoMode   m_io_modes;
3354    CTRexExtendedDriverBase * m_drv;
3355
3356private:
3357    CLatencyHWPort      m_latency_vports[TREX_MAX_PORTS];    /* read hardware driver */
3358    CLatencyVmPort      m_latency_vm_vports[TREX_MAX_PORTS]; /* vm driver */
3359    CLatencyPktInfo     m_latency_pkt;
3360    TrexPublisher       m_zmq_publisher;
3361    CGlobalStats        m_stats;
3362    uint32_t            m_stats_cnt;
3363    std::mutex          m_cp_lock;
3364
3365    TrexMonitor         m_monitor;
3366    shutdown_rc_e       m_mark_for_shutdown;
3367
3368public:
3369    TrexStateless       *m_trex_stateless;
3370
3371};
3372
3373// Before starting, send gratuitous ARP on our addresses, and try to resolve dst MAC addresses.
3374void CGlobalTRex::pre_test() {
3375    CTrexDpdkParams dpdk_p;
3376    get_ex_drv()->get_dpdk_drv_params(dpdk_p);
3377    CPretest pretest(m_max_ports, dpdk_p.rx_data_q_num + dpdk_p.rx_drop_q_num);
3378    bool resolve_needed = false;
3379    uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
3380    bool need_grat_arp[TREX_MAX_PORTS];
3381
3382    if (CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
3383        std::vector<ClientCfgCompactEntry *> conf;
3384        m_fl.get_client_cfg_ip_list(conf);
3385
3386        // If we got src MAC for port in global config, take it, otherwise use src MAC from DPDK
3387        uint8_t port_macs[m_max_ports][ETHER_ADDR_LEN];
3388        for (int port_id = 0; port_id < m_max_ports; port_id++) {
3389            memcpy(port_macs[port_id], CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, ETHER_ADDR_LEN);
3390        }
3391
3392        for (std::vector<ClientCfgCompactEntry *>::iterator it = conf.begin(); it != conf.end(); it++) {
3393            uint8_t port = (*it)->get_port();
3394            uint16_t vlan = (*it)->get_vlan();
3395            uint32_t count = (*it)->get_count();
3396            uint32_t dst_ip = (*it)->get_dst_ip();
3397            uint32_t src_ip = (*it)->get_src_ip();
3398
3399            for (int i = 0; i < count; i++) {
3400                //??? handle ipv6;
3401                if ((*it)->is_ipv4()) {
3402                    pretest.add_next_hop(port, dst_ip + i, vlan);
3403                }
3404            }
3405            if (!src_ip) {
3406                src_ip = CGlobalInfo::m_options.m_ip_cfg[port].get_ip();
3407                if (!src_ip) {
3408                    fprintf(stderr, "No matching src ip for port: %d ip:%s vlan: %d\n"
3409                            , port, ip_to_str(dst_ip).c_str(), vlan);
3410                    fprintf(stderr, "You must specify src_ip in client config file or in TRex config file\n");
3411                    exit(1);
3412                }
3413            }
3414            pretest.add_ip(port, src_ip, vlan, port_macs[port]);
3415            COneIPv4Info ipv4(src_ip, vlan, port_macs[port], port);
3416            m_mg.add_grat_arp_src(ipv4);
3417
3418            delete *it;
3419        }
3420        if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
3421            fprintf(stdout, "*******Pretest for client cfg********\n");
3422            pretest.dump(stdout);
3423            }
3424    } else {
3425        for (int port_id = 0; port_id < m_max_ports; port_id++) {
3426            if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
3427                resolve_needed = true;
3428            } else {
3429                resolve_needed = false;
3430            }
3431
3432            need_grat_arp[port_id] = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip() != 0;
3433
3434            pretest.add_ip(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip()
3435                           , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan()
3436                           , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
3437
3438            if (resolve_needed) {
3439                pretest.add_next_hop(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw()
3440                                     , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan());
3441            }
3442        }
3443    }
3444
3445    for (int port_id = 0; port_id < m_max_ports; port_id++) {
3446        CPhyEthIF *pif = &m_ports[port_id];
3447        // Configure port to send all packets to software
3448        pif->set_port_rcv_all(true);
3449    }
3450
3451    pretest.send_grat_arp_all();
3452    bool ret;
3453    int count = 0;
3454    bool resolve_failed = false;
3455    do {
3456        ret = pretest.resolve_all();
3457        count++;
3458    } while ((ret != true) && (count < 10));
3459    if (ret != true) {
3460        resolve_failed = true;
3461    }
3462
3463    if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
3464        fprintf(stdout, "*******Pretest after resolving ********\n");
3465        pretest.dump(stdout);
3466    }
3467
3468    if (CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
3469        CManyIPInfo pretest_result;
3470        pretest.get_results(pretest_result);
3471        if (resolve_failed) {
3472            fprintf(stderr, "Resolution of following IPs failed. Exiting.\n");
3473            for (const COneIPInfo *ip=pretest_result.get_next(); ip != NULL;
3474                   ip = pretest_result.get_next()) {
3475                if (ip->resolve_needed()) {
3476                    ip->dump(stderr, "  ");
3477                }
3478            }
3479            exit(1);
3480        }
3481        m_fl.set_client_config_resolved_macs(pretest_result);
3482        if ( CGlobalInfo::m_options.preview.getVMode() > 1) {
3483            m_fl.dump_client_config(stdout);
3484        }
3485
3486        bool port_found[TREX_MAX_PORTS];
3487        for (int port_id = 0; port_id < m_max_ports; port_id++) {
3488            port_found[port_id] = false;
3489        }
3490        // If client config enabled, we don't resolve MACs from trex_cfg.yaml. For latency (-l)
3491        // We need to able to send packets from RX core, so need to configure MAC/vlan for each port.
3492        for (const COneIPInfo *ip=pretest_result.get_next(); ip != NULL; ip = pretest_result.get_next()) {
3493            // Use first MAC/vlan we see on each port
3494            uint8_t port_id = ip->get_port();
3495            uint16_t vlan = ip->get_vlan();
3496            if ( ! port_found[port_id]) {
3497                port_found[port_id] = true;
3498                ip->get_mac(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest);
3499                CGlobalInfo::m_options.m_ip_cfg[port_id].set_vlan(vlan);
3500            }
3501        }
3502    } else {
3503        uint8_t mac[ETHER_ADDR_LEN];
3504        for (int port_id = 0; port_id < m_max_ports; port_id++) {
3505            if (! memcmp(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
3506                // we don't have dest MAC. Get it from what we resolved.
3507                uint32_t ip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
3508                uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan();
3509
3510                if (!pretest.get_mac(port_id, ip, vlan, mac)) {
3511                    fprintf(stderr, "Failed resolving dest MAC for default gateway:%d.%d.%d.%d on port %d\n"
3512                            , (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF, port_id);
3513
3514                    if (get_is_stateless()) {
3515                        continue;
3516                    } else {
3517                        exit(1);
3518                    }
3519                }
3520
3521
3522
3523                memcpy(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, mac, ETHER_ADDR_LEN);
3524                // if port is connected in loopback, no need to send gratuitous ARP. It will only confuse our ingress counters.
3525                if (need_grat_arp[port_id] && (! pretest.is_loopback(port_id))) {
3526                    COneIPv4Info ipv4(CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip()
3527                                      , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan()
3528                                      , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src
3529                                      , port_id);
3530                    m_mg.add_grat_arp_src(ipv4);
3531                }
3532            }
3533
3534            // update statistics baseline, so we can ignore what happened in pre test phase
3535            CPhyEthIF *pif = &m_ports[port_id];
3536            CPreTestStats pre_stats = pretest.get_stats(port_id);
3537            pif->set_ignore_stats_base(pre_stats);
3538            // Configure port back to normal mode. Only relevant packets handled by software.
3539            pif->set_port_rcv_all(false);
3540        }
3541    }
3542
3543    /* for stateless only - set port mode */
3544    if (get_is_stateless()) {
3545        for (int port_id = 0; port_id < m_max_ports; port_id++) {
3546            uint32_t src_ipv4 = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip();
3547            uint32_t dg = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
3548            const uint8_t *dst_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest;
3549
3550            /* L3 mode */
3551            if (src_ipv4 && dg) {
3552                if (memcmp(dst_mac, empty_mac, 6) == 0) {
3553                    m_trex_stateless->get_port_by_id(port_id)->set_l3_mode(src_ipv4, dg);
3554                } else {
3555                    m_trex_stateless->get_port_by_id(port_id)->set_l3_mode(src_ipv4, dg, dst_mac);
3556                }
3557
3558            /* L2 mode */
3559            } else if (CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.is_set) {
3560                m_trex_stateless->get_port_by_id(port_id)->set_l2_mode(dst_mac);
3561            }
3562        }
3563    }
3564
3565
3566}
3567
3568/**
3569 * check for a single core
3570 *
3571 * @author imarom (19-Nov-15)
3572 *
3573 * @param thread_id
3574 */
3575void
3576CGlobalTRex::check_for_dp_message_from_core(int thread_id) {
3577
3578    CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(thread_id);
3579
3580    /* fast path check */
3581    if ( likely ( ring->isEmpty() ) ) {
3582        return;
3583    }
3584
3585    while ( true ) {
3586        CGenNode * node = NULL;
3587        if (ring->Dequeue(node) != 0) {
3588            break;
3589        }
3590        assert(node);
3591
3592        TrexStatelessDpToCpMsgBase * msg = (TrexStatelessDpToCpMsgBase *)node;
3593        msg->handle();
3594        delete msg;
3595    }
3596
3597}
3598
3599/**
3600 * check for messages that arrived from DP to CP
3601 *
3602 */
3603void
3604CGlobalTRex::check_for_dp_messages() {
3605
3606    /* for all the cores - check for a new message */
3607    for (int i = 0; i < get_cores_tx(); i++) {
3608        check_for_dp_message_from_core(i);
3609    }
3610}
3611
3612bool CGlobalTRex::is_all_links_are_up(bool dump){
3613    bool all_link_are=true;
3614    int i;
3615    for (i=0; i<m_max_ports; i++) {
3616        CPhyEthIF * _if=&m_ports[i];
3617        _if->get_port_attr()->update_link_status();
3618        if ( dump ){
3619            _if->dump_stats(stdout);
3620        }
3621        if ( _if->get_port_attr()->is_link_up() == false){
3622            all_link_are=false;
3623            break;
3624        }
3625    }
3626    return (all_link_are);
3627}
3628
3629void CGlobalTRex::try_stop_all_cores(){
3630
3631    TrexStatelessDpQuit * dp_msg= new TrexStatelessDpQuit();
3632    send_message_all_dp(dp_msg);
3633    delete dp_msg;
3634
3635    if (get_is_stateless()) {
3636        TrexStatelessRxQuit * rx_msg= new TrexStatelessRxQuit();
3637        send_message_to_rx(rx_msg);
3638    }
3639
3640    // no need to delete rx_msg. Deleted by receiver
3641    bool all_core_finished = false;
3642    int i;
3643    for (i=0; i<20; i++) {
3644        if ( is_all_cores_finished() ){
3645            all_core_finished =true;
3646            break;
3647        }
3648        delay(100);
3649    }
3650    if ( all_core_finished ){
3651        m_zmq_publisher.publish_event(TrexPublisher::EVENT_SERVER_STOPPED);
3652        printf(" All cores stopped !! \n");
3653    }else{
3654        printf(" ERROR one of the DP core is stucked !\n");
3655    }
3656}
3657
3658
3659int  CGlobalTRex::send_message_all_dp(TrexStatelessCpToDpMsgBase *msg){
3660
3661    int max_threads=(int)CMsgIns::Ins()->getCpDp()->get_num_threads();
3662    int i;
3663
3664    for (i=0; i<max_threads; i++) {
3665        CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingCpToDp((uint8_t)i);
3666        ring->Enqueue((CGenNode*)msg->clone());
3667    }
3668    return (0);
3669}
3670
3671int CGlobalTRex::send_message_to_rx(TrexStatelessCpToRxMsgBase *msg) {
3672    CNodeRing *ring = CMsgIns::Ins()->getCpRx()->getRingCpToDp(0);
3673    ring->Enqueue((CGenNode *) msg);
3674
3675    return (0);
3676}
3677
3678
3679int  CGlobalTRex::ixgbe_rx_queue_flush(){
3680    int i;
3681    for (i=0; i<m_max_ports; i++) {
3682        CPhyEthIF * _if=&m_ports[i];
3683        _if->flush_rx_queue();
3684    }
3685    return (0);
3686}
3687
3688
3689// init stateful rx core
3690void CGlobalTRex::rx_stf_conf(void) {
3691    int i;
3692    CLatencyManagerCfg mg_cfg;
3693    mg_cfg.m_max_ports = m_max_ports;
3694
3695    uint32_t latency_rate=CGlobalInfo::m_options.m_latency_rate;
3696
3697    if ( latency_rate ) {
3698        mg_cfg.m_cps = (double)latency_rate ;
3699    } else {
3700        // If RX core needed, we need something to make the scheduler running.
3701        // If nothing configured, send 1 CPS latency measurement packets.
3702        if (CGlobalInfo::m_options.m_arp_ref_per == 0) {
3703            mg_cfg.m_cps = 1.0;
3704        } else {
3705            mg_cfg.m_cps = 0;
3706        }
3707    }
3708
3709    if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) {
3710        /* vm mode, indirect queues  */
3711        for (i=0; i<m_max_ports; i++) {
3712            CPhyEthIF * _if = &m_ports[i];
3713            CMessagingManager * rx_dp=CMsgIns::Ins()->getRxDp();
3714
3715            uint8_t thread_id = (i>>1);
3716
3717            CNodeRing * r = rx_dp->getRingCpToDp(thread_id);
3718            m_latency_vm_vports[i].Create((uint8_t)i, r, &m_mg, _if);
3719
3720            mg_cfg.m_ports[i] =&m_latency_vm_vports[i];
3721        }
3722
3723    }else{
3724        for (i=0; i<m_max_ports; i++) {
3725            CPhyEthIF * _if=&m_ports[i];
3726            _if->dump_stats(stdout);
3727            m_latency_vports[i].Create(_if, m_rx_core_tx_q_id, 1);
3728
3729            mg_cfg.m_ports[i] =&m_latency_vports[i];
3730        }
3731    }
3732
3733
3734    m_mg.Create(&mg_cfg);
3735    m_mg.set_mask(CGlobalInfo::m_options.m_latency_mask);
3736}
3737
3738// init m_rx_sl object for stateless rx core
3739void CGlobalTRex::rx_sl_configure(void) {
3740    CRxSlCfg rx_sl_cfg;
3741    int i;
3742
3743    rx_sl_cfg.m_max_ports = m_max_ports;
3744    rx_sl_cfg.m_tx_cores  = get_cores_tx();
3745
3746    if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) {
3747        /* vm mode, indirect queues  */
3748        for (i=0; i < m_max_ports; i++) {
3749            CPhyEthIF * _if = &m_ports[i];
3750            CMessagingManager * rx_dp = CMsgIns::Ins()->getRxDp();
3751            uint8_t thread_id = (i >> 1);
3752            CNodeRing * r = rx_dp->getRingCpToDp(thread_id);
3753            m_latency_vm_vports[i].Create(i, r, &m_mg, _if);
3754            rx_sl_cfg.m_ports[i] = &m_latency_vm_vports[i];
3755        }
3756    } else {
3757        for (i = 0; i < m_max_ports; i++) {
3758            CPhyEthIF * _if = &m_ports[i];
3759            m_latency_vports[i].Create(_if, m_rx_core_tx_q_id, 1);
3760            rx_sl_cfg.m_ports[i] = &m_latency_vports[i];
3761        }
3762    }
3763
3764    m_rx_sl.create(rx_sl_cfg);
3765}
3766
3767int  CGlobalTRex::ixgbe_start(void){
3768    int i;
3769    for (i=0; i<m_max_ports; i++) {
3770        socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)i);
3771        assert(CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
3772        CPhyEthIF * _if=&m_ports[i];
3773        _if->Create((uint8_t)i);
3774        _if->conf_queues();
3775        _if->stats_clear();
3776        _if->start();
3777        _if->configure_rx_duplicate_rules();
3778
3779        if ( get_ex_drv()->flow_ctrl_chg_supp()
3780             && ! CGlobalInfo::m_options.preview.get_is_disable_flow_control_setting()
3781             && _if->get_port_attr()->is_fc_change_supported()) {
3782            _if->disable_flow_control();
3783        }
3784
3785        _if->get_port_attr()->add_mac((char *)CGlobalInfo::m_options.get_src_mac_addr(i));
3786
3787        fflush(stdout);
3788    }
3789
3790    if ( !is_all_links_are_up()  ){
3791        /* wait for ports to be stable */
3792        get_ex_drv()->wait_for_stable_link();
3793
3794        if ( !is_all_links_are_up() /*&& !get_is_stateless()*/ ){ // disable start with link down for now
3795
3796            /* temporary solution for trex-192 issue, solve the case for X710/XL710, will work for both Statless and Stateful */
3797            if (  get_ex_drv()->drop_packets_incase_of_linkdown() ){
3798                printf(" WARNING : there is no link on one of the ports, driver support auto drop in case of link down - continue\n");
3799            }else{
3800                dump_links_status(stdout);
3801                rte_exit(EXIT_FAILURE, " One of the links is down \n");
3802            }
3803        }
3804    } else {
3805        get_ex_drv()->wait_after_link_up();
3806    }
3807
3808    dump_links_status(stdout);
3809
3810    ixgbe_rx_queue_flush();
3811
3812    if (! get_is_stateless()) {
3813        rx_stf_conf();
3814    }
3815
3816
3817    /* core 0 - control
3818       core 1 - port 0-0,1-0,
3819       core 2 - port 2-0,3-0,
3820       core 3 - port 0-1,1-1,
3821       core 4 - port 2-1,3-1,
3822
3823    */
3824    int port_offset=0;
3825    uint8_t lat_q_id;
3826
3827    if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) {
3828        lat_q_id = 0;
3829    } else {
3830        lat_q_id = get_cores_tx() / get_base_num_cores() + 1;
3831    }
3832    for (i=0; i<get_cores_tx(); i++) {
3833        int j=(i+1);
3834        int queue_id=((j-1)/get_base_num_cores() );   /* for the first min core queue 0 , then queue 1 etc */
3835        if ( get_is_stateless() ){
3836            m_cores_vif[j]=&m_cores_vif_sl[j];
3837        }else{
3838            m_cores_vif[j]=&m_cores_vif_sf[j];
3839        }
3840        m_cores_vif[j]->Create(j,
3841                               queue_id,
3842                               &m_ports[port_offset], /* 0,2*/
3843                               queue_id,
3844                               &m_ports[port_offset+1], /*1,3*/
3845                               lat_q_id);
3846        port_offset+=2;
3847        if (port_offset == m_max_ports) {
3848            port_offset = 0;
3849            // We want to allow sending latency packets only from first core handling a port
3850            lat_q_id = CCoreEthIF::INVALID_Q_ID;
3851        }
3852    }
3853
3854    fprintf(stdout," -------------------------------\n");
3855    fprintf(stdout, "RX core uses TX queue number %d on all ports\n", m_rx_core_tx_q_id);
3856    CCoreEthIF::DumpIfCfgHeader(stdout);
3857    for (i=0; i<get_cores_tx(); i++) {
3858        m_cores_vif[i+1]->DumpIfCfg(stdout);
3859    }
3860    fprintf(stdout," -------------------------------\n");
3861
3862    return (0);
3863}
3864
3865static void trex_termination_handler(int signum);
3866
3867void CGlobalTRex::register_signals() {
3868    struct sigaction action;
3869
3870    /* handler */
3871    action.sa_handler = trex_termination_handler;
3872
3873    /* blocked signals during handling */
3874    sigemptyset(&action.sa_mask);
3875    sigaddset(&action.sa_mask, SIGINT);
3876    sigaddset(&action.sa_mask, SIGTERM);
3877
3878    /* no flags */
3879    action.sa_flags = 0;
3880
3881    /* register */
3882    sigaction(SIGINT,  &action, NULL);
3883    sigaction(SIGTERM, &action, NULL);
3884}
3885
3886bool CGlobalTRex::Create(){
3887    CFlowsYamlInfo     pre_yaml_info;
3888
3889    register_signals();
3890
3891    m_stats_cnt =0;
3892    if (!get_is_stateless()) {
3893        pre_yaml_info.load_from_yaml_file(CGlobalInfo::m_options.cfg_file);
3894        if ( CGlobalInfo::m_options.preview.getVMode() > 0){
3895            CGlobalInfo::m_options.dump(stdout);
3896            CGlobalInfo::m_memory_cfg.Dump(stdout);
3897        }
3898    }
3899
3900    if ( !m_zmq_publisher.Create( CGlobalInfo::m_options.m_zmq_port,
3901                                  !CGlobalInfo::m_options.preview.get_zmq_publish_enable() ) ){
3902        return (false);
3903    }
3904
3905    if ( pre_yaml_info.m_vlan_info.m_enable ){
3906        CGlobalInfo::m_options.preview.set_vlan_mode_verify(CPreviewMode::VLAN_MODE_LOAD_BALANCE);
3907    }
3908    /* End update pre flags */
3909
3910    ixgbe_prob_init();
3911    cores_prob_init();
3912    queues_prob_init();
3913
3914    /* allocate rings */
3915    assert( CMsgIns::Ins()->Create(get_cores_tx()) );
3916
3917    if ( sizeof(CGenNodeNatInfo) != sizeof(CGenNode)  ) {
3918        printf("ERROR sizeof(CGenNodeNatInfo) %lu != sizeof(CGenNode) %lu must be the same size \n",sizeof(CGenNodeNatInfo),sizeof(CGenNode));
3919        assert(0);
3920    }
3921
3922    if ( sizeof(CGenNodeLatencyPktInfo) != sizeof(CGenNode)  ) {
3923        printf("ERROR sizeof(CGenNodeLatencyPktInfo) %lu != sizeof(CGenNode) %lu must be the same size \n",sizeof(CGenNodeLatencyPktInfo),sizeof(CGenNode));
3924        assert(0);
3925    }
3926
3927    /* allocate the memory */
3928    CTrexDpdkParams dpdk_p;
3929    get_ex_drv()->get_dpdk_drv_params(dpdk_p);
3930
3931    CGlobalInfo::init_pools(m_max_ports *
3932                            (dpdk_p.rx_data_q_num * dpdk_p.rx_desc_num_data_q +
3933                             dpdk_p.rx_drop_q_num * dpdk_p.rx_desc_num_drop_q));
3934    ixgbe_start();
3935    dump_config(stdout);
3936
3937    /* start stateless */
3938    if (get_is_stateless()) {
3939
3940        TrexStatelessCfg cfg;
3941
3942        TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_TCP,
3943                                             global_platform_cfg_info.m_zmq_rpc_port,
3944                                             &m_cp_lock);
3945
3946        cfg.m_port_count         = CGlobalInfo::m_options.m_expected_portd;
3947        cfg.m_rpc_req_resp_cfg   = &rpc_req_resp_cfg;
3948        cfg.m_rpc_server_verbose = false;
3949        cfg.m_platform_api       = new TrexDpdkPlatformApi();
3950        cfg.m_publisher          = &m_zmq_publisher;
3951
3952        m_trex_stateless = new TrexStateless(cfg);
3953
3954        rx_sl_configure();
3955    }
3956
3957    return (true);
3958
3959}
3960void CGlobalTRex::Delete(){
3961
3962    m_zmq_publisher.Delete();
3963
3964    if (m_trex_stateless) {
3965        delete m_trex_stateless;
3966        m_trex_stateless = NULL;
3967    }
3968
3969    m_fl.Delete();
3970
3971}
3972
3973
3974
3975int  CGlobalTRex::ixgbe_prob_init(void){
3976
3977    m_max_ports  = rte_eth_dev_count();
3978    if (m_max_ports == 0)
3979        rte_exit(EXIT_FAILURE, "Error: Could not find supported ethernet ports. You are probably trying to use unsupported NIC \n");
3980
3981    printf(" Number of ports found: %d \n",m_max_ports);
3982
3983    if ( m_max_ports %2 !=0 ) {
3984        rte_exit(EXIT_FAILURE, " Number of ports in config file is %d. It should be even. Please use --limit-ports, or change 'port_limit:' in the config file\n",
3985                 m_max_ports);
3986    }
3987
3988    if ( CGlobalInfo::m_options.get_expected_ports() > TREX_MAX_PORTS ) {
3989        rte_exit(EXIT_FAILURE, " Maximum number of ports supported is %d. You are trying to use %d. Please use --limit-ports, or change 'port_limit:' in the config file\n"
3990                 ,TREX_MAX_PORTS, CGlobalInfo::m_options.get_expected_ports());
3991    }
3992
3993    if ( CGlobalInfo::m_options.get_expected_ports() > m_max_ports ){
3994        rte_exit(EXIT_FAILURE, " There are %d ports available. You are trying to use %d. Please use --limit-ports, or change 'port_limit:' in the config file\n",
3995                 m_max_ports,
3996                 CGlobalInfo::m_options.get_expected_ports());
3997    }
3998    if (CGlobalInfo::m_options.get_expected_ports() < m_max_ports ) {
3999        /* limit the number of ports */
4000        m_max_ports=CGlobalInfo::m_options.get_expected_ports();
4001    }
4002    assert(m_max_ports <= TREX_MAX_PORTS);
4003
4004    struct rte_eth_dev_info dev_info;
4005    rte_eth_dev_info_get((uint8_t) 0,&dev_info);
4006
4007    if ( CGlobalInfo::m_options.preview.getVMode() > 0){
4008        printf("\n\n");
4009        printf("if_index : %d \n",dev_info.if_index);
4010        printf("driver name : %s \n",dev_info.driver_name);
4011        printf("min_rx_bufsize : %d \n",dev_info.min_rx_bufsize);
4012        printf("max_rx_pktlen  : %d \n",dev_info.max_rx_pktlen);
4013        printf("max_rx_queues  : %d \n",dev_info.max_rx_queues);
4014        printf("max_tx_queues  : %d \n",dev_info.max_tx_queues);
4015        printf("max_mac_addrs  : %d \n",dev_info.max_mac_addrs);
4016
4017        printf("rx_offload_capa : 0x%x \n",dev_info.rx_offload_capa);
4018        printf("tx_offload_capa : 0x%x \n",dev_info.tx_offload_capa);
4019        printf("rss reta_size   : %d \n",dev_info.reta_size);
4020        printf("flow_type_rss   : 0x%lx \n",dev_info.flow_type_rss_offloads);
4021    }
4022
4023    int i;
4024    struct rte_eth_dev_info dev_info1;
4025
4026    for (i=1; i<m_max_ports; i++) {
4027        rte_eth_dev_info_get((uint8_t) i,&dev_info1);
4028        if ( strcmp(dev_info1.driver_name,dev_info.driver_name)!=0) {
4029            printf(" ERROR all device should have the same type  %s != %s \n",dev_info1.driver_name,dev_info.driver_name);
4030            exit(1);
4031        }
4032    }
4033
4034    m_drv = CTRexExtendedDriverDb::Ins()->get_drv();
4035
4036    // check if firmware version is new enough
4037    for (i = 0; i < m_max_ports; i++) {
4038        if (m_drv->verify_fw_ver(i) < 0) {
4039            // error message printed by verify_fw_ver
4040            exit(1);
4041        }
4042    }
4043
4044    m_port_cfg.update_var();
4045
4046    if ( get_is_rx_filter_enable() ){
4047        m_port_cfg.update_global_config_fdir();
4048    }
4049
4050    if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) {
4051        /* verify that we have only one thread/core per dual- interface */
4052        if ( CGlobalInfo::m_options.preview.getCores()>1 ) {
4053            printf("Error: the number of cores should be 1 when the driver support only one tx queue and one rx queue. Please use -c 1 \n");
4054            exit(1);
4055        }
4056    }
4057    return (0);
4058}
4059
4060int  CGlobalTRex::cores_prob_init(){
4061    m_max_cores = rte_lcore_count();
4062    assert(m_max_cores>0);
4063    return (0);
4064}
4065
4066int  CGlobalTRex::queues_prob_init(){
4067
4068    if (m_max_cores < 2) {
4069        rte_exit(EXIT_FAILURE, "number of cores should be at least 2 \n");
4070    }
4071
4072    assert((m_max_ports>>1) <= get_cores_tx() );
4073
4074    m_cores_mul = CGlobalInfo::m_options.preview.getCores();
4075
4076    m_cores_to_dual_ports  = m_cores_mul;
4077
4078    /* core 0 - control
4079       -core 1 - port 0/1
4080       -core 2 - port 2/3
4081       -core 3 - port 0/1
4082       -core 4 - port 2/3
4083
4084       m_cores_to_dual_ports = 2;
4085    */
4086
4087    // One q for each core allowed to send on this port + 1 for latency q (Used in stateless) + 1 for RX core.
4088    m_max_queues_per_port  = m_cores_to_dual_ports + 2;
4089
4090    if (m_max_queues_per_port > BP_MAX_TX_QUEUE) {
4091        rte_exit(EXIT_FAILURE,
4092                 "Error: Number of TX queues exceeds %d. Try running with lower -c <val> \n",BP_MAX_TX_QUEUE);
4093    }
4094
4095    assert(m_max_queues_per_port>0);
4096    return (0);
4097}
4098
4099
4100void CGlobalTRex::dump_config(FILE *fd){
4101    fprintf(fd," number of ports         : %u \n",m_max_ports);
4102    fprintf(fd," max cores for 2 ports   : %u \n",m_cores_to_dual_ports);
4103    fprintf(fd," max queue per port      : %u \n",m_max_queues_per_port);
4104}
4105
4106
4107void CGlobalTRex::dump_links_status(FILE *fd){
4108    for (int i=0; i<m_max_ports; i++) {
4109        m_ports[i].get_port_attr()->update_link_status_nowait();
4110        m_ports[i].get_port_attr()->dump_link(fd);
4111    }
4112}
4113
4114bool CGlobalTRex::lookup_port_by_mac(const uint8_t *mac, uint8_t &port_id) {
4115    for (int i = 0; i < m_max_ports; i++) {
4116        if (memcmp(m_ports[i].get_port_attr()->get_layer_cfg().get_ether().get_src(), mac, 6) == 0) {
4117            port_id = i;
4118            return true;
4119        }
4120    }
4121
4122    return false;
4123}
4124
4125void CGlobalTRex::dump_post_test_stats(FILE *fd){
4126    uint64_t pkt_out=0;
4127    uint64_t pkt_out_bytes=0;
4128    uint64_t pkt_in_bytes=0;
4129    uint64_t pkt_in=0;
4130    uint64_t sw_pkt_out=0;
4131    uint64_t sw_pkt_out_err=0;
4132    uint64_t sw_pkt_out_bytes=0;
4133    uint64_t tx_arp = 0;
4134    uint64_t rx_arp = 0;
4135
4136    int i;
4137    for (i=0; i<get_cores_tx(); i++) {
4138        CCoreEthIF * erf_vif = m_cores_vif[i+1];
4139        CVirtualIFPerSideStats stats;
4140        erf_vif->GetCoreCounters(&stats);
4141        sw_pkt_out     += stats.m_tx_pkt;
4142        sw_pkt_out_err += stats.m_tx_drop +stats.m_tx_queue_full +stats.m_tx_alloc_error ;
4143        sw_pkt_out_bytes +=stats.m_tx_bytes;
4144    }
4145
4146
4147    for (i=0; i<m_max_ports; i++) {
4148        CPhyEthIF * _if=&m_ports[i];
4149        pkt_in  +=_if->get_stats().ipackets;
4150        pkt_in_bytes +=_if->get_stats().ibytes;
4151        pkt_out +=_if->get_stats().opackets;
4152        pkt_out_bytes +=_if->get_stats().obytes;
4153        tx_arp += _if->get_ignore_stats().get_tx_arp();
4154        rx_arp += _if->get_ignore_stats().get_rx_arp();
4155    }
4156    if ( CGlobalInfo::m_options.is_latency_enabled() ){
4157        sw_pkt_out += m_mg.get_total_pkt();
4158        sw_pkt_out_bytes +=m_mg.get_total_bytes();
4159    }
4160
4161
4162    fprintf (fd," summary stats \n");
4163    fprintf (fd," -------------- \n");
4164
4165    if (pkt_in > pkt_out)
4166        {
4167            fprintf (fd, " Total-pkt-drop       : 0 pkts \n");
4168            if (pkt_in > pkt_out * 1.01)
4169                fprintf (fd, " Warning : number of rx packets exceeds 101%% of tx packets!\n");
4170        }
4171    else
4172        fprintf (fd, " Total-pkt-drop       : %llu pkts \n", (unsigned long long) (pkt_out - pkt_in));
4173    for (i=0; i<m_max_ports; i++) {
4174        if ( m_stats.m_port[i].m_link_was_down ) {
4175            fprintf (fd, " WARNING: Link was down at port %d during test (at least for some time)!\n", i);
4176        }
4177    }
4178    fprintf (fd," Total-tx-bytes       : %llu bytes \n", (unsigned long long)pkt_out_bytes);
4179    fprintf (fd," Total-tx-sw-bytes    : %llu bytes \n", (unsigned long long)sw_pkt_out_bytes);
4180    fprintf (fd," Total-rx-bytes       : %llu byte \n", (unsigned long long)pkt_in_bytes);
4181
4182    fprintf (fd," \n");
4183
4184    fprintf (fd," Total-tx-pkt         : %llu pkts \n", (unsigned long long)pkt_out);
4185    fprintf (fd," Total-rx-pkt         : %llu pkts \n", (unsigned long long)pkt_in);
4186    fprintf (fd," Total-sw-tx-pkt      : %llu pkts \n", (unsigned long long)sw_pkt_out);
4187    fprintf (fd," Total-sw-err         : %llu pkts \n", (unsigned long long)sw_pkt_out_err);
4188    fprintf (fd," Total ARP sent       : %llu pkts \n", (unsigned long long)tx_arp);
4189    fprintf (fd," Total ARP received   : %llu pkts \n", (unsigned long long)rx_arp);
4190
4191
4192    if ( CGlobalInfo::m_options.is_latency_enabled() ){
4193        fprintf (fd," maximum-latency   : %.0f usec \n",m_mg.get_max_latency());
4194        fprintf (fd," average-latency   : %.0f usec \n",m_mg.get_avr_latency());
4195        fprintf (fd," latency-any-error : %s  \n",m_mg.is_any_error()?"ERROR":"OK");
4196    }
4197
4198
4199}
4200
4201
4202void CGlobalTRex::update_stats(){
4203
4204    int i;
4205    for (i=0; i<m_max_ports; i++) {
4206        CPhyEthIF * _if=&m_ports[i];
4207        _if->update_counters();
4208    }
4209    uint64_t total_open_flows=0;
4210
4211
4212    CFlowGenListPerThread   * lpt;
4213    for (i=0; i<get_cores_tx(); i++) {
4214        lpt = m_fl.m_threads_info[i];
4215        total_open_flows +=   lpt->m_stats.m_total_open_flows ;
4216    }
4217    m_last_total_cps = m_cps.add(total_open_flows);
4218
4219}
4220
4221tx_per_flow_t CGlobalTRex::get_flow_tx_stats(uint8_t port, uint16_t index) {
4222    return m_stats.m_port[port].m_tx_per_flow[index] - m_stats.m_port[port].m_prev_tx_per_flow[index];
4223}
4224
4225// read stats. Return read value, and clear.
4226tx_per_flow_t CGlobalTRex::clear_flow_tx_stats(uint8_t port, uint16_t index, bool is_lat) {
4227    uint8_t port0;
4228    CFlowGenListPerThread * lpt;
4229    tx_per_flow_t ret;
4230
4231    m_stats.m_port[port].m_tx_per_flow[index].clear();
4232
4233    for (int i=0; i < get_cores_tx(); i++) {
4234        lpt = m_fl.m_threads_info[i];
4235        port0 = lpt->getDualPortId() * 2;
4236        if ((port == port0) || (port == port0 + 1)) {
4237            m_stats.m_port[port].m_tx_per_flow[index] +=
4238                lpt->m_node_gen.m_v_if->m_stats[port - port0].m_tx_per_flow[index];
4239            if (is_lat)
4240                lpt->m_node_gen.m_v_if->m_stats[port - port0].m_lat_data[index - MAX_FLOW_STATS].reset();
4241        }
4242    }
4243
4244    ret = m_stats.m_port[port].m_tx_per_flow[index] - m_stats.m_port[port].m_prev_tx_per_flow[index];
4245
4246    // Since we return diff from prev, following "clears" the stats.
4247    m_stats.m_port[port].m_prev_tx_per_flow[index] = m_stats.m_port[port].m_tx_per_flow[index];
4248
4249    return ret;
4250}
4251
4252void CGlobalTRex::get_stats(CGlobalStats & stats){
4253
4254    int i;
4255    float total_tx=0.0;
4256    float total_rx=0.0;
4257    float total_tx_pps=0.0;
4258    float total_rx_pps=0.0;
4259
4260    stats.m_total_tx_pkts  = 0;
4261    stats.m_total_rx_pkts  = 0;
4262    stats.m_total_tx_bytes = 0;
4263    stats.m_total_rx_bytes = 0;
4264    stats.m_total_alloc_error=0;
4265    stats.m_total_queue_full=0;
4266    stats.m_total_queue_drop=0;
4267
4268
4269    stats.m_num_of_ports = m_max_ports;
4270    stats.m_cpu_util = m_fl.GetCpuUtil();
4271    stats.m_cpu_util_raw = m_fl.GetCpuUtilRaw();
4272    if (get_is_stateless()) {
4273        stats.m_rx_cpu_util = m_rx_sl.get_cpu_util();
4274    }
4275    stats.m_threads      = m_fl.m_threads_info.size();
4276
4277    for (i=0; i<m_max_ports; i++) {
4278        CPhyEthIF * _if=&m_ports[i];
4279        CPerPortStats * stp=&stats.m_port[i];
4280
4281        CPhyEthIFStats & st =_if->get_stats();
4282
4283        stp->opackets = st.opackets;
4284        stp->obytes   = st.obytes;
4285        stp->ipackets = st.ipackets;
4286        stp->ibytes   = st.ibytes;
4287        stp->ierrors  = st.ierrors;
4288        stp->oerrors  = st.oerrors;
4289        stp->m_total_tx_bps = _if->get_last_tx_rate()*_1Mb_DOUBLE;
4290        stp->m_total_tx_pps = _if->get_last_tx_pps_rate();
4291        stp->m_total_rx_bps = _if->get_last_rx_rate()*_1Mb_DOUBLE;
4292        stp->m_total_rx_pps = _if->get_last_rx_pps_rate();
4293        stp->m_link_up        = _if->get_port_attr()->is_link_up();
4294        stp->m_link_was_down |= ! _if->get_port_attr()->is_link_up();
4295
4296        stats.m_total_tx_pkts  += st.opackets;
4297        stats.m_total_rx_pkts  += st.ipackets;
4298        stats.m_total_tx_bytes += st.obytes;
4299        stats.m_total_rx_bytes += st.ibytes;
4300
4301        total_tx +=_if->get_last_tx_rate();
4302        total_rx +=_if->get_last_rx_rate();
4303        total_tx_pps +=_if->get_last_tx_pps_rate();
4304        total_rx_pps +=_if->get_last_rx_pps_rate();
4305        // IP ID rules
4306        for (uint16_t flow = 0; flow <= max_stat_hw_id_seen; flow++) {
4307            stats.m_port[i].m_tx_per_flow[flow].clear();
4308        }
4309        // payload rules
4310        for (uint16_t flow = MAX_FLOW_STATS; flow <= MAX_FLOW_STATS + max_stat_hw_id_seen_payload; flow++) {
4311            stats.m_port[i].m_tx_per_flow[flow].clear();
4312        }
4313
4314        stp->m_cpu_util = get_cpu_util_per_interface(i);
4315
4316    }
4317
4318    uint64_t total_open_flows=0;
4319    uint64_t total_active_flows=0;
4320
4321    uint64_t total_clients=0;
4322    uint64_t total_servers=0;
4323    uint64_t active_sockets=0;
4324    uint64_t total_sockets=0;
4325
4326
4327    uint64_t total_nat_time_out =0;
4328    uint64_t total_nat_time_out_wait_ack =0;
4329    uint64_t total_nat_no_fid   =0;
4330    uint64_t total_nat_active   =0;
4331    uint64_t total_nat_syn_wait = 0;
4332    uint64_t total_nat_open     =0;
4333    uint64_t total_nat_learn_error=0;
4334
4335    CFlowGenListPerThread   * lpt;
4336    stats.m_template.Clear();
4337    for (i=0; i<get_cores_tx(); i++) {
4338        lpt = m_fl.m_threads_info[i];
4339        total_open_flows +=   lpt->m_stats.m_total_open_flows ;
4340        total_active_flows += (lpt->m_stats.m_total_open_flows-lpt->m_stats.m_total_close_flows) ;
4341
4342        stats.m_total_alloc_error += lpt->m_node_gen.m_v_if->m_stats[0].m_tx_alloc_error+
4343            lpt->m_node_gen.m_v_if->m_stats[1].m_tx_alloc_error;
4344        stats.m_total_queue_full +=lpt->m_node_gen.m_v_if->m_stats[0].m_tx_queue_full+
4345            lpt->m_node_gen.m_v_if->m_stats[1].m_tx_queue_full;
4346
4347        stats.m_total_queue_drop +=lpt->m_node_gen.m_v_if->m_stats[0].m_tx_drop+
4348            lpt->m_node_gen.m_v_if->m_stats[1].m_tx_drop;
4349
4350        stats.m_template.Add(&lpt->m_node_gen.m_v_if->m_stats[0].m_template);
4351        stats.m_template.Add(&lpt->m_node_gen.m_v_if->m_stats[1].m_template);
4352
4353
4354        total_clients   += lpt->m_smart_gen.getTotalClients();
4355        total_servers   += lpt->m_smart_gen.getTotalServers();
4356        active_sockets  += lpt->m_smart_gen.ActiveSockets();
4357        total_sockets   += lpt->m_smart_gen.MaxSockets();
4358
4359        total_nat_time_out +=lpt->m_stats.m_nat_flow_timeout;
4360        total_nat_time_out_wait_ack += lpt->m_stats.m_nat_flow_timeout_wait_ack;
4361        total_nat_no_fid   +=lpt->m_stats.m_nat_lookup_no_flow_id ;
4362        total_nat_active   +=lpt->m_stats.m_nat_lookup_add_flow_id - lpt->m_stats.m_nat_lookup_remove_flow_id;
4363        total_nat_syn_wait += lpt->m_stats.m_nat_lookup_add_flow_id - lpt->m_stats.m_nat_lookup_wait_ack_state;
4364        total_nat_open     +=lpt->m_stats.m_nat_lookup_add_flow_id;
4365        total_nat_learn_error   +=lpt->m_stats.m_nat_flow_learn_error;
4366        uint8_t port0 = lpt->getDualPortId() *2;
4367        // IP ID rules
4368        for (uint16_t flow = 0; flow <= max_stat_hw_id_seen; flow++) {
4369            stats.m_port[port0].m_tx_per_flow[flow] +=
4370                lpt->m_node_gen.m_v_if->m_stats[0].m_tx_per_flow[flow];
4371            stats.m_port[port0 + 1].m_tx_per_flow[flow] +=
4372                lpt->m_node_gen.m_v_if->m_stats[1].m_tx_per_flow[flow];
4373        }
4374        // payload rules
4375        for (uint16_t flow = MAX_FLOW_STATS; flow <= MAX_FLOW_STATS + max_stat_hw_id_seen_payload; flow++) {
4376            stats.m_port[port0].m_tx_per_flow[flow] +=
4377                lpt->m_node_gen.m_v_if->m_stats[0].m_tx_per_flow[flow];
4378            stats.m_port[port0 + 1].m_tx_per_flow[flow] +=
4379                lpt->m_node_gen.m_v_if->m_stats[1].m_tx_per_flow[flow];
4380        }
4381
4382    }
4383
4384    stats.m_total_nat_time_out = total_nat_time_out;
4385    stats.m_total_nat_time_out_wait_ack = total_nat_time_out_wait_ack;
4386    stats.m_total_nat_no_fid   = total_nat_no_fid;
4387    stats.m_total_nat_active   = total_nat_active;
4388    stats.m_total_nat_syn_wait = total_nat_syn_wait;
4389    stats.m_total_nat_open     = total_nat_open;
4390    stats.m_total_nat_learn_error     = total_nat_learn_error;
4391
4392    stats.m_total_clients = total_clients;
4393    stats.m_total_servers = total_servers;
4394    stats.m_active_sockets = active_sockets;
4395
4396    if (total_sockets != 0) {
4397        stats.m_socket_util =100.0*(double)active_sockets/(double)total_sockets;
4398    } else {
4399        stats.m_socket_util = 0;
4400    }
4401
4402
4403
4404    float drop_rate=total_tx-total_rx;
4405    if ( (drop_rate<0.0)  || (drop_rate < 0.1*total_tx ) )  {
4406        drop_rate=0.0;
4407    }
4408    float pf =CGlobalInfo::m_options.m_platform_factor;
4409    stats.m_platform_factor = pf;
4410
4411    stats.m_active_flows = total_active_flows*pf;
4412    stats.m_open_flows   = total_open_flows*pf;
4413    stats.m_rx_drop_bps   = drop_rate*pf *_1Mb_DOUBLE;
4414
4415    stats.m_tx_bps        = total_tx*pf*_1Mb_DOUBLE;
4416    stats.m_rx_bps        = total_rx*pf*_1Mb_DOUBLE;
4417    stats.m_tx_pps        = total_tx_pps*pf;
4418    stats.m_rx_pps        = total_rx_pps*pf;
4419    stats.m_tx_cps        = m_last_total_cps*pf;
4420    if(stats.m_cpu_util < 0.0001)
4421        stats.m_bw_per_core = 0;
4422    else
4423        stats.m_bw_per_core   = 2*(stats.m_tx_bps/1e9)*100.0/(stats.m_cpu_util*stats.m_threads);
4424
4425    stats.m_tx_expected_cps        = m_expected_cps*pf;
4426    stats.m_tx_expected_pps        = m_expected_pps*pf;
4427    stats.m_tx_expected_bps        = m_expected_bps*pf;
4428}
4429
4430float
4431CGlobalTRex::get_cpu_util_per_interface(uint8_t port_id) {
4432    CPhyEthIF * _if = &m_ports[port_id];
4433
4434    float    tmp = 0;
4435    uint8_t  cnt = 0;
4436    for (const auto &p : _if->get_core_list()) {
4437        uint8_t core_id = p.first;
4438        CFlowGenListPerThread *lp = m_fl.m_threads_info[core_id];
4439        if (lp->is_port_active(port_id)) {
4440            tmp += lp->m_cpu_cp_u.GetVal();
4441            cnt++;
4442        }
4443    }
4444
4445    return ( (cnt > 0) ? (tmp / cnt) : 0);
4446
4447}
4448
4449bool CGlobalTRex::sanity_check(){
4450
4451    CFlowGenListPerThread   * lpt;
4452    uint32_t errors=0;
4453    int i;
4454    for (i=0; i<get_cores_tx(); i++) {
4455        lpt = m_fl.m_threads_info[i];
4456        errors   += lpt->m_smart_gen.getErrorAllocationCounter();
4457    }
4458
4459    if ( errors ) {
4460        printf(" ERRORs sockets allocation errors! \n");
4461        printf(" you should allocate more clients in the pool \n");
4462        return(true);
4463    }
4464    return ( false);
4465}
4466
4467
4468/* dump the template info */
4469void CGlobalTRex::dump_template_info(std::string & json){
4470    CFlowGenListPerThread   * lpt = m_fl.m_threads_info[0];
4471    CFlowsYamlInfo * yaml_info=&lpt->m_yaml_info;
4472
4473    json="{\"name\":\"template_info\",\"type\":0,\"data\":[";
4474    int i;
4475    for (i=0; i<yaml_info->m_vec.size()-1; i++) {
4476        CFlowYamlInfo * r=&yaml_info->m_vec[i] ;
4477        json+="\""+ r->m_name+"\"";
4478        json+=",";
4479    }
4480    json+="\""+yaml_info->m_vec[i].m_name+"\"";
4481    json+="]}" ;
4482}
4483
4484void CGlobalTRex::dump_stats(FILE *fd, CGlobalStats::DumpFormat format){
4485
4486    update_stats();
4487    get_stats(m_stats);
4488
4489    if (format==CGlobalStats::dmpTABLE) {
4490        if ( m_io_modes.m_g_mode == CTrexGlobalIoMode::gNORMAL ){
4491            switch (m_io_modes.m_pp_mode ){
4492            case CTrexGlobalIoMode::ppDISABLE:
4493                fprintf(fd,"\n+Per port stats disabled \n");
4494                break;
4495            case CTrexGlobalIoMode::ppTABLE:
4496                fprintf(fd,"\n-Per port stats table \n");
4497                m_stats.Dump(fd,CGlobalStats::dmpTABLE);
4498                break;
4499            case CTrexGlobalIoMode::ppSTANDARD:
4500                fprintf(fd,"\n-Per port stats - standard\n");
4501                m_stats.Dump(fd,CGlobalStats::dmpSTANDARD);
4502                break;
4503            };
4504
4505            switch (m_io_modes.m_ap_mode ){
4506            case   CTrexGlobalIoMode::apDISABLE:
4507                fprintf(fd,"\n+Global stats disabled \n");
4508                break;
4509            case   CTrexGlobalIoMode::apENABLE:
4510                fprintf(fd,"\n-Global stats enabled \n");
4511                m_stats.DumpAllPorts(fd);
4512                break;
4513            };
4514        }
4515    }else{
4516        /* at exit , always need to dump it in standartd mode for scripts*/
4517        m_stats.Dump(fd,format);
4518        m_stats.DumpAllPorts(fd);
4519    }
4520
4521}
4522
4523void
4524CGlobalTRex::publish_async_data(bool sync_now, bool baseline) {
4525    std::string json;
4526
4527    /* refactor to update, dump, and etc. */
4528    if (sync_now) {
4529        update_stats();
4530        get_stats(m_stats);
4531    }
4532
4533    m_stats.dump_json(json, baseline);
4534    m_zmq_publisher.publish_json(json);
4535
4536    /* generator json , all cores are the same just sample the first one */
4537    m_fl.m_threads_info[0]->m_node_gen.dump_json(json);
4538    m_zmq_publisher.publish_json(json);
4539
4540
4541    if ( !get_is_stateless() ){
4542        dump_template_info(json);
4543        m_zmq_publisher.publish_json(json);
4544    }
4545
4546    if ( get_is_rx_check_mode() ) {
4547        m_mg.rx_check_dump_json(json );
4548        m_zmq_publisher.publish_json(json);
4549    }
4550
4551    /* backward compatible */
4552    m_mg.dump_json(json );
4553    m_zmq_publisher.publish_json(json);
4554
4555    /* more info */
4556    m_mg.dump_json_v2(json );
4557    m_zmq_publisher.publish_json(json);
4558
4559    if (get_is_stateless()) {
4560        std::string stat_json;
4561        std::string latency_json;
4562        if (m_trex_stateless->m_rx_flow_stat.dump_json(stat_json, latency_json, baseline)) {
4563            m_zmq_publisher.publish_json(stat_json);
4564            m_zmq_publisher.publish_json(latency_json);
4565        }
4566    }
4567}
4568
4569void
4570CGlobalTRex::publish_async_barrier(uint32_t key) {
4571    m_zmq_publisher.publish_barrier(key);
4572}
4573
4574void
4575CGlobalTRex:: publish_async_port_attr_changed(uint8_t port_id) {
4576    Json::Value data;
4577    data["port_id"] = port_id;
4578    TRexPortAttr * _attr = m_ports[port_id].get_port_attr();
4579
4580    _attr->to_json(data["attr"]);
4581
4582    m_zmq_publisher.publish_event(TrexPublisher::EVENT_PORT_ATTR_CHANGED, data);
4583}
4584
4585void
4586CGlobalTRex::handle_slow_path() {
4587    m_stats_cnt+=1;
4588
4589    // update speed, link up/down etc.
4590    for (int i=0; i<m_max_ports; i++) {
4591        bool changed = m_ports[i].get_port_attr()->update_link_status_nowait();
4592        if (changed) {
4593            publish_async_port_attr_changed(i);
4594        }
4595    }
4596
4597    if ( CGlobalInfo::m_options.preview.get_no_keyboard() ==false ) {
4598        if ( m_io_modes.handle_io_modes() ) {
4599            mark_for_shutdown(SHUTDOWN_CTRL_C);
4600            return;
4601        }
4602    }
4603
4604    if ( sanity_check() ) {
4605        mark_for_shutdown(SHUTDOWN_TEST_ENDED);
4606        return;
4607    }
4608
4609    if (m_io_modes.m_g_mode != CTrexGlobalIoMode::gDISABLE ) {
4610        fprintf(stdout,"\033[2J");
4611        fprintf(stdout,"\033[2H");
4612
4613    } else {
4614        if ( m_io_modes.m_g_disable_first  ) {
4615            m_io_modes.m_g_disable_first=false;
4616            fprintf(stdout,"\033[2J");
4617            fprintf(stdout,"\033[2H");
4618            printf("clean !!!\n");
4619            fflush(stdout);
4620        }
4621    }
4622
4623
4624    if (m_io_modes.m_g_mode == CTrexGlobalIoMode::gHELP ) {
4625        m_io_modes.DumpHelp(stdout);
4626    }
4627
4628    dump_stats(stdout,CGlobalStats::dmpTABLE);
4629
4630    if (m_io_modes.m_g_mode == CTrexGlobalIoMode::gNORMAL ) {
4631        fprintf (stdout," current time    : %.1f sec  \n",now_sec());
4632        float d= CGlobalInfo::m_options.m_duration - now_sec();
4633        if (d<0) {
4634            d=0;
4635
4636        }
4637        fprintf (stdout," test duration   : %.1f sec  \n",d);
4638    }
4639
4640    if (m_io_modes.m_g_mode == CTrexGlobalIoMode::gMem) {
4641
4642        if ( m_stats_cnt%4==0) {
4643            fprintf (stdout," %s \n",CGlobalInfo::dump_pool_as_json_str().c_str());
4644        }
4645    }
4646
4647
4648    if ( CGlobalInfo::m_options.is_rx_enabled() && (! get_is_stateless())) {
4649        m_mg.update();
4650
4651        if ( m_io_modes.m_g_mode ==  CTrexGlobalIoMode::gNORMAL ) {
4652            if (CGlobalInfo::m_options.m_latency_rate != 0) {
4653                switch (m_io_modes.m_l_mode) {
4654                case CTrexGlobalIoMode::lDISABLE:
4655                    fprintf(stdout, "\n+Latency stats disabled \n");
4656                    break;
4657                case CTrexGlobalIoMode::lENABLE:
4658                    fprintf(stdout, "\n-Latency stats enabled \n");
4659                    m_mg.DumpShort(stdout);
4660                    break;
4661                case CTrexGlobalIoMode::lENABLE_Extended:
4662                    fprintf(stdout, "\n-Latency stats extended \n");
4663                    m_mg.Dump(stdout);
4664                    break;
4665                }
4666            }
4667
4668            if ( get_is_rx_check_mode() ) {
4669
4670                switch (m_io_modes.m_rc_mode) {
4671                case CTrexGlobalIoMode::rcDISABLE:
4672                    fprintf(stdout,"\n+Rx Check stats disabled \n");
4673                    break;
4674                case CTrexGlobalIoMode::rcENABLE:
4675                    fprintf(stdout,"\n-Rx Check stats enabled \n");
4676                    m_mg.DumpShortRxCheck(stdout);
4677                    break;
4678                case CTrexGlobalIoMode::rcENABLE_Extended:
4679                    fprintf(stdout,"\n-Rx Check stats enhanced \n");
4680                    m_mg.DumpRxCheck(stdout);
4681                    break;
4682                }
4683            }
4684        }
4685    }
4686    if ( m_io_modes.m_g_mode ==  CTrexGlobalIoMode::gNAT ) {
4687        if ( m_io_modes.m_nat_mode == CTrexGlobalIoMode::natENABLE ) {
4688            if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
4689                fprintf(stdout, "NAT flow table info\n");
4690                m_mg.dump_nat_flow_table(stdout);
4691            } else {
4692                fprintf(stdout, "\nThis is only relevant in --learn-mode %d\n", CParserOption::LEARN_MODE_TCP_ACK);
4693            }
4694        }
4695    }
4696
4697    /* publish data */
4698    publish_async_data(false);
4699}
4700
4701
4702void
4703CGlobalTRex::handle_fast_path() {
4704    /* check from messages from DP */
4705    check_for_dp_messages();
4706
4707    /* measure CPU utilization by sampling (we sample 1000 to get an accurate sampling) */
4708    for (int i = 0; i < 1000; i++) {
4709        m_fl.UpdateFast();
4710
4711        if (get_is_stateless()) {
4712            m_rx_sl.update_cpu_util();
4713        }else{
4714            m_mg.update_fast();
4715        }
4716
4717        rte_pause();
4718    }
4719
4720
4721    if ( is_all_cores_finished() ) {
4722        mark_for_shutdown(SHUTDOWN_TEST_ENDED);
4723    }
4724}
4725
4726
4727/**
4728 * shutdown sequence
4729 *
4730 */
4731void CGlobalTRex::shutdown() {
4732    std::stringstream ss;
4733    ss << " *** TRex is shutting down - cause: '";
4734
4735    switch (m_mark_for_shutdown) {
4736
4737    case SHUTDOWN_TEST_ENDED:
4738        ss << "test has ended'";
4739        break;
4740
4741    case SHUTDOWN_CTRL_C:
4742        ss << "CTRL + C detected'";
4743        break;
4744
4745    case SHUTDOWN_SIGINT:
4746        ss << "received signal SIGINT'";
4747        break;
4748
4749    case SHUTDOWN_SIGTERM:
4750        ss << "received signal SIGTERM'";
4751        break;
4752
4753    case SHUTDOWN_RPC_REQ:
4754        ss << "server received RPC 'shutdown' request'";
4755        break;
4756
4757    default:
4758        assert(0);
4759    }
4760
4761    /* report */
4762    std::cout << ss.str() << "\n";
4763
4764    /* first stop the WD */
4765    TrexWatchDog::getInstance().stop();
4766
4767    /* stateless shutdown */
4768    if (get_is_stateless()) {
4769        m_trex_stateless->shutdown();
4770    }
4771
4772    if (!is_all_cores_finished()) {
4773        try_stop_all_cores();
4774    }
4775
4776    m_mg.stop();
4777
4778    delay(1000);
4779
4780    /* shutdown drivers */
4781    for (int i = 0; i < m_max_ports; i++) {
4782        m_ports[i].stop();
4783    }
4784
4785    if (m_mark_for_shutdown != SHUTDOWN_TEST_ENDED) {
4786        /* we should stop latency and exit to stop agents */
4787        Delete();
4788        utl_termio_reset();
4789        exit(-1);
4790    }
4791}
4792
4793
4794int CGlobalTRex::run_in_master() {
4795
4796    //rte_thread_setname(pthread_self(), "TRex Control");
4797
4798    if ( get_is_stateless() ) {
4799        m_trex_stateless->launch_control_plane();
4800    }
4801
4802    /* exception and scope safe */
4803    std::unique_lock<std::mutex> cp_lock(m_cp_lock);
4804
4805    uint32_t slow_path_counter = 0;
4806
4807    const int FASTPATH_DELAY_MS = 10;
4808    const int SLOWPATH_DELAY_MS = 500;
4809
4810    m_monitor.create("master", 2);
4811    TrexWatchDog::getInstance().register_monitor(&m_monitor);
4812
4813    TrexWatchDog::getInstance().start();
4814
4815    while (!is_marked_for_shutdown()) {
4816
4817        /* fast path */
4818        handle_fast_path();
4819
4820        /* slow path */
4821        if (slow_path_counter >= SLOWPATH_DELAY_MS) {
4822            handle_slow_path();
4823            slow_path_counter = 0;
4824        }
4825
4826        m_monitor.disable(30); //assume we will wake up
4827
4828        cp_lock.unlock();
4829        delay(FASTPATH_DELAY_MS);
4830        slow_path_counter += FASTPATH_DELAY_MS;
4831        cp_lock.lock();
4832
4833        m_monitor.enable();
4834    }
4835
4836    /* on exit release the lock */
4837    cp_lock.unlock();
4838
4839    /* shutdown everything gracefully */
4840    shutdown();
4841
4842    return (0);
4843}
4844
4845
4846
4847int CGlobalTRex::run_in_rx_core(void){
4848
4849    CPreviewMode *lp = &CGlobalInfo::m_options.preview;
4850
4851    rte_thread_setname(pthread_self(), "TRex RX");
4852
4853    /* set RT mode if set */
4854    if (lp->get_rt_prio_mode()) {
4855        struct sched_param param;
4856        param.sched_priority = sched_get_priority_max(SCHED_FIFO);
4857        if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
4858            perror("setting RT priroity mode on RX core failed with error");
4859            exit(EXIT_FAILURE);
4860        }
4861    }
4862
4863    if (get_is_stateless()) {
4864        m_sl_rx_running = true;
4865        m_rx_sl.start();
4866        m_sl_rx_running = false;
4867    } else {
4868        if ( CGlobalInfo::m_options.is_rx_enabled() ){
4869            m_sl_rx_running = false;
4870            m_mg.start(0, true);
4871        }
4872    }
4873
4874    return (0);
4875}
4876
4877int CGlobalTRex::run_in_core(virtual_thread_id_t virt_core_id){
4878    std::stringstream ss;
4879    CPreviewMode *lp = &CGlobalInfo::m_options.preview;
4880
4881    ss << "Trex DP core " << int(virt_core_id);
4882    rte_thread_setname(pthread_self(), ss.str().c_str());
4883
4884    /* set RT mode if set */
4885    if (lp->get_rt_prio_mode()) {
4886        struct sched_param param;
4887        param.sched_priority = sched_get_priority_max(SCHED_FIFO);
4888        if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
4889            perror("setting RT priroity mode on DP core failed with error");
4890            exit(EXIT_FAILURE);
4891        }
4892    }
4893
4894
4895    if ( lp->getSingleCore() &&
4896         (virt_core_id==2 ) &&
4897         (lp-> getCores() ==1) ){
4898        printf(" bypass this core \n");
4899        m_signal[virt_core_id]=1;
4900        return (0);
4901    }
4902
4903
4904    assert(m_fl_was_init);
4905    CFlowGenListPerThread   * lpt;
4906
4907    lpt = m_fl.m_threads_info[virt_core_id-1];
4908
4909    /* register a watchdog handle on current core */
4910    lpt->m_monitor.create(ss.str(), 1);
4911    TrexWatchDog::getInstance().register_monitor(&lpt->m_monitor);
4912
4913    if (get_is_stateless()) {
4914        lpt->start_stateless_daemon(*lp);
4915    }else{
4916        lpt->start_generate_stateful(CGlobalInfo::m_options.out_file,*lp);
4917    }
4918
4919    /* done - remove this from the watchdog (we might wait on join for a long time) */
4920    lpt->m_monitor.disable();
4921
4922    m_signal[virt_core_id]=1;
4923    return (0);
4924}
4925
4926
4927int CGlobalTRex::stop_master(){
4928
4929    delay(1000);
4930    fprintf(stdout," ==================\n");
4931    fprintf(stdout," interface sum \n");
4932    fprintf(stdout," ==================\n");
4933    dump_stats(stdout,CGlobalStats::dmpSTANDARD);
4934    fprintf(stdout," ==================\n");
4935    fprintf(stdout," \n\n");
4936
4937    fprintf(stdout," ==================\n");
4938    fprintf(stdout," interface sum \n");
4939    fprintf(stdout," ==================\n");
4940
4941    CFlowGenListPerThread   * lpt;
4942    uint64_t total_tx_rx_check=0;
4943
4944    int i;
4945    for (i=0; i<get_cores_tx(); i++) {
4946        lpt = m_fl.m_threads_info[i];
4947        CCoreEthIF * erf_vif = m_cores_vif[i+1];
4948
4949        erf_vif->DumpCoreStats(stdout);
4950        erf_vif->DumpIfStats(stdout);
4951        total_tx_rx_check+=erf_vif->m_stats[CLIENT_SIDE].m_tx_rx_check_pkt+
4952            erf_vif->m_stats[SERVER_SIDE].m_tx_rx_check_pkt;
4953    }
4954
4955    fprintf(stdout," ==================\n");
4956    fprintf(stdout," generators \n");
4957    fprintf(stdout," ==================\n");
4958    for (i=0; i<get_cores_tx(); i++) {
4959        lpt = m_fl.m_threads_info[i];
4960        lpt->m_node_gen.DumpHist(stdout);
4961        lpt->DumpStats(stdout);
4962    }
4963    if ( CGlobalInfo::m_options.is_latency_enabled() ){
4964        fprintf(stdout," ==================\n");
4965        fprintf(stdout," latency \n");
4966        fprintf(stdout," ==================\n");
4967        m_mg.DumpShort(stdout);
4968        m_mg.Dump(stdout);
4969        m_mg.DumpShortRxCheck(stdout);
4970        m_mg.DumpRxCheck(stdout);
4971        m_mg.DumpRxCheckVerification(stdout,total_tx_rx_check);
4972    }
4973
4974    dump_stats(stdout,CGlobalStats::dmpSTANDARD);
4975    dump_post_test_stats(stdout);
4976    publish_async_data(false);
4977
4978    return (0);
4979}
4980
4981bool CGlobalTRex::is_all_cores_finished() {
4982    int i;
4983    for (i=0; i<get_cores_tx(); i++) {
4984        if ( m_signal[i+1]==0){
4985            return false;
4986        }
4987    }
4988    if (m_sl_rx_running)
4989        return false;
4990
4991    return true;
4992}
4993
4994
4995int CGlobalTRex::start_master_stateless(){
4996    int i;
4997    for (i=0; i<BP_MAX_CORES; i++) {
4998        m_signal[i]=0;
4999    }
5000    m_fl.Create();
5001    m_expected_pps = 0;
5002    m_expected_cps = 0;
5003    m_expected_bps = 0;
5004
5005    m_fl.generate_p_thread_info(get_cores_tx());
5006    CFlowGenListPerThread   * lpt;
5007
5008    for (i=0; i<get_cores_tx(); i++) {
5009        lpt = m_fl.m_threads_info[i];
5010        CVirtualIF * erf_vif = m_cores_vif[i+1];
5011        lpt->set_vif(erf_vif);
5012        lpt->m_node_gen.m_socket_id =m_cores_vif[i+1]->get_socket_id();
5013    }
5014    m_fl_was_init=true;
5015
5016    return (0);
5017}
5018
5019int CGlobalTRex::start_master_statefull() {
5020    int i;
5021    for (i=0; i<BP_MAX_CORES; i++) {
5022        m_signal[i]=0;
5023    }
5024
5025    m_fl.Create();
5026    m_fl.load_from_yaml(CGlobalInfo::m_options.cfg_file,get_cores_tx());
5027
5028    if ( CGlobalInfo::m_options.m_active_flows>0 ) {
5029        m_fl.update_active_flows(CGlobalInfo::m_options.m_active_flows);
5030    }
5031
5032    /* client config */
5033    if (CGlobalInfo::m_options.client_cfg_file != "") {
5034        try {
5035            m_fl.load_client_config_file(CGlobalInfo::m_options.client_cfg_file);
5036        } catch (const std::runtime_error &e) {
5037            std::cout << "\n*** " << e.what() << "\n\n";
5038            exit(-1);
5039        }
5040        CGlobalInfo::m_options.preview.set_client_cfg_enable(true);
5041        m_fl.set_client_config_tuple_gen_info(&m_fl.m_yaml_info.m_tuple_gen);
5042        pre_test();
5043    }
5044
5045    /* verify options */
5046    try {
5047        CGlobalInfo::m_options.verify();
5048    } catch (const std::runtime_error &e) {
5049        std::cout << "\n*** " << e.what() << "\n\n";
5050        exit(-1);
5051    }
5052
5053    m_expected_pps = m_fl.get_total_pps();
5054    m_expected_cps = 1000.0*m_fl.get_total_kcps();
5055    m_expected_bps = m_fl.get_total_tx_bps();
5056    if ( m_fl.get_total_repeat_flows() > 2000) {
5057        /* disable flows cache */
5058        CGlobalInfo::m_options.preview.setDisableMbufCache(true);
5059    }
5060
5061    CTupleGenYamlInfo * tg=&m_fl.m_yaml_info.m_tuple_gen;
5062
5063    m_mg.set_ip( tg->m_client_pool[0].get_ip_start(),
5064                 tg->m_server_pool[0].get_ip_start(),
5065                 tg->m_client_pool[0].getDualMask()
5066                 );
5067
5068    if (  CGlobalInfo::m_options.preview.getVMode() >0 ) {
5069        m_fl.DumpCsv(stdout);
5070        for (i=0; i<100; i++) {
5071            fprintf(stdout,"\n");
5072        }
5073        fflush(stdout);
5074    }
5075
5076    m_fl.generate_p_thread_info(get_cores_tx());
5077    CFlowGenListPerThread   * lpt;
5078
5079    for (i=0; i<get_cores_tx(); i++) {
5080        lpt = m_fl.m_threads_info[i];
5081        //CNullIF * erf_vif = new CNullIF();
5082        CVirtualIF * erf_vif = m_cores_vif[i+1];
5083        lpt->set_vif(erf_vif);
5084        /* socket id */
5085        lpt->m_node_gen.m_socket_id =m_cores_vif[i+1]->get_socket_id();
5086
5087    }
5088    m_fl_was_init=true;
5089
5090    return (0);
5091}
5092
5093
5094////////////////////////////////////////////
5095static CGlobalTRex g_trex;
5096
5097void CPhyEthIF::conf_queues() {
5098    CTrexDpdkParams dpdk_p;
5099    get_ex_drv()->get_dpdk_drv_params(dpdk_p);
5100    uint16_t num_tx_q = (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE) ?
5101        1 : g_trex.m_max_queues_per_port;
5102    socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)m_port_id);
5103    assert(CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
5104
5105    configure(dpdk_p.rx_drop_q_num + dpdk_p.rx_data_q_num, num_tx_q, &g_trex.m_port_cfg.m_port_conf);
5106    for (uint16_t qid = 0; qid < num_tx_q; qid++) {
5107        tx_queue_setup(qid, dpdk_p.tx_desc_num , socket_id, &g_trex.m_port_cfg.m_tx_conf);
5108    }
5109
5110    switch (dpdk_p.rx_drop_q_num) {
5111    case 0:
5112        if (dpdk_p.rx_data_q_num == 1) {
5113            // 1 rx rcv q. no drop q. VM mode.
5114            // Only 1 rx queue, so use it for everything
5115            g_trex.m_rx_core_tx_q_id = 0;
5116            rx_queue_setup(0, dpdk_p.rx_desc_num_data_q, socket_id, &g_trex.m_port_cfg.m_rx_conf,
5117                           CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
5118            set_rx_queue(0);
5119        } else {
5120            // no drop q. Many rcv queues. RSS mode.
5121            // rss on all rcv queues. Do not skip any q.
5122            configure_rss_redirect_table(dpdk_p.rx_data_q_num, 0xff);
5123            g_trex.m_rx_core_tx_q_id = g_trex.m_cores_to_dual_ports;
5124            for (int queue = 0; queue < dpdk_p.rx_data_q_num; queue++) {
5125                rx_queue_setup(queue, dpdk_p.rx_desc_num_data_q, socket_id,
5126                               &g_trex.m_port_cfg.m_rx_conf, CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k);
5127            }
5128        }
5129        break;
5130    case 1:
5131        // 1 drop q. 1 or more rx queues. Normal mode.
5132        // rx core will use largest tx q
5133        g_trex.m_rx_core_tx_q_id = g_trex.m_cores_to_dual_ports;
5134        // configure drop q
5135        rx_queue_setup(MAIN_DPDK_DROP_Q, dpdk_p.rx_desc_num_drop_q, socket_id, &g_trex.m_port_cfg.m_rx_conf,
5136                            CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
5137        set_rx_queue(MAIN_DPDK_RX_Q);
5138        rx_queue_setup(MAIN_DPDK_RX_Q, dpdk_p.rx_desc_num_data_q, socket_id,
5139                       &g_trex.m_port_cfg.m_rx_conf, CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k);
5140        break;
5141    default:
5142        // Many drop queues. Mellanox mode.
5143        g_trex.m_rx_core_tx_q_id = g_trex.m_cores_to_dual_ports;
5144        // configure drop queues (all queues but MAIN_DPDK_RX_Q)
5145        for (int j = 0; j < dpdk_p.rx_drop_q_num + 1; j++) {
5146            if (j == MAIN_DPDK_RX_Q) {
5147                continue;
5148            }
5149            rx_queue_setup(j, dpdk_p.rx_desc_num_drop_q, socket_id, &g_trex.m_port_cfg.m_rx_conf,
5150                           CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
5151        }
5152        rx_queue_setup(MAIN_DPDK_RX_Q, dpdk_p.rx_desc_num_data_q, socket_id,
5153                       &g_trex.m_port_cfg.m_rx_conf, CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k);
5154        // rss on all drop queues. Skip MAIN_DPDK_RX_Q
5155        configure_rss_redirect_table(dpdk_p.rx_drop_q_num + 1, MAIN_DPDK_RX_Q);
5156        break;
5157    }
5158}
5159
5160void CPhyEthIF::configure_rss_redirect_table(uint16_t numer_of_queues, uint16_t skip_queue) {
5161     struct rte_eth_dev_info dev_info;
5162
5163     rte_eth_dev_info_get(m_port_id,&dev_info);
5164     assert(dev_info.reta_size > 0);
5165     int reta_conf_size = std::max(1, dev_info.reta_size / RTE_RETA_GROUP_SIZE);
5166     struct rte_eth_rss_reta_entry64 reta_conf[reta_conf_size];
5167
5168     rte_eth_dev_rss_reta_query(m_port_id,&reta_conf[0],dev_info.reta_size);
5169
5170     for (int j = 0; j < reta_conf_size; j++) {
5171         uint16_t skip = 0;
5172         reta_conf[j].mask = ~0ULL;
5173         for (int i = 0; i < RTE_RETA_GROUP_SIZE; i++) {
5174             uint16_t q;
5175             while (true) {
5176                 q=(i + skip) % numer_of_queues;
5177                 if (q != skip_queue) {
5178                     break;
5179                 }
5180                 skip += 1;
5181             }
5182             reta_conf[j].reta[i] = q;
5183         }
5184     }
5185     rte_eth_dev_rss_reta_update(m_port_id, &reta_conf[0], dev_info.reta_size);
5186     rte_eth_dev_rss_reta_query(m_port_id, &reta_conf[0], dev_info.reta_size);
5187
5188#if 0
5189     /* verification */
5190     for (j = 0; j < reta_conf_size; j++) {
5191         for (i = 0; i<RTE_RETA_GROUP_SIZE; i++) {
5192             printf(" R  %d %d %d \n",j,i,reta_conf[j].reta[i]);
5193         }
5194     }
5195#endif
5196}
5197
5198void CPhyEthIF::update_counters() {
5199    get_ex_drv()->get_extended_stats(this, &m_stats);
5200    CRXCoreIgnoreStat ign_stats;
5201
5202    if (get_is_stateless()) {
5203        g_trex.m_rx_sl.get_ignore_stats(m_port_id, ign_stats, true);
5204    } else {
5205        g_trex.m_mg.get_ignore_stats(m_port_id, ign_stats, true);
5206    }
5207
5208    m_stats.obytes -= ign_stats.get_tx_bytes();
5209    m_stats.opackets -= ign_stats.get_tx_pkts();
5210    m_ignore_stats.opackets += ign_stats.get_tx_pkts();
5211    m_ignore_stats.obytes += ign_stats.get_tx_bytes();
5212    m_ignore_stats.m_tx_arp += ign_stats.get_tx_arp();
5213
5214    m_last_tx_rate      =  m_bw_tx.add(m_stats.obytes);
5215    m_last_rx_rate      =  m_bw_rx.add(m_stats.ibytes);
5216    m_last_tx_pps       =  m_pps_tx.add(m_stats.opackets);
5217    m_last_rx_pps       =  m_pps_rx.add(m_stats.ipackets);
5218}
5219
5220bool CPhyEthIF::Create(uint8_t portid) {
5221    m_port_id      = portid;
5222    m_last_rx_rate = 0.0;
5223    m_last_tx_rate = 0.0;
5224    m_last_tx_pps  = 0.0;
5225    m_port_attr    = g_trex.m_drv->create_port_attr(portid);
5226
5227    /* set src MAC addr */
5228    uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
5229    if (! memcmp( CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
5230        rte_eth_macaddr_get(m_port_id,
5231                            (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src);
5232    }
5233
5234    return true;
5235}
5236
5237const std::vector<std::pair<uint8_t, uint8_t>> &
5238CPhyEthIF::get_core_list() {
5239
5240    /* lazy find */
5241    if (m_core_id_list.size() == 0) {
5242
5243        for (uint8_t core_id = 0; core_id < g_trex.get_cores_tx(); core_id++) {
5244
5245            /* iterate over all the directions*/
5246            for (uint8_t dir = 0 ; dir < CS_NUM; dir++) {
5247                if (g_trex.m_cores_vif[core_id + 1]->get_ports()[dir].m_port->get_port_id() == m_port_id) {
5248                    m_core_id_list.push_back(std::make_pair(core_id, dir));
5249                }
5250            }
5251        }
5252    }
5253
5254    return m_core_id_list;
5255
5256}
5257
5258int CPhyEthIF::reset_hw_flow_stats() {
5259    if (get_ex_drv()->hw_rx_stat_supported()) {
5260        get_ex_drv()->reset_rx_stats(this, m_stats.m_fdir_prev_pkts, 0, MAX_FLOW_STATS);
5261    } else {
5262        g_trex.m_rx_sl.reset_rx_stats(get_port_id());
5263    }
5264    return 0;
5265}
5266
5267// get/reset flow director counters
5268// return 0 if OK. -1 if operation not supported.
5269// rx_stats, tx_stats - arrays of len max - min + 1. Returning rx, tx updated absolute values.
5270// min, max - minimum, maximum counters range to get
5271// reset - If true, need to reset counter value after reading
5272int CPhyEthIF::get_flow_stats(rx_per_flow_t *rx_stats, tx_per_flow_t *tx_stats, int min, int max, bool reset) {
5273    uint32_t diff_pkts[MAX_FLOW_STATS];
5274    uint32_t diff_bytes[MAX_FLOW_STATS];
5275    bool hw_rx_stat_supported = get_ex_drv()->hw_rx_stat_supported();
5276
5277    if (hw_rx_stat_supported) {
5278        if (get_ex_drv()->get_rx_stats(this, diff_pkts, m_stats.m_fdir_prev_pkts
5279                                       , diff_bytes, m_stats.m_fdir_prev_bytes, min, max) < 0) {
5280            return -1;
5281        }
5282    } else {
5283        g_trex.m_rx_sl.get_rx_stats(get_port_id(), rx_stats, min, max, reset, TrexPlatformApi::IF_STAT_IPV4_ID);
5284    }
5285
5286    for (int i = min; i <= max; i++) {
5287        if ( reset ) {
5288            // return value so far, and reset
5289            if (hw_rx_stat_supported) {
5290                if (rx_stats != NULL) {
5291                    rx_stats[i - min].set_pkts(m_stats.m_rx_per_flow_pkts[i] + diff_pkts[i]);
5292                    rx_stats[i - min].set_bytes(m_stats.m_rx_per_flow_bytes[i] + diff_bytes[i]);
5293                }
5294                m_stats.m_rx_per_flow_pkts[i] = 0;
5295                m_stats.m_rx_per_flow_bytes[i] = 0;
5296                get_ex_drv()->reset_rx_stats(this, &m_stats.m_fdir_prev_pkts[i], i, 1);
5297
5298            }
5299            if (tx_stats != NULL) {
5300                tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i, false);
5301            }
5302        } else {
5303            if (hw_rx_stat_supported) {
5304                m_stats.m_rx_per_flow_pkts[i] += diff_pkts[i];
5305                m_stats.m_rx_per_flow_bytes[i] += diff_bytes[i];
5306                if (rx_stats != NULL) {
5307                    rx_stats[i - min].set_pkts(m_stats.m_rx_per_flow_pkts[i]);
5308                    rx_stats[i - min].set_bytes(m_stats.m_rx_per_flow_bytes[i]);
5309                }
5310            }
5311            if (tx_stats != NULL) {
5312                tx_stats[i - min] = g_trex.get_flow_tx_stats(m_port_id, i);
5313            }
5314        }
5315    }
5316
5317    return 0;
5318}
5319
5320int CPhyEthIF::get_flow_stats_payload(rx_per_flow_t *rx_stats, tx_per_flow_t *tx_stats, int min, int max, bool reset) {
5321    g_trex.m_rx_sl.get_rx_stats(get_port_id(), rx_stats, min, max, reset, TrexPlatformApi::IF_STAT_PAYLOAD);
5322    for (int i = min; i <= max; i++) {
5323        if ( reset ) {
5324            if (tx_stats != NULL) {
5325                tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i + MAX_FLOW_STATS, true);
5326            }
5327        } else {
5328            if (tx_stats != NULL) {
5329                tx_stats[i - min] = g_trex.get_flow_tx_stats(m_port_id, i + MAX_FLOW_STATS);
5330            }
5331        }
5332    }
5333
5334    return 0;
5335}
5336
5337TrexStateless * get_stateless_obj() {
5338    return g_trex.m_trex_stateless;
5339}
5340
5341CRxCoreStateless * get_rx_sl_core_obj() {
5342    return &g_trex.m_rx_sl;
5343}
5344
5345static int latency_one_lcore(__attribute__((unused)) void *dummy)
5346{
5347    CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket;
5348    physical_thread_id_t  phy_id =rte_lcore_id();
5349
5350    if ( lpsock->thread_phy_is_rx(phy_id) ) {
5351        g_trex.run_in_rx_core();
5352    }else{
5353
5354        if ( lpsock->thread_phy_is_master( phy_id ) ) {
5355            g_trex.run_in_master();
5356            delay(1);
5357        }else{
5358            delay((uint32_t)(1000.0*CGlobalInfo::m_options.m_duration));
5359            /* this core has stopped */
5360            g_trex.m_signal[ lpsock->thread_phy_to_virt( phy_id ) ]=1;
5361        }
5362    }
5363    return 0;
5364}
5365
5366
5367
5368static int slave_one_lcore(__attribute__((unused)) void *dummy)
5369{
5370    CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket;
5371    physical_thread_id_t  phy_id =rte_lcore_id();
5372
5373    if ( lpsock->thread_phy_is_rx(phy_id) ) {
5374        g_trex.run_in_rx_core();
5375    }else{
5376        if ( lpsock->thread_phy_is_master( phy_id ) ) {
5377            g_trex.run_in_master();
5378            delay(1);
5379        }else{
5380            g_trex.run_in_core( lpsock->thread_phy_to_virt( phy_id ) );
5381        }
5382    }
5383    return 0;
5384}
5385
5386
5387
5388uint32_t get_cores_mask(uint32_t cores,int offset){
5389    int i;
5390
5391    uint32_t res=1;
5392
5393    uint32_t mask=(1<<(offset+1));
5394    for (i=0; i<(cores-1); i++) {
5395        res |= mask ;
5396        mask = mask <<1;
5397    }
5398    return (res);
5399}
5400
5401
5402static char *g_exe_name;
5403const char *get_exe_name() {
5404    return g_exe_name;
5405}
5406
5407
5408int main(int argc , char * argv[]){
5409    g_exe_name = argv[0];
5410
5411    return ( main_test(argc , argv));
5412}
5413
5414
5415int update_global_info_from_platform_file(){
5416
5417    CPlatformYamlInfo *cg=&global_platform_cfg_info;
5418
5419    CGlobalInfo::m_socket.Create(&cg->m_platform);
5420
5421
5422    if (!cg->m_info_exist) {
5423        /* nothing to do ! */
5424        return 0;
5425    }
5426
5427    CGlobalInfo::m_options.prefix =cg->m_prefix;
5428    CGlobalInfo::m_options.preview.setCores(cg->m_thread_per_dual_if);
5429
5430    if ( cg->m_port_limit_exist ){
5431        CGlobalInfo::m_options.m_expected_portd =cg->m_port_limit;
5432    }
5433
5434    if ( cg->m_enable_zmq_pub_exist ){
5435        CGlobalInfo::m_options.preview.set_zmq_publish_enable(cg->m_enable_zmq_pub);
5436        CGlobalInfo::m_options.m_zmq_port = cg->m_zmq_pub_port;
5437    }
5438    if ( cg->m_telnet_exist ){
5439        CGlobalInfo::m_options.m_telnet_port = cg->m_telnet_port;
5440    }
5441
5442    if ( cg->m_mac_info_exist ){
5443        int i;
5444        /* cop the file info */
5445
5446        int port_size=cg->m_mac_info.size();
5447
5448        if ( port_size > TREX_MAX_PORTS ){
5449            port_size = TREX_MAX_PORTS;
5450        }
5451        for (i=0; i<port_size; i++){
5452            cg->m_mac_info[i].copy_src(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.src)   ;
5453            cg->m_mac_info[i].copy_dest(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.dest)  ;
5454            CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.is_set = 1;
5455
5456            CGlobalInfo::m_options.m_ip_cfg[i].set_def_gw(cg->m_mac_info[i].get_def_gw());
5457            CGlobalInfo::m_options.m_ip_cfg[i].set_ip(cg->m_mac_info[i].get_ip());
5458            CGlobalInfo::m_options.m_ip_cfg[i].set_mask(cg->m_mac_info[i].get_mask());
5459            CGlobalInfo::m_options.m_ip_cfg[i].set_vlan(cg->m_mac_info[i].get_vlan());
5460            // If one of the ports has vlan, work in vlan mode
5461            if (cg->m_mac_info[i].get_vlan() != 0) {
5462                CGlobalInfo::m_options.preview.set_vlan_mode_verify(CPreviewMode::VLAN_MODE_NORMAL);
5463            }
5464        }
5465    }
5466
5467    /* mul by interface type */
5468    float mul=1.0;
5469    if (cg->m_port_bandwidth_gb<10) {
5470        cg->m_port_bandwidth_gb=10.0;
5471    }
5472
5473    mul = mul*(float)cg->m_port_bandwidth_gb/10.0;
5474    mul= mul * (float)cg->m_port_limit/2.0;
5475
5476    mul= mul * CGlobalInfo::m_options.m_mbuf_factor;
5477
5478
5479    CGlobalInfo::m_memory_cfg.set_pool_cache_size(RTE_MEMPOOL_CACHE_MAX_SIZE);
5480
5481    CGlobalInfo::m_memory_cfg.set_number_of_dp_cors(
5482                                                    CGlobalInfo::m_options.get_number_of_dp_cores_needed() );
5483
5484    CGlobalInfo::m_memory_cfg.set(cg->m_memory,mul);
5485    return (0);
5486}
5487
5488extern "C" int eal_cpu_detected(unsigned lcore_id);
5489// return mask representing available cores
5490int core_mask_calc() {
5491    uint32_t mask = 0;
5492    int lcore_id;
5493
5494    for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
5495        if (eal_cpu_detected(lcore_id)) {
5496            mask |= (1 << lcore_id);
5497        }
5498    }
5499
5500    return mask;
5501}
5502
5503// Return number of set bits in i
5504uint32_t num_set_bits(uint32_t i)
5505{
5506    i = i - ((i >> 1) & 0x55555555);
5507    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
5508    return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
5509}
5510
5511// sanity check if the cores we want to use really exist
5512int core_mask_sanity(uint32_t wanted_core_mask) {
5513    uint32_t calc_core_mask = core_mask_calc();
5514    uint32_t wanted_core_num, calc_core_num;
5515
5516    wanted_core_num = num_set_bits(wanted_core_mask);
5517    calc_core_num = num_set_bits(calc_core_mask);
5518
5519    if (calc_core_num == 1) {
5520        printf ("Error: You have only 1 core available. Minimum configuration requires 2 cores\n");
5521        printf("        If you are running on VM, consider adding more cores if possible\n");
5522        return -1;
5523    }
5524    if (wanted_core_num > calc_core_num) {
5525        printf("Error: You have %d threads available, but you asked for %d threads.\n", calc_core_num, wanted_core_num);
5526        printf("       Calculation is: -c <num>(%d) * dual ports (%d) + 1 master thread %s"
5527               , CGlobalInfo::m_options.preview.getCores(), CGlobalInfo::m_options.get_expected_dual_ports()
5528               , get_is_rx_thread_enabled() ? "+1 latency thread (because of -l flag)\n" : "\n");
5529        if (CGlobalInfo::m_options.preview.getCores() > 1)
5530            printf("       Maybe try smaller -c <num>.\n");
5531        printf("       If you are running on VM, consider adding more cores if possible\n");
5532        return -1;
5533    }
5534
5535    if (wanted_core_mask != (wanted_core_mask & calc_core_mask)) {
5536        printf ("Serious error: Something is wrong with the hardware. Wanted core mask is %x. Existing core mask is %x\n", wanted_core_mask, calc_core_mask);
5537        return -1;
5538    }
5539
5540    return 0;
5541}
5542
5543int  update_dpdk_args(void){
5544
5545    CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket;
5546    CParserOption * lpop= &CGlobalInfo::m_options;
5547
5548    lpsock->set_rx_thread_is_enabled(get_is_rx_thread_enabled());
5549    lpsock->set_number_of_threads_per_ports(lpop->preview.getCores() );
5550    lpsock->set_number_of_dual_ports(lpop->get_expected_dual_ports());
5551    if ( !lpsock->sanity_check() ){
5552        printf(" ERROR in configuration file \n");
5553        return (-1);
5554    }
5555
5556    if ( CGlobalInfo::m_options.preview.getVMode() > 0  ) {
5557        lpsock->dump(stdout);
5558    }
5559
5560    snprintf(global_cores_str, sizeof(global_cores_str), "0x%llx" ,(unsigned long long)lpsock->get_cores_mask());
5561    if (core_mask_sanity(strtol(global_cores_str, NULL, 16)) < 0) {
5562        return -1;
5563    }
5564
5565    /* set the DPDK options */
5566    global_dpdk_args_num = 0;
5567
5568    global_dpdk_args[global_dpdk_args_num++]=(char *)"xx";
5569
5570    if ( CGlobalInfo::m_options.preview.get_mlx5_so_mode() ){
5571        global_dpdk_args[global_dpdk_args_num++]=(char *)"-d";
5572        snprintf(global_mlx5_so_id_str, sizeof(global_mlx5_so_id_str), "libmlx5-64%s.so",global_image_postfix );
5573        global_dpdk_args[global_dpdk_args_num++]=(char *)global_mlx5_so_id_str;
5574    }
5575
5576    if ( CGlobalInfo::m_options.preview.get_mlx4_so_mode() ){
5577        global_dpdk_args[global_dpdk_args_num++]=(char *)"-d";
5578        snprintf(global_mlx4_so_id_str, sizeof(global_mlx4_so_id_str), "libmlx4-64%s.so",global_image_postfix );
5579        global_dpdk_args[global_dpdk_args_num++]=(char *)global_mlx4_so_id_str;
5580    }
5581
5582    global_dpdk_args[global_dpdk_args_num++]=(char *)"-c";
5583    global_dpdk_args[global_dpdk_args_num++]=(char *)global_cores_str;
5584    global_dpdk_args[global_dpdk_args_num++]=(char *)"-n";
5585    global_dpdk_args[global_dpdk_args_num++]=(char *)"4";
5586
5587    if ( CGlobalInfo::m_options.preview.getVMode() == 0  ) {
5588        global_dpdk_args[global_dpdk_args_num++]=(char *)"--log-level";
5589        snprintf(global_loglevel_str, sizeof(global_loglevel_str), "%d", 4);
5590        global_dpdk_args[global_dpdk_args_num++]=(char *)global_loglevel_str;
5591    }else{
5592        global_dpdk_args[global_dpdk_args_num++]=(char *)"--log-level";
5593        snprintf(global_loglevel_str, sizeof(global_loglevel_str), "%d", CGlobalInfo::m_options.preview.getVMode()+1);
5594        global_dpdk_args[global_dpdk_args_num++]=(char *)global_loglevel_str;
5595    }
5596
5597    global_dpdk_args[global_dpdk_args_num++] = (char *)"--master-lcore";
5598
5599    snprintf(global_master_id_str, sizeof(global_master_id_str), "%u", lpsock->get_master_phy_id());
5600    global_dpdk_args[global_dpdk_args_num++] = global_master_id_str;
5601
5602    /* add white list */
5603    if (lpop->m_run_mode == CParserOption::RUN_MODE_DUMP_INFO and lpop->dump_interfaces.size()) {
5604        for (int i=0; i<(int)lpop->dump_interfaces.size(); i++) {
5605            global_dpdk_args[global_dpdk_args_num++]=(char *)"-w";
5606            global_dpdk_args[global_dpdk_args_num++]=(char *)lpop->dump_interfaces[i].c_str();
5607        }
5608    }
5609    else {
5610        for (int i=0; i<(int)global_platform_cfg_info.m_if_list.size(); i++) {
5611            global_dpdk_args[global_dpdk_args_num++]=(char *)"-w";
5612            global_dpdk_args[global_dpdk_args_num++]=(char *)global_platform_cfg_info.m_if_list[i].c_str();
5613        }
5614    }
5615
5616
5617
5618    if ( lpop->prefix.length()  ){
5619        global_dpdk_args[global_dpdk_args_num++]=(char *)"--file-prefix";
5620        snprintf(global_prefix_str, sizeof(global_prefix_str), "%s", lpop->prefix.c_str());
5621        global_dpdk_args[global_dpdk_args_num++]=(char *)global_prefix_str;
5622        global_dpdk_args[global_dpdk_args_num++]=(char *)"-m";
5623        if (global_platform_cfg_info.m_limit_memory.length()) {
5624            global_dpdk_args[global_dpdk_args_num++]=(char *)global_platform_cfg_info.m_limit_memory.c_str();
5625        }else{
5626            global_dpdk_args[global_dpdk_args_num++]=(char *)"1024";
5627        }
5628    }
5629
5630
5631    if ( CGlobalInfo::m_options.preview.getVMode() > 0  ) {
5632        printf("args \n");
5633        int i;
5634        for (i=0; i<global_dpdk_args_num; i++) {
5635            printf(" %s \n",global_dpdk_args[i]);
5636        }
5637    }
5638    return (0);
5639}
5640
5641
5642int sim_load_list_of_cap_files(CParserOption * op){
5643
5644    CFlowGenList fl;
5645    fl.Create();
5646    fl.load_from_yaml(op->cfg_file,1);
5647    if ( op->preview.getVMode() >0 ) {
5648        fl.DumpCsv(stdout);
5649    }
5650    uint32_t start=    os_get_time_msec();
5651
5652    CErfIF erf_vif;
5653
5654    fl.generate_p_thread_info(1);
5655    CFlowGenListPerThread   * lpt;
5656    lpt=fl.m_threads_info[0];
5657    lpt->set_vif(&erf_vif);
5658
5659    if ( (op->preview.getVMode() >1)  || op->preview.getFileWrite() ) {
5660        lpt->start_generate_stateful(op->out_file,op->preview);
5661    }
5662
5663    lpt->m_node_gen.DumpHist(stdout);
5664
5665    uint32_t stop=    os_get_time_msec();
5666    printf(" d time = %ul %ul \n",stop-start,os_get_time_freq());
5667    fl.Delete();
5668    return (0);
5669}
5670
5671void dump_interfaces_info() {
5672    printf("Showing interfaces info.\n");
5673    uint8_t m_max_ports = rte_eth_dev_count();
5674    struct ether_addr mac_addr;
5675    char mac_str[ETHER_ADDR_FMT_SIZE];
5676    struct rte_pci_addr pci_addr;
5677
5678    for (uint8_t port_id=0; port_id<m_max_ports; port_id++) {
5679        // PCI, MAC and Driver
5680        pci_addr = rte_eth_devices[port_id].device->devargs->pci.addr;
5681        rte_eth_macaddr_get(port_id, &mac_addr);
5682        ether_format_addr(mac_str, sizeof mac_str, &mac_addr);
5683        printf("PCI: %04x:%02x:%02x.%d - MAC: %s - Driver: %s\n",
5684            pci_addr.domain, pci_addr.bus, pci_addr.devid, pci_addr.function, mac_str,
5685            rte_eth_devices[port_id].data->drv_name);
5686    }
5687}
5688
5689
5690int learn_image_postfix(char * image_name){
5691
5692    char *p = strstr(image_name,TREX_NAME);
5693    if (p) {
5694        strcpy(global_image_postfix,p+strlen(TREX_NAME));
5695    }
5696    return(0);
5697}
5698
5699int main_test(int argc , char * argv[]){
5700
5701    learn_image_postfix(argv[0]);
5702
5703    utl_termio_init();
5704
5705    int ret;
5706    unsigned lcore_id;
5707    printf("Starting  TRex %s please wait  ... \n",VERSION_BUILD_NUM);
5708
5709    CGlobalInfo::m_options.preview.clean();
5710
5711    if ( parse_options_wrapper(argc, argv, &CGlobalInfo::m_options,true ) != 0){
5712        exit(-1);
5713    }
5714
5715    /* enable core dump if requested */
5716    if (CGlobalInfo::m_options.preview.getCoreDumpEnable()) {
5717        utl_set_coredump_size(-1);
5718    }
5719    else {
5720        utl_set_coredump_size(0);
5721    }
5722
5723
5724    update_global_info_from_platform_file();
5725
5726    /* It is not a mistake. Give the user higher priorty over the configuration file */
5727    if (parse_options_wrapper(argc, argv, &CGlobalInfo::m_options ,false) != 0) {
5728        exit(-1);
5729    }
5730
5731
5732    if ( CGlobalInfo::m_options.preview.getVMode() > 0){
5733        CGlobalInfo::m_options.dump(stdout);
5734        CGlobalInfo::m_memory_cfg.Dump(stdout);
5735    }
5736
5737
5738    if (update_dpdk_args() < 0) {
5739        return -1;
5740    }
5741
5742    CParserOption * po=&CGlobalInfo::m_options;
5743
5744
5745    if ( CGlobalInfo::m_options.preview.getVMode() == 0  ) {
5746        rte_set_log_level(1);
5747
5748    }
5749    uid_t uid;
5750    uid = geteuid ();
5751    if ( uid != 0 ) {
5752        printf("ERROR you must run with superuser priviliges \n");
5753        printf("User id   : %d \n",uid);
5754        printf("try 'sudo' %s \n",argv[0]);
5755        return (-1);
5756    }
5757
5758    /* set affinity to the master core as default */
5759    cpu_set_t mask;
5760    CPU_ZERO(&mask);
5761    CPU_SET(CGlobalInfo::m_socket.get_master_phy_id(), &mask);
5762    pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask);
5763
5764    ret = rte_eal_init(global_dpdk_args_num, (char **)global_dpdk_args);
5765    if (ret < 0){
5766        printf(" You might need to run ./trex-cfg  once  \n");
5767        rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
5768    }
5769    set_driver();
5770    if (CGlobalInfo::m_options.m_run_mode == CParserOption::RUN_MODE_DUMP_INFO) {
5771        dump_interfaces_info();
5772        exit(0);
5773    }
5774    reorder_dpdk_ports();
5775    time_init();
5776
5777    /* check if we are in simulation mode */
5778    if ( CGlobalInfo::m_options.out_file != "" ){
5779        printf(" t-rex simulation mode into %s \n",CGlobalInfo::m_options.out_file.c_str());
5780        return ( sim_load_list_of_cap_files(&CGlobalInfo::m_options) );
5781    }
5782
5783    if ( !g_trex.Create() ){
5784        exit(1);
5785    }
5786
5787    if (po->preview.get_is_rx_check_enable() &&  (po->m_rx_check_sample< get_min_sample_rate()) ) {
5788        po->m_rx_check_sample = get_min_sample_rate();
5789        printf("Warning:rx check sample rate should not be lower than %d. Setting it to %d\n",get_min_sample_rate(),get_min_sample_rate());
5790    }
5791
5792    /* set dump mode */
5793    g_trex.m_io_modes.set_mode((CTrexGlobalIoMode::CliDumpMode)CGlobalInfo::m_options.m_io_mode);
5794
5795    /* disable WD if needed */
5796    bool wd_enable = (CGlobalInfo::m_options.preview.getWDDisable() ? false : true);
5797    TrexWatchDog::getInstance().init(wd_enable);
5798
5799    g_trex.m_sl_rx_running = false;
5800    if ( get_is_stateless() ) {
5801        g_trex.start_master_stateless();
5802
5803    }else{
5804        g_trex.start_master_statefull();
5805    }
5806
5807    // For unit testing of HW rules and queues configuration. Just send some packets and exit.
5808    if (CGlobalInfo::m_options.m_debug_pkt_proto != 0) {
5809        CTrexDpdkParams dpdk_p;
5810        get_ex_drv()->get_dpdk_drv_params(dpdk_p);
5811        CTrexDebug debug = CTrexDebug(g_trex.m_ports, g_trex.m_max_ports
5812                                      , dpdk_p.rx_data_q_num + dpdk_p.rx_drop_q_num);
5813        int ret;
5814
5815        if (CGlobalInfo::m_options.m_debug_pkt_proto == D_PKT_TYPE_HW_TOGGLE_TEST) {
5816            // Unit test: toggle many times between receive all and stateless/stateful modes,
5817            // to test resiliency of add/delete fdir filters
5818            printf("Starting receive all/normal mode toggle unit test\n");
5819            for (int i = 0; i < 100; i++) {
5820                for (int port_id = 0; port_id < g_trex.m_max_ports; port_id++) {
5821                    CPhyEthIF *pif = &g_trex.m_ports[port_id];
5822                    pif->set_port_rcv_all(true);
5823                }
5824                ret = debug.test_send(D_PKT_TYPE_HW_VERIFY_RCV_ALL);
5825                if (ret != 0) {
5826                    printf("Iteration %d: Receive all mode failed\n", i);
5827                    exit(ret);
5828                }
5829
5830                for (int port_id = 0; port_id < g_trex.m_max_ports; port_id++) {
5831                    CPhyEthIF *pif = &g_trex.m_ports[port_id];
5832                    CTRexExtendedDriverDb::Ins()->get_drv()->configure_rx_filter_rules(pif);
5833                }
5834
5835                ret = debug.test_send(D_PKT_TYPE_HW_VERIFY);
5836                if (ret != 0) {
5837                    printf("Iteration %d: Normal mode failed\n", i);
5838                    exit(ret);
5839                }
5840
5841                printf("Iteration %d OK\n", i);
5842            }
5843            exit(0);
5844        } else {
5845            if (CGlobalInfo::m_options.m_debug_pkt_proto == D_PKT_TYPE_HW_VERIFY_RCV_ALL) {
5846                for (int port_id = 0; port_id < g_trex.m_max_ports; port_id++) {
5847                    CPhyEthIF *pif = &g_trex.m_ports[port_id];
5848                    pif->set_port_rcv_all(true);
5849                }
5850            }
5851            ret = debug.test_send(CGlobalInfo::m_options.m_debug_pkt_proto);
5852            exit(ret);
5853        }
5854    }
5855
5856    // in case of client config, we already run pretest
5857    if (! CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
5858        g_trex.pre_test();
5859    }
5860
5861    // after doing all needed ARP resolution, we need to flush queues, and stop our drop queue
5862    g_trex.ixgbe_rx_queue_flush();
5863    for (int i = 0; i < g_trex.m_max_ports; i++) {
5864        CPhyEthIF *_if = &g_trex.m_ports[i];
5865        _if->stop_rx_drop_queue();
5866    }
5867
5868    if ( CGlobalInfo::m_options.is_latency_enabled()
5869         && (CGlobalInfo::m_options.m_latency_prev > 0)) {
5870        uint32_t pkts = CGlobalInfo::m_options.m_latency_prev *
5871            CGlobalInfo::m_options.m_latency_rate;
5872        printf("Starting warm up phase for %d sec\n",CGlobalInfo::m_options.m_latency_prev);
5873        g_trex.m_mg.start(pkts, NULL);
5874        delay(CGlobalInfo::m_options.m_latency_prev* 1000);
5875        printf("Finished \n");
5876        g_trex.m_mg.reset();
5877    }
5878
5879    if ( CGlobalInfo::m_options.preview.getOnlyLatency() ){
5880        rte_eal_mp_remote_launch(latency_one_lcore, NULL, CALL_MASTER);
5881        RTE_LCORE_FOREACH_SLAVE(lcore_id) {
5882            if (rte_eal_wait_lcore(lcore_id) < 0)
5883                return -1;
5884        }
5885        g_trex.stop_master();
5886
5887        return (0);
5888    }
5889
5890    if ( CGlobalInfo::m_options.preview.getSingleCore() ) {
5891        g_trex.run_in_core(1);
5892        g_trex.stop_master();
5893        return (0);
5894    }
5895
5896    rte_eal_mp_remote_launch(slave_one_lcore, NULL, CALL_MASTER);
5897    RTE_LCORE_FOREACH_SLAVE(lcore_id) {
5898        if (rte_eal_wait_lcore(lcore_id) < 0)
5899            return -1;
5900    }
5901
5902    g_trex.stop_master();
5903    g_trex.Delete();
5904    utl_termio_reset();
5905
5906    return (0);
5907}
5908
5909void wait_x_sec(int sec) {
5910    int i;
5911    printf(" wait %d sec ", sec);
5912    fflush(stdout);
5913    for (i=0; i<sec; i++) {
5914        delay(1000);
5915        printf(".");
5916        fflush(stdout);
5917    }
5918    printf("\n");
5919    fflush(stdout);
5920}
5921
5922/* should be called after rte_eal_init() */
5923void set_driver() {
5924    uint8_t m_max_ports = rte_eth_dev_count();
5925    if ( !m_max_ports ) {
5926        printf("Could not find interfaces.\n");
5927        exit(1);
5928    }
5929    struct rte_eth_dev_info dev_info;
5930    rte_eth_dev_info_get(0, &dev_info);
5931
5932    if ( !CTRexExtendedDriverDb::Ins()->is_driver_exists(dev_info.driver_name) ){
5933        printf("\nError: driver %s is not supported. Please consult the documentation for a list of supported drivers\n"
5934               ,dev_info.driver_name);
5935        exit(1);
5936    }
5937
5938    CTRexExtendedDriverDb::Ins()->set_driver_name(dev_info.driver_name);
5939}
5940
5941/*
5942Changes the order of rte_eth_devices array elements
5943to be consistent with our /etc/trex_cfg.yaml
5944(this is workaround, full solution would be mapp