bp_sim.h revision 5d2b2709
1#ifndef BP_SIM_H
2#define BP_SIM_H
3/*
4 Hanoh Haim
5 Cisco Systems, Inc.
6*/
7
8/*
9Copyright (c) 2015-2016 Cisco Systems, Inc.
10
11Licensed under the Apache License, Version 2.0 (the "License");
12you may not use this file except in compliance with the License.
13You may obtain a copy of the License at
14
15    http://www.apache.org/licenses/LICENSE-2.0
16
17Unless required by applicable law or agreed to in writing, software
18distributed under the License is distributed on an "AS IS" BASIS,
19WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20See the License for the specific language governing permissions and
21limitations under the License.
22*/
23
24#include <stddef.h>
25#include <stdio.h>
26#include <stdint.h>
27#include <vector>
28#include <algorithm>
29#include <map>
30#include <iostream>
31#include <fstream>
32#include <string>
33#include <queue>
34#include "mbuf.h"
35#include <common/c_common.h>
36#include <common/captureFile.h>
37#include <common/Network/Packet/TcpHeader.h>
38#include <common/Network/Packet/UdpHeader.h>
39#include <common/Network/Packet/IcmpHeader.h>
40#include <common/Network/Packet/IPHeader.h>
41#include <common/Network/Packet/IPv6Header.h>
42#include <common/Network/Packet/EthernetHeader.h>
43#include <math.h>
44#include <common/bitMan.h>
45#include <yaml-cpp/yaml.h>
46#include "trex_defs.h"
47#include "utl_ip.h"
48#include "os_time.h"
49#include "pal_utl.h"
50#include "rx_check_header.h"
51#include "rx_check.h"
52#include "time_histogram.h"
53#include "utl_cpuu.h"
54#include "tuple_gen.h"
55#include "utl_jitter.h"
56#include "msg_manager.h"
57#include "nat_check.h"
58#include <common/cgen_map.h>
59#include <arpa/inet.h>
60#include "platform_cfg.h"
61#include "flow_stat.h"
62#include "trex_watchdog.h"
63#include "trex_client_config.h"
64#include "h_timer.h"
65#include "tw_cfg.h"
66
67
68#include <trex_stateless_dp_core.h>
69
70#ifdef RTE_DPDK
71#	include <rte_ip.h>
72#endif /* RTE_DPDK */
73
74class CGenNodePCAP;
75
76#define FORCE_NO_INLINE __attribute__ ((noinline))
77#define FORCE_INLINE __attribute__((always_inline))
78
79/* reserve both 0xFF and 0xFE , router will -1 FF */
80#define TTL_RESERVE_DUPLICATE 0xff
81#define TOS_TTL_RESERVE_DUPLICATE 0x1
82/*
83 * Length of string needed to hold the largest port (16-bit) address
84 */
85#define INET_PORTSTRLEN 5
86
87/* VM commands */
88
89class CMiniVMCmdBase {
90public:
91    enum MV_FLAGS {
92        MIN_VM_V6=1    // IPv6 addressing
93    };
94    uint8_t   m_cmd;
95    uint8_t   m_flags;
96    uint16_t  m_start_0;
97    uint16_t  m_stop_1;
98    uint16_t  m_add_pkt_len; /* request more length for mbuf packet the size */
99};
100
101class CMiniVMReplaceIP : public CMiniVMCmdBase {
102public:
103    ipaddr_t m_server_ip;
104};
105
106class CMiniVMReplaceIPWithPort : public CMiniVMReplaceIP {
107public:
108    uint16_t  m_start_port;
109    uint16_t  m_stop_port;
110    uint16_t  m_client_port;
111    uint16_t  m_server_port;
112};
113
114/* this command replace IP in 2 diffrent location and port
115
116c =  10.1.1.2
117o =  10.1.1.2
118m = audio 102000
119
120==>
121
122c =  xx.xx.xx.xx
123o =  xx.xx.xx.xx
124m = audio yyyy
125
126*/
127
128class CMiniVMReplaceIP_IP_Port : public CMiniVMCmdBase {
129public:
130    ipaddr_t m_ip;
131    uint16_t  m_ip0_start;
132    uint16_t  m_ip0_stop;
133
134    uint16_t  m_ip1_start;
135    uint16_t  m_ip1_stop;
136
137
138    uint16_t  m_port;
139    uint16_t  m_port_start;
140    uint16_t  m_port_stop;
141};
142
143class CMiniVMReplaceIP_PORT_IP_IP_Port : public CMiniVMReplaceIP_IP_Port {
144public:
145    ipaddr_t m_ip_via;
146    uint16_t m_port_via;
147
148    uint16_t  m_ip_via_start;
149    uint16_t  m_ip_via_stop;
150};
151
152class CMiniVMDynPyload : public CMiniVMCmdBase {
153public:
154    void * m_ptr;
155    ipaddr_t m_ip;
156} ;
157
158/* VM with SIMD commands for RTSP we can add SIP/FTP  commands too */
159
160typedef enum { VM_REPLACE_IP_OFFSET =0x12, /* fix ip at offset  */
161               VM_REPLACE_IP_PORT_OFFSET, /*  fix ip at offset and client port*/
162               VM_REPLACE_IP_PORT_RESPONSE_OFFSET, /* fix client port and server port  */
163               VM_REPLACE_IP_IP_PORT,/* SMID command to replace IPV4 , IPV4, PORT in 3 diffrent location , see CMiniVMReplaceIP_IP_Port*/
164               VM_REPLACE_IPVIA_IP_IP_PORT,/* SMID command to replace ip,port IPV4 , IPV4, PORT in 3 diffrent location , see CMiniVMReplaceIP_PORT_IP_IP_Port*/
165               VM_DYN_PYLOAD,
166
167
168               VM_EOP /* end of program */
169               } mini_vm_op_code_t;
170
171
172/* work only on x86 littel */
173#define	MY_B(b)	(((int)b)&0xff)
174
175class CFlowPktInfo ;
176
177class CMiniVM {
178
179public:
180    CMiniVM(){
181        m_new_pkt_size=0;
182    }
183
184    int mini_vm_run(CMiniVMCmdBase * cmds[]);
185    int mini_vm_replace_ip(CMiniVMReplaceIP * cmd);
186    int mini_vm_replace_port_ip(CMiniVMReplaceIPWithPort * cmd);
187    int mini_vm_replace_ports(CMiniVMReplaceIPWithPort * cmd);
188    int mini_vm_replace_ip_ip_ports(CMiniVMReplaceIP_IP_Port * cmd);
189    int mini_vm_replace_ip_via_ip_ip_ports(CMiniVMReplaceIP_PORT_IP_IP_Port * cmd);
190    int mini_vm_dyn_payload( CMiniVMDynPyload * cmd);
191
192
193private:
194    int append_with_end_of_line(uint16_t len){
195        //assert(m_new_pkt_size<=0);
196        if (m_new_pkt_size <0 ) {
197            memset(m_pyload_mbuf_ptr+len+m_new_pkt_size,0xa,(-m_new_pkt_size));
198        }
199
200        return (0);
201    }
202
203public:
204    int16_t        m_new_pkt_size; /* New packet size after transform by plugin */
205    CFlowPktInfo * m_pkt_info;
206    char *         m_pyload_mbuf_ptr; /* pointer to the pyload pointer of new allocated packet from mbuf */
207};
208
209
210
211
212
213class CGenNode;
214class CFlowYamlInfo;
215class CFlowGenListPerThread ;
216
217
218/* callback */
219void on_node_first(uint8_t plugin_id,CGenNode *     node,
220                   CFlowYamlInfo *  template_info,
221                   CTupleTemplateGeneratorSmart * tuple_gen,
222                   CFlowGenListPerThread  * flow_gen
223                   );
224
225void on_node_last(uint8_t plugin_id,CGenNode *     node);
226
227rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode *     node,CFlowPktInfo * pkt_info);
228
229class CPreviewMode ;
230
231class CLatencyPktData {
232 public:
233    CLatencyPktData() {m_flow_seq = FLOW_STAT_PAYLOAD_INITIAL_FLOW_SEQ;}
234    inline uint32_t get_seq_num() {return m_seq_num;}
235    inline void inc_seq_num() {m_seq_num++;}
236    inline uint32_t get_flow_seq() {return m_flow_seq;}
237    void reset() {
238        m_seq_num = UINT32_MAX - 1; // catch wrap around issues early
239        m_flow_seq++;
240        if (m_flow_seq == FLOW_STAT_PAYLOAD_INITIAL_FLOW_SEQ)
241            m_flow_seq++;
242    }
243
244 private:
245    uint32_t m_seq_num;  // seq num to put in packet for payload rules. Increased every packet.
246    uint16_t m_flow_seq;  // Seq num of flow. Changed when we start new flow on this id.
247};
248
249/* represent the virtual interface
250*/
251
252/* counters per side */
253class CVirtualIFPerSideStats {
254public:
255    CVirtualIFPerSideStats(){
256        Clear();
257        m_template.Clear();
258    }
259
260    uint64_t   m_tx_pkt;
261    uint64_t   m_tx_rx_check_pkt;
262    uint64_t   m_tx_bytes;
263    uint64_t   m_tx_drop;
264    uint64_t   m_tx_queue_full;
265    uint64_t   m_tx_alloc_error;
266    tx_per_flow_t m_tx_per_flow[MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD];
267    CLatencyPktData m_lat_data[MAX_FLOW_STATS_PAYLOAD];
268    CPerTxthreadTemplateInfo m_template;
269
270public:
271
272    void Add(CVirtualIFPerSideStats * obj){
273        m_tx_pkt     += obj->m_tx_pkt;
274        m_tx_rx_check_pkt +=obj->m_tx_rx_check_pkt;
275        m_tx_bytes   += obj->m_tx_bytes;
276        m_tx_drop    += obj->m_tx_drop;
277        m_tx_alloc_error += obj->m_tx_alloc_error;
278        m_tx_queue_full +=obj->m_tx_queue_full;
279        m_template.Add(&obj->m_template);
280    }
281
282    void Clear(){
283       m_tx_pkt=0;
284       m_tx_rx_check_pkt=0;
285       m_tx_bytes=0;
286       m_tx_drop=0;
287       m_tx_alloc_error=0;
288       m_tx_queue_full=0;
289       m_template.Clear();
290       for (int i = 0; i < MAX_FLOW_STATS_PAYLOAD; i++) {
291           m_lat_data[i].reset();
292       }
293       for (int i = 0; i < sizeof(m_tx_per_flow) / sizeof(m_tx_per_flow[0]); i++) {
294           m_tx_per_flow[i].clear();
295       }
296    }
297
298    inline void Dump(FILE *fd);
299};
300
301
302void CVirtualIFPerSideStats::Dump(FILE *fd){
303
304    #define DP_B(f) if (f) printf(" %-40s : %lu \n",#f,f)
305    DP_B(m_tx_pkt);
306    DP_B(m_tx_rx_check_pkt);
307    DP_B(m_tx_bytes);
308    DP_B(m_tx_drop);
309    DP_B(m_tx_alloc_error);
310    DP_B(m_tx_queue_full);
311    m_template.Dump(fd);
312}
313
314class CVirtualIF {
315public:
316    CVirtualIF () {
317        m_preview_mode = NULL;
318    }
319    virtual ~CVirtualIF() {}
320    virtual int open_file(std::string file_name)=0;
321    virtual int close_file(void)=0;
322    /* send one packet */
323    virtual int send_node(CGenNode * node)=0;
324    /* send one packet to a specific dir. flush all packets */
325    virtual void send_one_pkt(pkt_dir_t dir, rte_mbuf_t *m) {}
326    /* flush all pending packets into the stream */
327    virtual int flush_tx_queue(void)=0;
328    /* update the source and destination mac-addr of a given mbuf by global database */
329    virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p)=0;
330    /* translate port_id to the correct dir on the core */
331    virtual pkt_dir_t port_id_to_dir(uint8_t port_id) {
332        return (CS_INVALID);
333    }
334    void set_review_mode(CPreviewMode *preview_mode) {
335        m_preview_mode = preview_mode;
336    }
337
338protected:
339    CPreviewMode            * m_preview_mode;
340
341public:
342    CVirtualIFPerSideStats    m_stats[CS_NUM];
343};
344
345/* global info */
346
347#define CONST_NB_MBUF  16380
348
349/* this is the first small part of the packet that we manipulate */
350#define FIRST_PKT_SIZE 64
351#define CONST_SMALL_MBUF_SIZE (FIRST_PKT_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
352
353
354#define _128_MBUF_SIZE 128
355#define _256_MBUF_SIZE 256
356#define _512_MBUF_SIZE 512
357#define _1024_MBUF_SIZE 1024
358#define _2048_MBUF_SIZE 2048
359#define _4096_MBUF_SIZE 4096
360#define MAX_PKT_ALIGN_BUF_9K       (9*1024+64)
361
362#define MBUF_PKT_PREFIX ( sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM )
363
364#define CONST_128_MBUF_SIZE (128 + MBUF_PKT_PREFIX )
365#define CONST_256_MBUF_SIZE (256 + MBUF_PKT_PREFIX )
366#define CONST_512_MBUF_SIZE (512 + MBUF_PKT_PREFIX)
367#define CONST_1024_MBUF_SIZE (1024 + MBUF_PKT_PREFIX)
368#define CONST_2048_MBUF_SIZE (2048 + MBUF_PKT_PREFIX)
369#define CONST_4096_MBUF_SIZE (4096 + MBUF_PKT_PREFIX)
370#define CONST_9k_MBUF_SIZE   (MAX_PKT_ALIGN_BUF_9K + MBUF_PKT_PREFIX)
371
372
373#define TW_BUCKETS       (CGlobalInfo::m_options.get_tw_buckets())
374#define TW_BUCKETS_LEVEL1_DIV (16)
375#define TW_LEVELS        (CGlobalInfo::m_options.get_tw_levels())
376#define BUCKET_TIME_SEC (CGlobalInfo::m_options.get_tw_bucket_time_in_sec())
377#define BUCKET_TIME_SEC_LEVEL1 (CGlobalInfo::m_options.get_tw_bucket_level1_time_in_sec())
378
379
380class CPreviewMode {
381public:
382    CPreviewMode(){
383        clean();
384    }
385    void clean(){
386        m_flags = 0;
387        m_flags1=0;
388        setCores(1);
389        set_zmq_publish_enable(true);
390    }
391
392    void setFileWrite(bool enable){
393        btSetMaskBit32(m_flags,0,0,enable?1:0);
394    }
395
396    bool getFileWrite(){
397        return (btGetMaskBit32(m_flags,0,0) ? true:false);
398    }
399
400    void setDisableMbufCache(bool enable){
401        btSetMaskBit32(m_flags,2,2,enable?1:0);
402    }
403
404    bool isMbufCacheDisabled(){
405        return (btGetMaskBit32(m_flags,2,2) ? true:false);
406    }
407
408    void set_disable_flow_control_setting(bool enable){
409        btSetMaskBit32(m_flags,4,4,enable?1:0);
410    }
411
412    bool get_is_disable_flow_control_setting(){
413        return (btGetMaskBit32(m_flags,4,4) ? true:false);
414    }
415
416
417          /* learn & verify mode  */
418    void set_learn_and_verify_mode_enable(bool enable){
419        btSetMaskBit32(m_flags,5,5,enable?1:0);
420    }
421
422    bool get_learn_and_verify_mode_enable(){
423        return (btGetMaskBit32(m_flags,5,5) ? true:false);
424    }
425
426  /* IPv6 enable/disable */
427    void set_ipv6_mode_enable(bool enable){
428        btSetMaskBit32(m_flags,7,7,enable?1:0);
429    }
430
431    bool get_ipv6_mode_enable(){
432        return (btGetMaskBit32(m_flags,7,7) ? true:false);
433    }
434
435    void setVMode(uint8_t vmode){
436        btSetMaskBit32(m_flags,10,8,vmode);
437    }
438    uint8_t  getVMode(){
439        return (btGetMaskBit32(m_flags,10,8) );
440    }
441
442
443    void setRealTime(bool enable){
444        btSetMaskBit32(m_flags,11,11,enable?1:0);
445    }
446
447    bool getRealTime(){
448        return (btGetMaskBit32(m_flags,11,11) ? true:false);
449    }
450
451    void setClientServerFlip(bool enable){
452        btSetMaskBit32(m_flags,12,12,enable?1:0);
453    }
454
455    bool getClientServerFlip(){
456        return (btGetMaskBit32(m_flags,12,12) ? true:false);
457    }
458
459    void setSingleCore(bool enable){
460        btSetMaskBit32(m_flags,13,13,enable?1:0);
461    }
462
463    bool getSingleCore(){
464        return (btGetMaskBit32(m_flags,13,13) ? true:false);
465    }
466
467    /* -p */
468    void setClientServerFlowFlip(bool enable){
469        btSetMaskBit32(m_flags,14,14,enable?1:0);
470    }
471
472    bool getClientServerFlowFlip(){
473        return (btGetMaskBit32(m_flags,14,14) ? true:false);
474    }
475
476
477
478    void setNoCleanFlowClose(bool enable){
479        btSetMaskBit32(m_flags,15,15,enable?1:0);
480    }
481
482    bool getNoCleanFlowClose(){
483        return (btGetMaskBit32(m_flags,15,15) ? true:false);
484    }
485
486    void setCores(uint8_t cores){
487        btSetMaskBit32(m_flags,24,16,cores);
488    }
489
490    uint8_t getCores(){
491        return (btGetMaskBit32(m_flags,24,16) );
492    }
493
494    bool  getIsOneCore(){
495        return (getCores()==1?true:false);
496    }
497
498    void setOnlyLatency(bool enable){
499        btSetMaskBit32(m_flags,25,25,enable?1:0);
500    }
501
502    bool getOnlyLatency(){
503        return (btGetMaskBit32(m_flags,25,25) ? true:false);
504    }
505
506    // bit 26 is free. Was deprecated option.
507
508    void set_zmq_publish_enable(bool enable){
509        btSetMaskBit32(m_flags,27,27,enable?1:0);
510    }
511
512    bool get_zmq_publish_enable(){
513        return (btGetMaskBit32(m_flags,27,27) ? true:false);
514    }
515
516    void set_pcap_mode_enable(bool enable){
517        btSetMaskBit32(m_flags,28,28,enable?1:0);
518    }
519
520    bool get_pcap_mode_enable(){
521        return (btGetMaskBit32(m_flags,28,28) ? true:false);
522    }
523
524    /* VLAN enable/disable */
525    bool get_vlan_mode_enable(){
526        return (btGetMaskBit32(m_flags,29,29) ? true:false);
527    }
528
529    void set_vlan_mode_enable(bool enable){
530        btSetMaskBit32(m_flags,29,29,enable?1:0);
531    }
532
533    bool get_mac_ip_overide_enable(){
534        return (btGetMaskBit32(m_flags,30,30) ? true:false);
535    }
536
537    void set_mac_ip_overide_enable(bool enable){
538        btSetMaskBit32(m_flags,30,30,enable?1:0);
539        if (enable) {
540            set_slowpath_features_on(enable);
541        }
542    }
543
544    bool get_is_rx_check_enable(){
545        return (btGetMaskBit32(m_flags,31,31) ? true:false);
546    }
547
548    void set_rx_check_enable(bool enable){
549        btSetMaskBit32(m_flags,31,31,enable?1:0);
550    }
551
552    bool get_is_slowpath_features_on() {
553        return (btGetMaskBit32(m_flags1, 0, 0) ? true : false);
554    }
555
556    void set_slowpath_features_on(bool enable) {
557        btSetMaskBit32(m_flags1, 0, 0, enable ? 1 : 0);
558    }
559
560    bool get_is_client_cfg_enable() {
561        return (btGetMaskBit32(m_flags1, 1, 1) ? true : false);
562    }
563
564    void set_client_cfg_enable(bool enable){
565        btSetMaskBit32(m_flags1, 1, 1, enable ? 1 : 0);
566        if (enable) {
567            set_slowpath_features_on(enable);
568        }
569    }
570
571
572
573    bool get_vm_one_queue_enable(){
574        return (btGetMaskBit32(m_flags1,2,2) ? true:false);
575    }
576
577    void set_no_keyboard(bool enable){
578        btSetMaskBit32(m_flags1,5,5,enable?1:0);
579    }
580
581    bool get_no_keyboard(){
582        return (btGetMaskBit32(m_flags1,5,5) ? true:false);
583    }
584
585    void set_vm_one_queue_enable(bool enable){
586        btSetMaskBit32(m_flags1,2,2,enable?1:0);
587    }
588
589    /* -e */
590    void setClientServerFlowFlipAddr(bool enable){
591        btSetMaskBit32(m_flags1,3,3,enable?1:0);
592    }
593
594    bool getClientServerFlowFlipAddr(){
595        return (btGetMaskBit32(m_flags1,3,3) ? true:false);
596    }
597
598    /* split mac is enabled */
599    void setWDDisable(bool wd_disable){
600        btSetMaskBit32(m_flags1,6,6,wd_disable?1:0);
601    }
602
603    bool getWDDisable(){
604        return (btGetMaskBit32(m_flags1,6,6) ? true:false);
605    }
606
607    void setCoreDumpEnable(bool enable) {
608        btSetMaskBit32(m_flags1, 7, 7, (enable ? 1 : 0) );
609    }
610
611    bool getCoreDumpEnable(){
612        return (btGetMaskBit32(m_flags1, 7, 7) ? true : false);
613    }
614
615    void setChecksumOffloadEnable(bool enable) {
616        btSetMaskBit32(m_flags1, 8, 8, (enable ? 1 : 0) );
617    }
618
619    bool getChecksumOffloadEnable(){
620        return (btGetMaskBit32(m_flags1, 8, 8) ? true : false);
621    }
622
623    void setCloseEnable(bool enable) {
624        btSetMaskBit32(m_flags1, 9, 9, (enable ? 1 : 0) );
625    }
626
627    bool getCloseEnable(){
628        return (btGetMaskBit32(m_flags1, 9, 9) ? true : false);
629    }
630
631    void set_rt_prio_mode(bool enable) {
632        btSetMaskBit32(m_flags1, 10, 10, (enable ? 1 : 0) );
633    }
634
635    bool get_rt_prio_mode() {
636        return (btGetMaskBit32(m_flags1, 10, 10) ? true : false);
637    }
638
639    void set_mlx5_so_mode(bool enable) {
640        btSetMaskBit32(m_flags1, 11, 11, (enable ? 1 : 0) );
641    }
642
643    bool get_mlx5_so_mode() {
644        return (btGetMaskBit32(m_flags1, 11, 11) ? true : false);
645    }
646
647public:
648    void Dump(FILE *fd);
649
650private:
651    uint32_t      m_flags;
652    uint32_t      m_flags1;
653
654
655};
656
657
658
659typedef  struct mac_align_t_ {
660        uint8_t dest[6];
661        uint8_t src[6];
662        uint8_t is_set;
663        uint8_t pad[3];
664} mac_align_t  ;
665
666struct CMacAddrCfg {
667public:
668    CMacAddrCfg () {
669        reset();
670    }
671    void reset () {
672        memset(u.m_data, 0, sizeof(u.m_data));
673        u.m_mac.dest[3] = 1;
674        u.m_mac.is_set = 0;
675    }
676    union {
677        mac_align_t m_mac;
678        uint8_t     m_data[16];
679    } u;
680} __rte_cache_aligned; ;
681
682class CPerPortIPCfg {
683 public:
684    uint32_t get_ip() {return m_ip;}
685    uint32_t get_mask() {return m_mask;}
686    uint32_t get_def_gw() {return m_def_gw;}
687    uint32_t get_vlan() {return m_vlan;}
688    void set_ip(uint32_t val) {m_ip = val;}
689    void set_mask(uint32_t val) {m_mask = val;}
690    void set_def_gw(uint32_t val) {m_def_gw = val;}
691    void set_vlan(uint16_t val) {m_vlan = val;}
692
693 private:
694    uint32_t m_def_gw;
695    uint32_t m_ip;
696    uint32_t m_mask;
697    uint16_t m_vlan;
698};
699
700
701class CParserOption {
702
703public:
704    /* Runtime flags */
705    enum {
706        RUN_FLAGS_RXCHECK_CONST_TS =1,
707    };
708
709    /**
710     * different running modes for Trex
711     */
712    enum trex_run_mode_e {
713        RUN_MODE_INVALID,
714        RUN_MODE_BATCH,
715        RUN_MODE_INTERACTIVE,
716        RUN_MODE_DUMP_INFO,
717    };
718
719    enum trex_learn_mode_e {
720    LEARN_MODE_DISABLED=0,
721    LEARN_MODE_TCP_ACK=1,
722    LEARN_MODE_IP_OPTION=2,
723    LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND=3,
724    LEARN_MODE_MAX=LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND,
725    // This is used to check if 1 or 3 exist
726    LEARN_MODE_TCP=100
727    };
728
729public:
730
731    void reset() {
732        preview.clean();
733        m_tw_buckets = 1024;
734        m_tw_levels = 3;
735        m_active_flows = 0;
736        m_factor = 1.0;
737        m_mbuf_factor = 1.0;
738        m_duration = 0.0;
739        m_platform_factor = 1.0;
740        m_vlan_port[0] = 100;
741        m_vlan_port[1] = 100;
742        memset(m_src_ipv6, 0, sizeof(m_src_ipv6));
743        memset(m_dst_ipv6, 0, sizeof(m_dst_ipv6));
744        memset(m_ip_cfg, 0, sizeof(m_ip_cfg));
745        m_latency_rate = 0;
746        m_latency_mask = 0xffffffff;
747        m_latency_prev = 0;
748        m_rx_check_sample = 0;
749        m_rx_check_hops = 0;
750        m_wait_before_traffic = 1;
751        m_zmq_port = 4500;
752        m_telnet_port = 4501;
753        m_expected_portd = 4; /* should be at least the number of ports found in the system but could be less */
754        m_io_mode = 1;
755        m_run_flags = 0;
756        m_l_pkt_mode = 0;
757        m_learn_mode = 0;
758        m_debug_pkt_proto = 0;
759        m_arp_ref_per = 120; // in seconds
760        m_rx_thread_enabled = false;
761        m_run_mode = RUN_MODE_INVALID;
762        cfg_file = "";
763        client_cfg_file = "";
764        platform_cfg_file = "";
765        out_file = "";
766        prefix = "";
767        set_tw_bucket_time_in_usec(20.0);
768    }
769
770    CParserOption(){
771        reset();
772    }
773
774    CPreviewMode    preview;
775    uint16_t        m_tw_buckets;
776    uint16_t        m_tw_levels;
777    uint32_t        m_active_flows;
778    float           m_factor;
779    float           m_mbuf_factor;
780    float           m_duration;
781    float           m_platform_factor;
782    uint16_t		m_vlan_port[2]; /* vlan value */
783    uint16_t		m_src_ipv6[6];  /* Most signficant 96-bits */
784    uint16_t		m_dst_ipv6[6];  /* Most signficant 96-bits */
785    CPerPortIPCfg   m_ip_cfg[TREX_MAX_PORTS];
786    uint32_t        m_latency_rate; /* pkt/sec for each thread/port zero disable */
787    uint32_t        m_latency_mask;
788    uint32_t        m_latency_prev;
789    uint32_t        m_wait_before_traffic;
790    uint16_t        m_rx_check_sample; /* the sample rate of flows */
791    uint16_t        m_rx_check_hops;
792    uint16_t        m_zmq_port;
793    uint16_t        m_telnet_port;
794    uint16_t        m_expected_portd;
795    uint16_t        m_io_mode; //0,1,2 0 disable, 1- normal , 2 - short
796    uint16_t        m_run_flags;
797    uint8_t         m_l_pkt_mode;
798    uint8_t         m_learn_mode;
799    uint16_t        m_debug_pkt_proto;
800    uint16_t        m_arp_ref_per;
801    bool            m_rx_thread_enabled;
802    trex_run_mode_e    m_run_mode;
803    std::string        cfg_file;
804    std::string        client_cfg_file;
805    std::string        platform_cfg_file;
806    std::string        out_file;
807    std::string        prefix;
808    std::vector<std::string> dump_interfaces;
809    CMacAddrCfg     m_mac_addr[TREX_MAX_PORTS];
810    double          m_tw_bucket_time_sec;
811    double          m_tw_bucket_time_sec_level1;
812
813public:
814    uint8_t *       get_src_mac_addr(int if_index){
815        return (m_mac_addr[if_index].u.m_mac.src);
816    }
817    uint8_t *       get_dst_src_mac_addr(int if_index){
818        return (m_mac_addr[if_index].u.m_mac.dest);
819    }
820
821    uint32_t get_expected_ports(){
822        return (m_expected_portd);
823    }
824
825    /* how many dual ports supported */
826    uint32_t get_expected_dual_ports(void){
827        return (m_expected_portd>>1);
828    }
829
830    uint32_t get_number_of_dp_cores_needed() {
831        return ( (m_expected_portd>>1)   * preview.getCores());
832    }
833    bool is_stateless(){
834        if (m_run_mode == RUN_MODE_INVALID) {
835            fprintf(stderr, "Internal bug: Calling is stateless before initializing run mode\n");
836            fprintf(stderr, "Try to put -i or -f <file> option as first in the option list\n");
837            exit(-1);
838        }
839        return (m_run_mode == RUN_MODE_INTERACTIVE ?true:false);
840    }
841    bool is_latency_enabled() {
842        return ( (m_latency_rate == 0) ? false : true);
843    }
844    bool is_rx_enabled() {
845        return m_rx_thread_enabled;
846    }
847    void set_rx_enabled() {
848        m_rx_thread_enabled = true;
849    }
850
851    inline double get_tw_bucket_time_in_sec(void){
852        return (m_tw_bucket_time_sec);
853    }
854
855    inline double get_tw_bucket_level1_time_in_sec(void){
856        return (m_tw_bucket_time_sec_level1);
857    }
858
859    void set_tw_bucket_time_in_usec(double usec){
860        m_tw_bucket_time_sec= (usec/1000000.0);
861        m_tw_bucket_time_sec_level1 = (m_tw_bucket_time_sec*(double)m_tw_buckets)/((double)TW_BUCKETS_LEVEL1_DIV);
862    }
863
864    void     set_tw_buckets(uint16_t buckets){
865        m_tw_buckets=buckets;
866    }
867
868    inline uint16_t get_tw_buckets(void){
869        return (m_tw_buckets);
870    }
871
872    void     set_tw_levels(uint16_t levels){
873        m_tw_levels=levels;
874    }
875
876    inline uint16_t get_tw_levels(void){
877        return (m_tw_levels);
878    }
879
880
881
882    inline void set_rxcheck_const_ts(){
883        m_run_flags |= RUN_FLAGS_RXCHECK_CONST_TS;
884    }
885    inline void clear_rxcheck_const_ts(){
886        m_run_flags &=~ RUN_FLAGS_RXCHECK_CONST_TS;
887    }
888
889    inline bool is_rxcheck_const_ts(){
890        return (  (m_run_flags &RUN_FLAGS_RXCHECK_CONST_TS)?true:false );
891    }
892
893    inline uint8_t get_l_pkt_mode(){
894        return (m_l_pkt_mode);
895    }
896    void dump(FILE *fd);
897    bool is_valid_opt_val(int val, int min, int max, const std::string &opt_name);
898
899    void verify();
900};
901
902
903class  CGlobalMemory {
904
905public:
906    CGlobalMemory(){
907        CPlatformMemoryYamlInfo info;
908        m_num_cores=1;
909        m_pool_cache_size=32;
910    }
911    void set(const CPlatformMemoryYamlInfo &info,float mul);
912
913    uint32_t get_2k_num_blocks(){
914        return ( m_mbuf[MBUF_2048]);
915    }
916
917    uint32_t get_each_core_dp_flows(){
918        return ( m_mbuf[MBUF_DP_FLOWS]/m_num_cores );
919    }
920    void set_number_of_dp_cors(uint32_t cores){
921        m_num_cores = cores;
922    }
923
924    void set_pool_cache_size(uint32_t pool_cache){
925        m_pool_cache_size=pool_cache;
926    }
927
928    void Dump(FILE *fd);
929
930public:
931    uint32_t         m_mbuf[MBUF_ELM_SIZE]; // relative to traffic norm to 2x10G ports
932    uint32_t         m_num_cores;
933    uint32_t         m_pool_cache_size;
934
935};
936
937typedef uint8_t socket_id_t;
938typedef uint8_t port_id_t;
939/* the real phsical thread id */
940typedef uint8_t physical_thread_id_t;
941
942
943typedef uint8_t virtual_thread_id_t;
944/*
945
946 virtual thread 0 (v0)- is always the master
947
948for 2 dual ports ( 2x2 =4 ports) the virtual thread looks like that
949-----------------
950DEFAULT:
951-----------------
952  (0,1)       (2,3)
953  dual-if0       dual-if-1
954    v1        v2
955    v3        v4
956    v5        v6
957    v7        v8
958
959    rx is v9
960
961  */
962
963#define MAX_SOCKETS_SUPPORTED   (4)
964#define MAX_THREADS_SUPPORTED   (120)
965
966
967class CPlatformSocketInfoBase {
968
969
970public:
971    /* sockets API */
972
973    /* is socket enabled */
974    virtual bool is_sockets_enable(socket_id_t socket)=0;
975
976    /* number of main active sockets. socket #0 is always used  */
977    virtual socket_id_t max_num_active_sockets()=0;
978
979    virtual ~CPlatformSocketInfoBase() {}
980
981public:
982    /* which socket to allocate memory to each port */
983    virtual socket_id_t port_to_socket(port_id_t port)=0;
984
985public:
986    /* this is from CLI, number of thread per dual port */
987    virtual void set_number_of_threads_per_ports(uint8_t num_threads)=0;
988    virtual void set_rx_thread_is_enabled(bool enable)=0;
989    virtual void set_number_of_dual_ports(uint8_t num_dual_ports)=0;
990
991
992    virtual bool sanity_check()=0;
993
994    /* return the core mask */
995    virtual uint64_t get_cores_mask()=0;
996
997    /* virtual thread_id is always from   1..number of threads  virtual  */
998    virtual virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t  phy_id)=0;
999
1000    /* return  the map betwean virtual to phy id */
1001    virtual physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id)=0;
1002
1003
1004    virtual physical_thread_id_t get_master_phy_id() = 0;
1005    virtual bool thread_phy_is_rx(physical_thread_id_t  phy_id)=0;
1006
1007    virtual void dump(FILE *fd)=0;
1008
1009    bool thread_phy_is_master(physical_thread_id_t  phy_id) {
1010        return (get_master_phy_id() == phy_id);
1011    }
1012
1013};
1014
1015class CPlatformSocketInfoNoConfig : public CPlatformSocketInfoBase {
1016
1017public:
1018    CPlatformSocketInfoNoConfig(){
1019        m_dual_if=0;
1020        m_threads_per_dual_if=0;
1021        m_rx_is_enabled=false;
1022    }
1023
1024    /* is socket enabled */
1025    bool is_sockets_enable(socket_id_t socket);
1026
1027    /* number of main active sockets. socket #0 is always used  */
1028    socket_id_t max_num_active_sockets();
1029
1030public:
1031    /* which socket to allocate memory to each port */
1032    socket_id_t port_to_socket(port_id_t port);
1033
1034public:
1035    /* this is from CLI, number of thread per dual port */
1036    void set_number_of_threads_per_ports(uint8_t num_threads);
1037    void set_rx_thread_is_enabled(bool enable);
1038    void set_number_of_dual_ports(uint8_t num_dual_ports);
1039
1040    bool sanity_check();
1041
1042    /* return the core mask */
1043    uint64_t get_cores_mask();
1044
1045    /* virtual thread_id is always from   1..number of threads  virtual  */
1046    virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t  phy_id);
1047
1048    /* return  the map betwean virtual to phy id */
1049    physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id);
1050
1051    physical_thread_id_t get_master_phy_id();
1052    bool thread_phy_is_rx(physical_thread_id_t  phy_id);
1053
1054    virtual void dump(FILE *fd);
1055
1056private:
1057    uint32_t                 m_dual_if;
1058    uint32_t                 m_threads_per_dual_if;
1059    bool                     m_rx_is_enabled;
1060};
1061
1062
1063
1064/* there is a configuration file */
1065class CPlatformSocketInfoConfig : public CPlatformSocketInfoBase {
1066public:
1067    bool Create(CPlatformCoresYamlInfo * platform);
1068    void Delete();
1069
1070        /* is socket enabled */
1071    bool is_sockets_enable(socket_id_t socket);
1072
1073    /* number of main active sockets. socket #0 is always used  */
1074    socket_id_t max_num_active_sockets();
1075
1076public:
1077    /* which socket to allocate memory to each port */
1078    socket_id_t port_to_socket(port_id_t port);
1079
1080public:
1081    /* this is from CLI, number of thread per dual port */
1082    void set_number_of_threads_per_ports(uint8_t num_threads);
1083    void set_rx_thread_is_enabled(bool enable);
1084    void set_number_of_dual_ports(uint8_t num_dual_ports);
1085
1086    bool sanity_check();
1087
1088    /* return the core mask */
1089    uint64_t get_cores_mask();
1090
1091    /* virtual thread_id is always from   1..number of threads  virtual  */
1092    virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t  phy_id);
1093
1094    /* return  the map betwean virtual to phy id */
1095    physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id);
1096
1097    physical_thread_id_t get_master_phy_id();
1098    bool thread_phy_is_rx(physical_thread_id_t  phy_id);
1099
1100public:
1101    virtual void dump(FILE *fd);
1102private:
1103    void reset();
1104    bool init();
1105
1106private:
1107    bool                     m_sockets_enable[MAX_SOCKETS_SUPPORTED];
1108    uint32_t                 m_sockets_enabled;
1109    socket_id_t              m_socket_per_dual_if[(TREX_MAX_PORTS >> 1)];
1110
1111    uint32_t                 m_max_threads_per_dual_if;
1112
1113    uint32_t                 m_num_dual_if;
1114    uint32_t                 m_threads_per_dual_if;
1115    bool                     m_rx_is_enabled;
1116    uint8_t                  m_thread_virt_to_phy[MAX_THREADS_SUPPORTED];
1117    uint8_t                  m_thread_phy_to_virtual[MAX_THREADS_SUPPORTED];
1118
1119    CPlatformCoresYamlInfo * m_platform;
1120};
1121
1122
1123
1124class CPlatformSocketInfo {
1125
1126public:
1127    bool Create(CPlatformCoresYamlInfo * platform);
1128    void Delete();
1129
1130public:
1131    /* sockets API */
1132
1133    /* is socket enabled */
1134    bool is_sockets_enable(socket_id_t socket);
1135
1136    /* number of main active sockets. socket #0 is always used  */
1137    socket_id_t max_num_active_sockets();
1138
1139public:
1140    /* which socket to allocate memory to each port */
1141    socket_id_t port_to_socket(port_id_t port);
1142
1143public:
1144    /* this is from CLI, number of thread per dual port */
1145    void set_number_of_threads_per_ports(uint8_t num_threads);
1146    void set_rx_thread_is_enabled(bool enable);
1147    void set_number_of_dual_ports(uint8_t num_dual_ports);
1148
1149
1150    bool sanity_check();
1151
1152    /* return the core mask */
1153    uint64_t get_cores_mask();
1154
1155    /* virtual thread_id is always from   1..number of threads  virtual  */
1156    virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t  phy_id);
1157
1158    /* return  the map betwean virtual to phy id */
1159    physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id);
1160
1161    bool thread_phy_is_master(physical_thread_id_t  phy_id);
1162    physical_thread_id_t get_master_phy_id();
1163    bool thread_phy_is_rx(physical_thread_id_t  phy_id);
1164
1165    void dump(FILE *fd);
1166
1167
1168private:
1169    CPlatformSocketInfoBase * m_obj;
1170    CPlatformCoresYamlInfo * m_platform;
1171};
1172
1173class CRteMemPool {
1174
1175public:
1176    inline rte_mbuf_t   * _rte_pktmbuf_alloc(rte_mempool_t * mp ){
1177        rte_mbuf_t   * m=rte_pktmbuf_alloc(mp);
1178        if ( likely(m>0) ) {
1179            return (m);
1180        }
1181        dump_in_case_of_error(stderr);
1182        assert(0);
1183    }
1184
1185    inline rte_mbuf_t   * pktmbuf_alloc(uint16_t size){
1186
1187        rte_mbuf_t        * m;
1188        if ( size < _128_MBUF_SIZE) {
1189            m = _rte_pktmbuf_alloc(m_mbuf_pool_128);
1190        }else if ( size < _256_MBUF_SIZE) {
1191            m = _rte_pktmbuf_alloc(m_mbuf_pool_256);
1192        }else if (size < _512_MBUF_SIZE) {
1193            m = _rte_pktmbuf_alloc(m_mbuf_pool_512);
1194        }else if (size < _1024_MBUF_SIZE) {
1195            m = _rte_pktmbuf_alloc(m_mbuf_pool_1024);
1196        }else if (size < _2048_MBUF_SIZE) {
1197            m = _rte_pktmbuf_alloc(m_mbuf_pool_2048);
1198        }else if (size < _4096_MBUF_SIZE) {
1199            m = _rte_pktmbuf_alloc(m_mbuf_pool_4096);
1200        }else{
1201            assert(size<MAX_PKT_ALIGN_BUF_9K);
1202            m = _rte_pktmbuf_alloc(m_mbuf_pool_9k);
1203        }
1204        return (m);
1205    }
1206
1207    inline rte_mbuf_t   * pktmbuf_alloc_small(){
1208        return ( _rte_pktmbuf_alloc(m_small_mbuf_pool) );
1209    }
1210
1211
1212    void dump(FILE *fd);
1213
1214    void dump_in_case_of_error(FILE *fd);
1215
1216    void dump_as_json(Json::Value &json);
1217
1218private:
1219    void add_to_json(Json::Value &json, std::string name, rte_mempool_t * pool);
1220
1221public:
1222    rte_mempool_t *   m_small_mbuf_pool; /* pool for start packets */
1223
1224    rte_mempool_t *   m_mbuf_pool_128;
1225    rte_mempool_t *   m_mbuf_pool_256;
1226    rte_mempool_t *   m_mbuf_pool_512;
1227    rte_mempool_t *   m_mbuf_pool_1024;
1228    rte_mempool_t *   m_mbuf_pool_2048;
1229    rte_mempool_t *   m_mbuf_pool_4096;
1230    rte_mempool_t *   m_mbuf_pool_9k;
1231
1232    rte_mempool_t *   m_mbuf_global_nodes;
1233    uint32_t          m_pool_id;
1234};
1235
1236
1237
1238
1239class CGlobalInfo {
1240public:
1241    static void init_pools(uint32_t rx_buffers);
1242    /* for simulation */
1243    static void free_pools();
1244
1245    static inline rte_mbuf_t   * pktmbuf_alloc_small(socket_id_t socket){
1246        return ( m_mem_pool[socket].pktmbuf_alloc_small() );
1247    }
1248
1249    static inline rte_mbuf_t * pktmbuf_alloc_small_by_port(uint8_t port_id) {
1250        return ( m_mem_pool[m_socket.port_to_socket(port_id)].pktmbuf_alloc_small() );
1251    }
1252
1253    /**
1254     * try to allocate small buffers too
1255     * _alloc allocate big buffers only
1256     *
1257     * @param socket
1258     * @param size
1259     *
1260     * @return
1261     */
1262    static inline rte_mbuf_t   * pktmbuf_alloc(socket_id_t socket,uint16_t size){
1263        if (size<FIRST_PKT_SIZE) {
1264            return ( pktmbuf_alloc_small(socket));
1265        }
1266        return (m_mem_pool[socket].pktmbuf_alloc(size));
1267    }
1268
1269    static inline rte_mbuf_t * pktmbuf_alloc_by_port(uint8_t port_id, uint16_t size){
1270        socket_id_t socket = m_socket.port_to_socket(port_id);
1271        if (size<FIRST_PKT_SIZE) {
1272            return ( pktmbuf_alloc_small(socket));
1273        }
1274        return (m_mem_pool[socket].pktmbuf_alloc(size));
1275    }
1276
1277    static inline bool is_learn_verify_mode(){
1278        return ( (m_options.m_learn_mode != CParserOption::LEARN_MODE_DISABLED) && m_options.preview.get_learn_and_verify_mode_enable());
1279    }
1280
1281    static inline bool is_learn_mode(){
1282        return ( (m_options.m_learn_mode != CParserOption::LEARN_MODE_DISABLED));
1283    }
1284
1285    static inline bool is_learn_mode(CParserOption::trex_learn_mode_e mode){
1286        if (mode == CParserOption::LEARN_MODE_TCP) {
1287            return ((m_options.m_learn_mode == CParserOption::LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND)
1288                    || (m_options.m_learn_mode == CParserOption::LEARN_MODE_TCP_ACK));
1289        } else
1290            return (m_options.m_learn_mode == mode);
1291    }
1292
1293    static inline bool is_ipv6_enable(void){
1294        return ( m_options.preview.get_ipv6_mode_enable() );
1295    }
1296
1297    static inline bool is_realtime(void){
1298        //return (false);
1299        return ( m_options.preview.getRealTime() );
1300    }
1301
1302    static inline void set_realtime(bool enable){
1303        m_options.preview.setRealTime(enable);
1304    }
1305
1306    static uint32_t get_node_pool_size(){
1307        return (m_nodes_pool_size);
1308    }
1309
1310    static inline CGenNode * create_node(void){
1311        CGenNode * res;
1312        if ( unlikely (rte_mempool_get(m_mem_pool[0].m_mbuf_global_nodes, (void **)&res) <0) ){
1313            rte_exit(EXIT_FAILURE, "can't allocate m_mbuf_global_nodes  objects try to tune the configuration file \n");
1314            return (0);
1315        }
1316        return (res);
1317    }
1318
1319
1320    static inline void free_node(CGenNode *p){
1321        rte_mempool_put(m_mem_pool[0].m_mbuf_global_nodes, p);
1322    }
1323
1324
1325    static void dump_pool_as_json(Json::Value &json);
1326    static std::string dump_pool_as_json_str(void);
1327
1328
1329public:
1330    static CRteMemPool       m_mem_pool[MAX_SOCKETS_SUPPORTED];
1331
1332    static uint32_t              m_nodes_pool_size;
1333    static CParserOption         m_options;
1334    static CGlobalMemory         m_memory_cfg;
1335    static CPlatformSocketInfo   m_socket;
1336};
1337
1338static inline int get_is_stateless(){
1339    return (CGlobalInfo::m_options.is_stateless() );
1340}
1341
1342static inline int get_is_rx_check_mode(){
1343    return (CGlobalInfo::m_options.preview.get_is_rx_check_enable() ?1:0);
1344}
1345
1346static inline bool get_is_rx_filter_enable(){
1347    uint32_t latency_rate=CGlobalInfo::m_options.m_latency_rate;
1348    return ( ( get_is_rx_check_mode() || CGlobalInfo::is_learn_mode() || latency_rate != 0
1349               || get_is_stateless()) ?true:false );
1350}
1351static inline uint16_t get_rx_check_hops() {
1352    return (CGlobalInfo::m_options.m_rx_check_hops);
1353}
1354
1355#define MAX_PYLOAD_PKT_CHANGE 4
1356/* info for the dynamic plugin */
1357
1358
1359struct CFlowYamlDpPkt {
1360    CFlowYamlDpPkt(){
1361        m_pkt_id=0xff;
1362        m_pyld_offset=0;
1363        m_type=0;
1364        m_len=0;
1365        m_pkt_mask=0xffffffff;
1366    }
1367
1368    uint8_t   m_pkt_id; /* number of packet */
1369    uint8_t   m_pyld_offset; /* 0-10 */
1370    uint8_t   m_type;  /* 0 -random , 1 - inc */
1371    uint8_t   m_len;   /* number of 32bit data 1,2,3,*/
1372
1373    uint32_t  m_pkt_mask; /* 0xffffffff take all the packet */
1374public:
1375    void Dump(FILE *fd);
1376};
1377
1378struct CFlowYamlDynamicPyloadPlugin {
1379
1380    CFlowYamlDynamicPyloadPlugin(){
1381        m_num=0;
1382        int i;
1383        for (i=0;i<MAX_PYLOAD_PKT_CHANGE;i++ ) {
1384            m_pkt_ids[i]=0xff;
1385        }
1386    }
1387
1388    uint8_t         m_num;/* number of pkts_id*/
1389    uint8_t         m_pkt_ids[MAX_PYLOAD_PKT_CHANGE]; /* -1 for not valid - fast mask */
1390    CFlowYamlDpPkt  m_program[MAX_PYLOAD_PKT_CHANGE];
1391public:
1392    void Add(CFlowYamlDpPkt & fd);
1393    void Dump(FILE *fd);
1394};
1395
1396struct CVlanYamlInfo {
1397    CVlanYamlInfo(){
1398        m_enable=0;
1399        m_vlan_per_port[0]=100;
1400        m_vlan_per_port[1]=200;
1401    }
1402    bool            m_enable;
1403    uint16_t        m_vlan_per_port[2];
1404
1405public:
1406    void Dump(FILE *fd);
1407
1408};
1409
1410
1411
1412struct CFlowYamlInfo {
1413    CFlowYamlInfo(){
1414        m_dpPkt=0;
1415        m_server_addr=0;
1416        m_client_pool_idx = 0;
1417        m_server_pool_idx = 0;
1418        m_cap_mode=false;
1419        m_ipg_sec=0.01;
1420        m_rtt_sec=0.01;
1421    }
1422
1423    std::string     m_name;
1424    std::string     m_client_pool_name;
1425    std::string     m_server_pool_name;
1426    double          m_k_cps;    //k CPS
1427    double          m_restart_time; /* restart time of this template */
1428    dsec_t          m_ipg_sec;   // ipg in sec
1429    dsec_t          m_rtt_sec;   // rtt in sec
1430    uint32_t        m_w;
1431    uint32_t        m_wlength;
1432    uint32_t        m_limit;
1433    uint32_t        m_flowcnt;
1434    uint8_t         m_plugin_id; /* 0 - default , 1 - RTSP160 , 2- RTSP250 */
1435    uint8_t         m_client_pool_idx;
1436    uint8_t         m_server_pool_idx;
1437    bool            m_one_app_server;
1438    uint32_t        m_server_addr;
1439    bool            m_one_app_server_was_set;
1440    bool            m_cap_mode;
1441    bool            m_cap_mode_was_set;
1442    bool            m_wlength_set;
1443    bool            m_limit_was_set;
1444    CFlowYamlDynamicPyloadPlugin * m_dpPkt; /* plugin */
1445
1446public:
1447    void Dump(FILE *fd);
1448};
1449
1450
1451
1452
1453#define _1MB_DOUBLE ((double)(1024.0*1024.0))
1454#define _1GB_DOUBLE ((double)(1024.0*1024.0*1024.0))
1455
1456#define _1Mb_DOUBLE ((double)(1000.0*1000.0))
1457
1458
1459#define _1MB ((1024*1024)ULL)
1460#define _1GB 1000000000ULL
1461#define _500GB (_1GB*500)
1462
1463
1464
1465#define DP(f) if (f) printf(" %-40s: %llu \n",#f,(unsigned long long)f)
1466#define DP_name(n,f) if (f) printf(" %-40s: %llu \n",n,(unsigned long long)f)
1467
1468#define DP_S(f,f_s) if (f) printf(" %-40s: %s \n",#f,f_s.c_str())
1469
1470class CFlowPktInfo;
1471
1472
1473
1474typedef enum {
1475    KBYE_1024,
1476    KBYE_1000
1477} human_kbyte_t;
1478
1479std::string double_to_human_str(double num,
1480                                std::string units,
1481                                human_kbyte_t etype);
1482
1483
1484
1485class CCapFileFlowInfo ;
1486
1487#define SYNC_TIME_OUT ( 1.0/1000)
1488
1489//#define SYNC_TIME_OUT ( 2000.0/1000)
1490
1491/* this is a simple struct, do not add constructor and destractor here!
1492   we are optimizing the allocation dealocation !!!
1493 */
1494
1495struct CGenNodeBase  {
1496public:
1497
1498    enum {
1499        FLOW_PKT                =0,
1500        FLOW_FIF                =1,
1501        FLOW_DEFER_PORT_RELEASE =2,
1502        FLOW_PKT_NAT            =3,
1503        FLOW_SYNC               =4,     /* called evey 1 msec */
1504        STATELESS_PKT           =5,
1505        EXIT_SCHED              =6,
1506        COMMAND                 =7,
1507        EXIT_PORT_SCHED         =8,
1508        PCAP_PKT                =9,
1509        GRAT_ARP                =10,
1510        TW_SYNC                 =11,
1511        TW_SYNC1                =12,
1512
1513    };
1514
1515    /* flags MASKS*/
1516    enum {
1517        NODE_FLAGS_DIR                  =1,
1518        NODE_FLAGS_MBUF_CACHE           =2,
1519        NODE_FLAGS_SAMPLE_RX_CHECK      =4,
1520
1521        NODE_FLAGS_LEARN_MODE           =8,   /* bits 3,4 MASK 0x18 wait for second direction packet */
1522        NODE_FLAGS_LEARN_MSG_PROCESSED  =0x10,   /* got NAT msg */
1523
1524        NODE_FLAGS_LATENCY              =0x20,   /* got NAT msg */
1525        NODE_FLAGS_INIT_START_FROM_SERVER_SIDE = 0x40,
1526        NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE     = 0x80,
1527        NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR = 0x100, /* init packet start from server side with server addr */
1528        NODE_FLAGS_SLOW_PATH = 0x200 /* used by the nodes to differ between fast path nodes and slow path nodes */
1529    };
1530
1531
1532public:
1533    /*********************************************/
1534    /* C1  must */
1535    uint8_t             m_type;
1536    uint8_t             m_thread_id; /* zero base */
1537    uint8_t             m_socket_id;
1538    uint8_t             m_pad2;
1539
1540    uint16_t            m_src_port;
1541    uint16_t            m_flags; /* BIT 0 - DIR ,
1542                                    BIT 1 - mbug_cache
1543                                    BIT 2 - SAMPLE DUPLICATE */
1544
1545    double              m_time;    /* can't change this header - size 16 bytes*/
1546
1547public:
1548    bool operator <(const CGenNodeBase * rsh ) const {
1549        return (m_time<rsh->m_time);
1550    }
1551    bool operator ==(const CGenNodeBase * rsh ) const {
1552        return (m_time==rsh->m_time);
1553    }
1554    bool operator >(const CGenNodeBase * rsh ) const {
1555        return (m_time>rsh->m_time);
1556    }
1557
1558public:
1559    void set_socket_id(socket_id_t socket){
1560        m_socket_id=socket;
1561    }
1562
1563    socket_id_t get_socket_id(){
1564        return ( m_socket_id );
1565    }
1566
1567    inline void set_slow_path(bool enable) {
1568        if (enable) {
1569            m_flags |= NODE_FLAGS_SLOW_PATH;
1570        } else {
1571            m_flags &= ~NODE_FLAGS_SLOW_PATH;
1572        }
1573    }
1574
1575    inline bool get_is_slow_path() const {
1576        return ( (m_flags & NODE_FLAGS_SLOW_PATH) ? true : false);
1577    }
1578
1579    void free_base();
1580
1581    bool is_flow_node(){
1582        if ((m_type == FLOW_PKT) || (m_type == FLOW_PKT_NAT)) {
1583            return (true);
1584        }else{
1585            return (false);
1586        }
1587    }
1588};
1589
1590
1591struct CGenNode : public CGenNodeBase  {
1592
1593public:
1594
1595    uint32_t        m_src_ip;  /* client ip */
1596    uint32_t        m_dest_ip; /* server ip */
1597
1598    uint64_t            m_flow_id; /* id that goes up for each flow */
1599
1600    /*c2*/
1601    CFlowPktInfo *      m_pkt_info;
1602
1603    CCapFileFlowInfo *  m_flow_info;
1604    CFlowYamlInfo    *  m_template_info;
1605
1606    void *              m_plugin_info;
1607
1608/* cache line -2 */
1609    CHTimerObj           m_tmr;
1610    uint64_t             m_tmr_pad[4];
1611
1612/* cache line -3 */
1613
1614
1615    CTupleGeneratorSmart *m_tuple_gen;
1616    // cache line 1 - 64bytes waste of space !
1617    uint32_t            m_nat_external_ipv4; // NAT client IP
1618    uint32_t            m_nat_tcp_seq_diff_client; // support for firewalls that do TCP seq num randomization
1619    uint32_t            m_nat_tcp_seq_diff_server; // And some do seq num randomization for server->client also
1620    uint16_t            m_nat_external_port; // NAT client port
1621    uint16_t            m_nat_pad[1];
1622    const ClientCfgBase *m_client_cfg;
1623    uint32_t            m_src_idx;
1624    uint32_t            m_dest_idx;
1625    uint32_t            m_end_of_cache_line[6];
1626
1627
1628public:
1629    void free_gen_node();
1630public:
1631    void Dump(FILE *fd);
1632
1633
1634
1635    static void DumpHeader(FILE *fd);
1636    inline bool is_last_in_flow();
1637    inline uint16_t get_template_id();
1638    inline bool is_repeat_flow();
1639    inline bool can_cache_mbuf(void);
1640
1641    /* is it possible to cache MBUF */
1642    inline uint32_t update_next_pkt_in_flow_tw(void);
1643
1644    /* update the node time for accurate scheduler */
1645    inline void update_next_pkt_in_flow_as(void);
1646
1647    inline uint32_t update_next_pkt_in_flow_both(void);
1648
1649
1650    inline void reset_pkt_in_flow(void);
1651    inline uint8_t get_plugin_id(void){
1652        return ( m_template_info->m_plugin_id);
1653    }
1654
1655    inline bool is_responder_pkt();
1656    inline bool is_initiator_pkt();
1657
1658
1659    inline bool is_eligible_from_server_side(){
1660        return ( ( (m_src_ip&1) == 1)?true:false);
1661    }
1662
1663
1664    inline void set_initiator_start_from_server_side_with_server_addr(bool enable){
1665           if (enable) {
1666            m_flags |= NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR;
1667           }else{
1668            m_flags &=~ NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR;
1669           }
1670    }
1671
1672    inline bool get_is_initiator_start_from_server_with_server_addr(){
1673            return (  (m_flags &NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR)?true:false );
1674    }
1675
1676    inline void set_initiator_start_from_server(bool enable){
1677       if (enable) {
1678        m_flags |= NODE_FLAGS_INIT_START_FROM_SERVER_SIDE;
1679       }else{
1680        m_flags &=~ NODE_FLAGS_INIT_START_FROM_SERVER_SIDE;
1681       }
1682    }
1683    inline bool get_is_initiator_start_from_server(){
1684        return (  (m_flags &NODE_FLAGS_INIT_START_FROM_SERVER_SIDE)?true:false );
1685    }
1686
1687    inline void set_all_flow_from_same_dir(bool enable){
1688        if (enable) {
1689         m_flags |= NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE;
1690        }else{
1691         m_flags &=~ NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE;
1692        }
1693    }
1694
1695    inline bool get_is_all_flow_from_same_dir(void){
1696        return (  (m_flags &NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE)?true:false );
1697    }
1698
1699
1700
1701    /* direction for ip addr */
1702    inline  pkt_dir_t cur_pkt_ip_addr_dir();
1703    /* direction for TCP/UDP port */
1704    inline  pkt_dir_t cur_pkt_port_addr_dir();
1705    /* from which interface dir to get out */
1706    inline  pkt_dir_t cur_interface_dir();
1707
1708
1709    inline void set_mbuf_cache_dir(pkt_dir_t  dir){
1710        if (dir) {
1711            m_flags |=NODE_FLAGS_DIR;
1712        }else{
1713            m_flags &=~NODE_FLAGS_DIR;
1714        }
1715    }
1716
1717    inline pkt_dir_t get_mbuf_cache_dir(){
1718        return ((pkt_dir_t)( m_flags &1));
1719    }
1720
1721    inline void set_cache_mbuf(rte_mbuf_t * m){
1722        m_plugin_info=(void *)m;
1723        m_flags |= NODE_FLAGS_MBUF_CACHE;
1724    }
1725
1726    inline rte_mbuf_t * get_cache_mbuf(){
1727        if ( m_flags &NODE_FLAGS_MBUF_CACHE ) {
1728            return ((rte_mbuf_t *)m_plugin_info);
1729        }else{
1730            return ((rte_mbuf_t *)0);
1731        }
1732    }
1733
1734public:
1735
1736    inline void set_rx_check(){
1737        m_flags |= NODE_FLAGS_SAMPLE_RX_CHECK;
1738    }
1739
1740    inline bool is_rx_check_enabled(){
1741        return ((m_flags & NODE_FLAGS_SAMPLE_RX_CHECK)?true:false);
1742    }
1743
1744public:
1745
1746    inline void set_nat_first_state(){
1747        btSetMaskBit16(m_flags,4,3,1);
1748        m_type=FLOW_PKT_NAT;
1749    }
1750
1751    inline bool is_nat_first_state(){
1752        return (btGetMaskBit16(m_flags,4,3)==1?true:false) ;
1753    }
1754
1755    inline void set_nat_wait_state(){
1756        btSetMaskBit16(m_flags,4,3,2);
1757    }
1758
1759
1760    inline bool is_nat_wait_state(){
1761        return (btGetMaskBit16(m_flags,4,3)==2?true:false) ;
1762    }
1763
1764    // We saw first TCP SYN. Waiting for SYN+ACK
1765    inline void set_nat_wait_ack_state() {
1766        btSetMaskBit16(m_flags, 4, 3, 3);
1767    }
1768
1769    inline bool is_nat_wait_ack_state(){
1770        return (btGetMaskBit16(m_flags,4,3) == 3) ? true : false;
1771    }
1772
1773    inline void set_nat_learn_state(){
1774        m_type=FLOW_PKT; /* normal operation .. repeat might work too */
1775    }
1776
1777public:
1778    inline uint32_t get_short_fid(void){
1779        return (((uint32_t)m_flow_id) & NAT_FLOW_ID_MASK_TCP_ACK);
1780    }
1781
1782    inline uint8_t get_thread_id(void){
1783        return (m_thread_id);
1784    }
1785
1786    inline void set_nat_tcp_seq_diff_client(uint32_t diff) {
1787        m_nat_tcp_seq_diff_client = diff;
1788    }
1789
1790    inline uint32_t get_nat_tcp_seq_diff_client() {
1791        return m_nat_tcp_seq_diff_client;
1792    }
1793
1794    inline void set_nat_tcp_seq_diff_server(uint32_t diff) {
1795        m_nat_tcp_seq_diff_server = diff;
1796    }
1797
1798    inline uint32_t get_nat_tcp_seq_diff_server() {
1799        return m_nat_tcp_seq_diff_server;
1800    }
1801
1802    inline void set_nat_ipv4_addr(uint32_t ip){
1803        m_nat_external_ipv4 =ip;
1804    }
1805
1806    inline void set_nat_ipv4_port(uint16_t port){
1807        m_nat_external_port = port;
1808    }
1809
1810    inline uint32_t  get_nat_ipv4_addr(){
1811        return ( m_nat_external_ipv4 );
1812    }
1813
1814    inline uint16_t get_nat_ipv4_port(){
1815        return ( m_nat_external_port );
1816    }
1817
1818    bool is_external_is_eq_to_internal_ip(){
1819        /* this API is used to check TRex itself */
1820        if ( (get_nat_ipv4_addr() == m_src_ip ) &&
1821             (get_nat_ipv4_port()==m_src_port)) {
1822            return (true);
1823        }else{
1824            return (false);
1825        }
1826    }
1827
1828
1829public:
1830    inline void replace_tuple(void);
1831
1832} __rte_cache_aligned;
1833
1834
1835
1836
1837
1838#if __x86_64__
1839/* size of 64 bytes */
1840    #define DEFER_CLIENTS_NUM (16)
1841#else
1842    #define DEFER_CLIENTS_NUM (16)
1843#endif
1844
1845/* this class must be in the same size of CGenNode */
1846struct CGenNodeDeferPort  {
1847    /* this header must be the same as CGenNode */
1848    uint8_t             m_type;
1849    uint8_t             m_pad3;
1850    uint16_t            m_pad2;
1851    uint32_t            m_cnt;
1852    double              m_time;
1853
1854    uint32_t            m_clients[DEFER_CLIENTS_NUM];
1855    uint16_t            m_ports[DEFER_CLIENTS_NUM];
1856    uint8_t             m_pool_idx[DEFER_CLIENTS_NUM];
1857    uint64_t            m_pad4[8];
1858
1859public:
1860    void init(void){
1861        m_type=CGenNode::FLOW_DEFER_PORT_RELEASE;
1862        m_cnt=0;
1863    }
1864
1865    /* return true if object is full */
1866    bool add_client(uint8_t pool_idx, uint32_t client,
1867                   uint16_t port){
1868        m_clients[m_cnt]=client;
1869        m_ports[m_cnt]=port;
1870        m_pool_idx[m_cnt] = pool_idx;
1871        m_cnt++;
1872        if ( m_cnt == DEFER_CLIENTS_NUM ) {
1873            return (true);
1874        }
1875        return (false);
1876    }
1877
1878} __rte_cache_aligned ;
1879
1880/* run time verification of objects size and offsets
1881   need to clean this up and derive this objects from base object but require too much refactoring right now
1882   hhaim
1883*/
1884
1885#define COMPARE_NODE_OBJECT(NODE_NAME)     if ( sizeof(NODE_NAME) != sizeof(CGenNode)  ) { \
1886                                            printf("ERROR sizeof(%s) %lu != sizeof(CGenNode) %lu must be the same size \n",#NODE_NAME,sizeof(NODE_NAME),sizeof(CGenNode)); \
1887                                            assert(0); \
1888                                            }\
1889                                            if ( (int)offsetof(struct NODE_NAME,m_type)!=offsetof(struct CGenNodeBase,m_type) ){\
1890                                            printf("ERROR offsetof(struct %s,m_type)!=offsetof(struct CGenNodeBase,m_type) \n",#NODE_NAME);\
1891                                            assert(0);\
1892                                            }\
1893                                            if ( (int)offsetof(struct CGenNodeDeferPort,m_time)!=offsetof(struct CGenNodeBase,m_time) ){\
1894                                            printf("ERROR offsetof(struct %s,m_time)!=offsetof(struct CGenNodeBase,m_time) \n",#NODE_NAME);\
1895                                            assert(0);\
1896                                            }
1897
1898#define COMPARE_NODE_OBJECT_SIZE(NODE_NAME)     if ( sizeof(NODE_NAME) != sizeof(CGenNode)  ) { \
1899                                            printf("ERROR sizeof(%s) %lu != sizeof(CGenNode) %lu must be the same size \n",#NODE_NAME,sizeof(NODE_NAME),sizeof(CGenNode)); \
1900                                            assert(0); \
1901                                            }
1902
1903
1904
1905inline int check_objects_sizes(void){
1906    COMPARE_NODE_OBJECT(CGenNodeDeferPort);
1907    return (0);
1908}
1909
1910
1911struct CGenNodeCompare
1912{
1913   bool operator() (const CGenNode * lhs, const CGenNode * rhs)
1914   {
1915       return lhs->m_time > rhs->m_time;
1916   }
1917};
1918
1919
1920class CCapPktRaw;
1921class CFileWriterBase;
1922
1923
1924
1925class CFlowGenStats {
1926public:
1927    CFlowGenStats(){
1928        clear();
1929    }
1930    // stats
1931    uint64_t                         m_total_bytes;
1932    uint64_t                         m_total_pkt;
1933    uint64_t                         m_total_open_flows;
1934    uint64_t                         m_total_close_flows;
1935    uint64_t                         m_nat_lookup_no_flow_id;
1936    uint64_t                         m_nat_lookup_remove_flow_id;
1937    uint64_t                         m_nat_lookup_wait_ack_state;
1938    uint64_t                         m_nat_lookup_add_flow_id;
1939    uint64_t                         m_nat_flow_timeout;
1940    uint64_t                         m_nat_flow_timeout_wait_ack;
1941    uint64_t                         m_nat_flow_learn_error;
1942
1943public:
1944    void clear();
1945    void dump(FILE *fd);
1946};
1947
1948
1949
1950typedef std::priority_queue<CGenNode *, std::vector<CGenNode *>,CGenNodeCompare> pqueue_t;
1951
1952
1953
1954class CErfIF : public CVirtualIF {
1955    friend class basic_client_cfg_test1_Test;
1956public:
1957    CErfIF(){
1958        m_writer=NULL;
1959        m_raw=NULL;
1960    }
1961public:
1962
1963    virtual int open_file(std::string file_name);
1964    virtual int write_pkt(CCapPktRaw *pkt_raw);
1965    virtual int close_file(void);
1966
1967    virtual int update_mac_addr_from_global_cfg(pkt_dir_t       dir, uint8_t * p){
1968        return (0);
1969    }
1970
1971
1972
1973    /**
1974     * send one packet
1975     *
1976     * @param node
1977     *
1978     * @return
1979     */
1980    virtual int send_node(CGenNode * node);
1981
1982
1983
1984    /**
1985     * flush all pending packets into the stream
1986     *
1987     * @return
1988     */
1989    virtual int flush_tx_queue(void);
1990
1991
1992protected:
1993    void add_vlan(uint16_t vlan_id);
1994    void apply_client_config(const ClientCfgBase *cfg, pkt_dir_t dir);
1995    virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir);
1996
1997    CFileWriterBase         * m_writer;
1998    CCapPktRaw              * m_raw;
1999};
2000
2001/* for stateless we have a small changes in case we send the packets for optimization */
2002class CErfIFStl : public CErfIF {
2003
2004public:
2005
2006    virtual int send_node(CGenNode * node);
2007
2008    virtual int update_mac_addr_from_global_cfg(pkt_dir_t       dir, uint8_t * p);
2009
2010    virtual pkt_dir_t port_id_to_dir(uint8_t port_id);
2011
2012private:
2013    int send_sl_node(CGenNodeStateless * node_sl);
2014    int send_pcap_node(CGenNodePCAP * pcap_node);
2015
2016};
2017
2018/**
2019 * same as regular STL but no I/O (dry run)
2020 *
2021 * @author imarom (07-Jan-16)
2022 */
2023class CErfIFStlNull : public CErfIFStl {
2024public:
2025
2026    virtual int open_file(std::string file_name) {
2027        return (0);
2028    }
2029
2030    virtual int write_pkt(CCapPktRaw *pkt_raw) {
2031        return (0);
2032    }
2033
2034    virtual int close_file(void) {
2035        return (0);
2036    }
2037
2038    virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir) {
2039
2040    }
2041
2042
2043
2044    virtual int flush_tx_queue(void){
2045        return (0);
2046
2047    }
2048
2049};
2050
2051
2052static inline int fill_pkt(CCapPktRaw  * raw,rte_mbuf_t * m){
2053    raw->pkt_len = m->pkt_len;
2054    char *p=raw->raw;
2055
2056    rte_mbuf_t *m_next;
2057
2058    while (m != NULL) {
2059        m_next = m->next;
2060        rte_memcpy(p,m->buf_addr,m->data_len);
2061        p+=m->data_len;
2062        m = m_next;
2063    }
2064    return (0);
2065}
2066
2067
2068class CNullIF : public CVirtualIF {
2069
2070public:
2071    CNullIF(){
2072    }
2073
2074public:
2075
2076    virtual int open_file(std::string file_name){
2077        return (0);
2078    }
2079
2080    virtual int write_pkt(CCapPktRaw *pkt_raw){
2081        return (0);
2082    }
2083
2084    virtual int close_file(void){
2085        return (0);
2086    }
2087
2088    virtual int update_mac_addr_from_global_cfg(pkt_dir_t       dir, uint8_t * p){
2089        return (0);
2090    }
2091
2092
2093    virtual int send_node(CGenNode * node);
2094
2095    virtual int flush_tx_queue(void){
2096        return (0);
2097
2098    }
2099};
2100
2101
2102
2103
2104
2105class CNodeGenerator {
2106public:
2107
2108    friend CFlowGenListPerThread;
2109
2110     typedef enum { scINIT = 0x17,
2111                    scWORK ,
2112                    scWAIT ,
2113                    scSTRECH,
2114                    scTERMINATE
2115                   } sch_state_t;
2116
2117   typedef enum { smSTATELESS = 0x17,
2118                  smSTATEFUL  ,
2119                 } sch_mode_t;
2120
2121   #define BURST_OFFSET_DTIME    (100.0/1000000)
2122   #define EAT_WINDOW_DTIME      (15.0/1000000)
2123   #define WAIT_WINDOW_SIZE      (-1.0/1000000)
2124
2125    bool  Create(CFlowGenListPerThread  *  parent);
2126    void  Delete();
2127
2128    void  set_vif(CVirtualIF * v_if);
2129
2130    CFlowGenListPerThread  *  Parent(){
2131        return (m_parent);
2132    }
2133
2134public:
2135    void  add_node(CGenNode * mynode);
2136    void  remove_all(CFlowGenListPerThread * thread);
2137    void  remove_all_stateless(CFlowGenListPerThread * thread);
2138
2139    int   open_file(std::string file_name,
2140                    CPreviewMode * preview);
2141    int   close_file(CFlowGenListPerThread * thread);
2142    int   flush_file(dsec_t max_time,
2143                     dsec_t d_time,
2144                     bool on_terminate,
2145                     CFlowGenListPerThread * thread,
2146                     double & old_offset);
2147    int   defer_handler(CFlowGenListPerThread * thread);
2148
2149    void schedule_node(CGenNode * node,double delay){
2150        node->m_time = (now_sec()+ delay);
2151        add_node(node);
2152    }
2153
2154    /**
2155     * set packet limit for the generator
2156     */
2157    void set_packet_limit(uint64_t limit) {
2158        m_limit = limit;
2159    }
2160
2161    void DumpHist(FILE *fd){
2162        fprintf(fd,"\n");
2163        fprintf(fd,"\n");
2164        fprintf(fd,"normal\n");
2165        fprintf(fd,"-------------\n");
2166        m_realtime_his.Dump(fd);
2167    }
2168
2169    void dump_json(std::string & json);
2170
2171
2172
2173private:
2174
2175    #ifdef _DEBUG
2176      #define UPDATE_STATS(a) update_stats(a)
2177    #else
2178      #define UPDATE_STATS(a)
2179    #endif
2180
2181    int   update_stats(CGenNode * node);
2182
2183    inline int   flush_one_node_to_file(CGenNode * node){
2184        return (m_v_if->send_node(node));
2185    }
2186    int   update_stl_stats(CGenNodeStateless *node_sl);
2187    bool  has_limit_reached();
2188
2189    FORCE_NO_INLINE bool handle_slow_messages(uint8_t type,
2190                                              CGenNode * node,
2191                                              CFlowGenListPerThread * thread,
2192                                              bool on_terminate);
2193
2194private:
2195        void add_exit_node(CFlowGenListPerThread * thread,
2196                                          dsec_t max_time);
2197
2198        inline bool handle_stl_node(CGenNode * node,
2199                                    CFlowGenListPerThread * thread);
2200
2201
2202        FORCE_INLINE bool do_work_stl(CGenNode * node,
2203                                      CFlowGenListPerThread * thread,
2204                                      bool on_terminate);
2205
2206        template<bool ON_TERMINATE>
2207        FORCE_INLINE bool do_work_both(CGenNode * node,
2208                                      CFlowGenListPerThread * thread,
2209                                      dsec_t d_time);
2210
2211        template<int SCH_MODE,bool ON_TERMINATE>
2212        FORCE_INLINE bool do_work(CGenNode * node,
2213                                  CFlowGenListPerThread * thread,
2214                                  dsec_t d_time);
2215
2216        FORCE_INLINE void do_sleep(dsec_t & cur_time,
2217                                   CFlowGenListPerThread * thread,
2218                                   dsec_t ntime);
2219
2220
2221        FORCE_INLINE int teardown(CFlowGenListPerThread * thread,
2222                                   bool on_terminate,
2223                                   double &old_offset,
2224                                   double offset);
2225
2226        template<int SCH_MODE,bool ON_TERIMATE>
2227        int flush_file_realtime(dsec_t max_time,
2228                                dsec_t d_time,
2229                                CFlowGenListPerThread * thread,
2230                                double &old_offset);
2231
2232        int flush_file_sim(dsec_t max_time,
2233                            dsec_t d_time,
2234                            bool always,
2235                            CFlowGenListPerThread * thread,
2236                            double &old_offset);
2237
2238        FORCE_NO_INLINE void handle_slow_operations(sch_state_t &state,
2239                                                    CGenNode * &node,
2240                                                    dsec_t &cur_time,
2241                                                    dsec_t &n_time,
2242                                                    dsec_t &offset,
2243                                                    CFlowGenListPerThread *thread);
2244
2245        void handle_time_strech(CGenNode * &node,
2246                                dsec_t &cur_time,
2247                                dsec_t &n_time,
2248                                dsec_t &offset,
2249                                CFlowGenListPerThread *thread);
2250
2251
2252private:
2253    void handle_command(CGenNode *node, CFlowGenListPerThread *thread, bool &exit_scheduler);
2254    void handle_flow_pkt(CGenNode *node, CFlowGenListPerThread *thread);
2255    void handle_flow_sync(CGenNode *node, CFlowGenListPerThread *thread, bool &exit_scheduler);
2256    void handle_pcap_pkt(CGenNode *node, CFlowGenListPerThread *thread);
2257    void handle_maintenance(CFlowGenListPerThread *thread);
2258    void handle_batch_tw_level1(CGenNode *node, CFlowGenListPerThread *thread,bool &exit_scheduler,bool on_terminate);
2259
2260
2261public:
2262    pqueue_t                  m_p_queue;
2263    socket_id_t               m_socket_id;
2264    CVirtualIF *              m_v_if;
2265    CFlowGenListPerThread  *  m_parent;
2266    CPreviewMode              m_preview_mode;
2267    uint64_t                  m_cnt;
2268    uint64_t                  m_non_active;
2269    uint64_t                  m_limit;
2270    CTimeHistogram            m_realtime_his;
2271    dsec_t                    m_scheduler_offset;
2272
2273    dsec_t                    m_last_sync_time_sec;
2274    dsec_t                    m_tw_level1_next_sec;
2275};
2276
2277
2278class CPolicer {
2279
2280public:
2281
2282    CPolicer(){
2283        ClearMeter();
2284    }
2285
2286    void ClearMeter(){
2287        m_cir=0.0;
2288        m_bucket_size=1.0;
2289        m_level=0.0;
2290        m_last_time=0.0;
2291    }
2292
2293    bool update(double dsize,dsec_t now_sec);
2294
2295    void set_cir(double cir){
2296        BP_ASSERT(cir>=0.0);
2297        m_cir=cir;
2298    }
2299    void set_level(double level){
2300        m_level =level;
2301    }
2302
2303    void set_bucket_size(double bucket){
2304        m_bucket_size =bucket;
2305    }
2306
2307private:
2308
2309    double                      m_cir;
2310
2311    double                      m_bucket_size;
2312
2313    double                      m_level;
2314
2315    double                      m_last_time;
2316};
2317
2318class CFlowKey {
2319public:
2320    uint32_t                m_ipaddr1;
2321    uint32_t                m_ipaddr2;
2322
2323    uint16_t                m_port1;
2324    uint16_t                m_port2;
2325
2326    uint8_t                 m_ip_proto; /* TCP/UDP 6/17*/
2327    uint8_t                 m_l2_proto; /*IPV4/IPV6*/
2328    uint16_t                m_vrfid;
2329
2330public:
2331    inline bool operator <(const CFlowKey& rhs) const;
2332    inline bool operator >(const CFlowKey& rhs) const;
2333    inline bool operator ==(const CFlowKey& rhs) const;
2334public:
2335    void Dump(FILE *fd);
2336    void Clean();
2337};
2338
2339
2340inline  bool CFlowKey::operator <(const CFlowKey& rhs) const{
2341    int cmp=memcmp(&m_ipaddr1,&rhs.m_ipaddr1 ,sizeof(CFlowKey));
2342    if (cmp>0) {
2343        return (true);
2344    }else{
2345        return (false);
2346    }
2347}
2348
2349inline bool CFlowKey::operator >(const CFlowKey& rhs) const{
2350    int cmp=memcmp(&m_ipaddr1,&rhs.m_ipaddr1 ,sizeof(CFlowKey));
2351    if (cmp<0) {
2352        return (true);
2353    }else{
2354        return (false);
2355    }
2356}
2357
2358inline bool CFlowKey::operator ==(const CFlowKey& rhs) const{
2359    int cmp=memcmp(&m_ipaddr1,&rhs.m_ipaddr1 ,sizeof(CFlowKey));
2360    if (cmp==0) {
2361        return (true);
2362    }else{
2363        return (false);
2364    }
2365}
2366
2367
2368
2369/***********************************************************/
2370/* descriptor flags                                        */
2371
2372#define IS_SWAP_S 0
2373#define IS_SWAP_E 0
2374
2375#define IS_VALID_S 1
2376#define IS_VALID_E 1
2377
2378#define PROTO_S 3
2379#define PROTO_E 2
2380
2381#define IS_INIT_SIDE 4
2382
2383#define IS_LAST_PKT_S 5
2384#define IS_LAST_PKT_E 5
2385
2386#define IS_RTT 6
2387
2388#define IS_PCAP_TIMING 7
2389
2390// 8-12 is used
2391#define FLOW_ID 8
2392
2393
2394#define PLUGIN_ENABLE_S 13
2395#define PLUGIN_ENABLE_E 13
2396#define BOTH_DIR_FLOW_SE 14
2397#define LEARN_MODE_ENABLE 15
2398
2399/***********************************************************/
2400
2401class CPacketDescriptorPerDir {
2402public:
2403    CPacketDescriptorPerDir(){
2404       m_dir_pkt_num=0;
2405       m_max_dir_flow_pkts=0;
2406    }
2407public:
2408    void SetMaxPkts( uint32_t val){
2409        assert(val<65000);
2410        m_max_dir_flow_pkts = (uint16_t)val;
2411    }
2412    uint16_t GetMaxPkts(void){
2413        return (m_max_dir_flow_pkts);
2414    }
2415
2416    void SetPktNum(uint32_t pkt_id){
2417        assert(pkt_id<65000);
2418        m_dir_pkt_num=(uint16_t)pkt_id;
2419    }
2420
2421    uint16_t GetPktNum(void){
2422        return (m_dir_pkt_num);
2423    }
2424
2425private:
2426    // per direction info
2427    uint16_t    m_dir_pkt_num;   // pkt id
2428    uint16_t    m_max_dir_flow_pkts;
2429};
2430
2431
2432class CPacketDescriptor {
2433
2434public:
2435
2436    inline void Clear(){
2437        m_flags = 0;
2438        m_flow_pkt_num=0;
2439        m_plugin_id=0;
2440        m_max_flow_pkts=0;
2441        m_max_flow_aging=0;
2442    }
2443
2444    inline uint8_t getPluginId(){
2445        return (m_plugin_id);
2446    }
2447    inline void SetPluginId(uint8_t plugin_id){
2448        m_plugin_id=plugin_id;
2449    }
2450
2451    inline bool IsLearn(){
2452        return (btGetMaskBit32(m_flags,LEARN_MODE_ENABLE,LEARN_MODE_ENABLE) ? true:false);
2453    }
2454    inline void SetLearn(bool enable){
2455        btSetMaskBit32(m_flags,LEARN_MODE_ENABLE ,LEARN_MODE_ENABLE ,enable?1:0);
2456    }
2457
2458
2459    inline bool IsPluginEnable(){
2460        return (btGetMaskBit32(m_flags,PLUGIN_ENABLE_S,PLUGIN_ENABLE_S) ? true:false);
2461    }
2462    inline void SetPluginEnable(bool enable){
2463        btSetMaskBit32(m_flags,PLUGIN_ENABLE_S ,PLUGIN_ENABLE_S ,enable?1:0);
2464    }
2465
2466    inline bool IsBiDirectionalFlow(){
2467        return (btGetMaskBit32(m_flags,BOTH_DIR_FLOW_SE,BOTH_DIR_FLOW_SE) ? true:false);
2468    }
2469    inline void SetBiPluginEnable(bool enable){
2470        btSetMaskBit32(m_flags,BOTH_DIR_FLOW_SE ,BOTH_DIR_FLOW_SE ,enable?1:0);
2471    }
2472
2473
2474    /* packet number inside the global flow */
2475    inline void SetFlowPktNum(uint32_t pkt_id){
2476        m_flow_pkt_num = pkt_id;
2477
2478    }
2479    /**
2480     * start from zero 0,1,2,.. , it is on global flow if you have couple of flows it will count all of the flows
2481     *
2482     * flow  FlowPktNum
2483     * 0         0
2484     * 0         1
2485     * 0         2
2486     * 1         0
2487     * 1         1
2488     * 2         0
2489     *
2490     * @return
2491     */
2492    inline uint32_t getFlowPktNum(){
2493        return ( m_flow_pkt_num);
2494    }
2495
2496
2497    inline void SetFlowId(uint16_t flow_id){
2498        btSetMaskBit32(m_flags,12,8,flow_id);
2499
2500    }
2501
2502    inline uint16_t getFlowId(){
2503        return ( ( uint16_t)btGetMaskBit32(m_flags,12,8));
2504    }
2505
2506    inline void SetPcapTiming(bool is_pcap){
2507        btSetMaskBit32(m_flags,IS_PCAP_TIMING,IS_PCAP_TIMING,is_pcap?1:0);
2508    }
2509    inline bool IsPcapTiming(){
2510        return (btGetMaskBit32(m_flags,IS_PCAP_TIMING,IS_PCAP_TIMING) ? true:false);
2511    }
2512
2513
2514    /* return true if this packet in diff direction from prev flow packet ,
2515    if true need to choose RTT else IPG for inter packet gap */
2516    inline bool IsRtt(){
2517        return (btGetMaskBit32(m_flags,IS_RTT,IS_RTT) ? true:false);
2518    }
2519    inline void SetRtt(bool is_rtt){
2520        btSetMaskBit32(m_flags,IS_RTT,IS_RTT,is_rtt?1:0);
2521    }
2522
2523    /* this is in respect to the first flow  */
2524    inline bool IsInitSide(){
2525        return (btGetMaskBit32(m_flags,IS_INIT_SIDE,IS_INIT_SIDE) ? true:false);
2526    }
2527
2528    /* this is in respect to the first flow , this is what is needed when we replace IP source / destiniation */
2529    inline void SetInitSide(bool is_init_side){
2530        btSetMaskBit32(m_flags,IS_INIT_SIDE,IS_INIT_SIDE,is_init_side?1:0);
2531    }
2532
2533    /* per flow */
2534    inline bool IsSwapTuple(){
2535        return (btGetMaskBit32(m_flags,IS_SWAP_S,IS_SWAP_E) ? true:false);
2536    }
2537    inline void SetSwapTuple(bool is_swap){
2538        btSetMaskBit32(m_flags,IS_SWAP_S,IS_SWAP_E,is_swap?1:0);
2539    }
2540
2541    inline bool IsValidPkt(){
2542        return (btGetMaskBit32(m_flags,IS_VALID_S,IS_VALID_E) ? true:false);
2543    }
2544
2545    inline void SetIsValidPkt(bool is_valid){
2546        btSetMaskBit32(m_flags,IS_VALID_S,IS_VALID_E,is_valid?1:0);
2547    }
2548
2549    inline void SetIsTcp(bool is_valid){
2550        btSetMaskBit32(m_flags,PROTO_S,PROTO_E,is_valid?1:0);
2551    }
2552
2553    inline bool IsTcp(){
2554        return ((btGetMaskBit32(m_flags,PROTO_S,PROTO_E) == 1) ? true:false);
2555    }
2556
2557    inline void SetIsUdp(bool is_valid){
2558        btSetMaskBit32(m_flags,PROTO_S,PROTO_E,is_valid?2:0);
2559    }
2560
2561    inline bool IsUdp(){
2562        return ((btGetMaskBit32(m_flags,PROTO_S,PROTO_E) == 2) ? true:false);
2563    }
2564
2565    inline void SetIsIcmp(bool is_valid){
2566        btSetMaskBit32(m_flags,PROTO_S,PROTO_E,is_valid?3:0);
2567    }
2568
2569    inline bool IsIcmp(){
2570        return ((btGetMaskBit32(m_flags,PROTO_S,PROTO_E) == 3) ? true:false);
2571    }
2572
2573    inline void SetId(uint16_t _id){
2574        btSetMaskBit32(m_flags,31,16,_id);
2575
2576    }
2577    inline uint16_t getId(){
2578        return ( ( uint16_t)btGetMaskBit32(m_flags,31,16));
2579    }
2580
2581    inline void SetIsLastPkt(bool is_last){
2582        btSetMaskBit32(m_flags,IS_LAST_PKT_S,IS_LAST_PKT_E,is_last?1:0);
2583    }
2584
2585    /* last packet of couple of flows */
2586    inline bool IsLastPkt(){
2587        return (btGetMaskBit32(m_flags,IS_LAST_PKT_S,IS_LAST_PKT_E) ? true:false);
2588    }
2589
2590    // there could be couple of flows per template in case of plugin
2591    inline void SetMaxPktsPerFlow(uint32_t pkts){
2592        assert(pkts<65000);
2593        m_max_flow_pkts=pkts;
2594    }
2595    inline uint16_t GetMaxPktsPerFlow(){
2596        return ( m_max_flow_pkts );
2597    }
2598        // there could be couple of flows per template in case of plugin
2599    inline void SetMaxFlowTimeout(double sec){
2600        //assert (sec<65000);
2601        sec = sec*2.0+5.0;
2602        if ( sec > 65000) {
2603            printf("Warning pcap file aging is %f truncating it \n",sec);
2604            sec = 65000;
2605        }
2606        m_max_flow_aging = (uint16_t)sec;
2607    }
2608
2609    inline uint16_t GetMaxFlowTimeout(void){
2610        return ( m_max_flow_aging );
2611    }
2612
2613    /* return per dir info , the dir is with respect to the first flow client/server side , this is tricky */
2614    CPacketDescriptorPerDir * GetDirInfo(void){
2615        return (&m_per_dir[IsInitSide()?CLIENT_SIDE:SERVER_SIDE]);
2616    }
2617
2618    bool IsOneDirectionalFlow(void){
2619        if ( ( m_per_dir[CLIENT_SIDE].GetMaxPkts() == GetMaxPktsPerFlow()) || ( m_per_dir[SERVER_SIDE].GetMaxPkts() == GetMaxPktsPerFlow()) ) {
2620            return (true);
2621        }else{
2622            return (false);
2623        }
2624    }
2625
2626public:
2627    void Dump(FILE *fd);
2628
2629private:
2630    uint32_t    m_flags;
2631    uint16_t    m_flow_pkt_num; // packet number inside the flow
2632    uint8_t     m_plugin_id; // packet number inside the flow
2633    uint8_t     m_pad;
2634    uint16_t    m_max_flow_pkts;  // how many packet per this flow getFlowId()
2635    uint16_t    m_max_flow_aging; // maximum aging in sec
2636    CPacketDescriptorPerDir  m_per_dir[CS_NUM]; // per direction info
2637};
2638
2639
2640class CPacketParser;
2641class CFlow ;
2642
2643
2644class CCPacketParserCounters {
2645public:
2646    uint64_t  m_pkt;
2647    uint64_t  m_ipv4;
2648    uint64_t  m_ipv6;
2649    uint64_t  m_non_ip;
2650    uint64_t  m_vlan;
2651    uint64_t  m_arp;
2652    uint64_t  m_mpls;
2653
2654
2655    /* IP stats */
2656    uint64_t  m_non_valid_ipv4_ver;
2657    uint64_t  m_non_valid_ipv6_ver;
2658    uint64_t  m_ip_checksum_error;
2659    uint64_t  m_ip_length_error;
2660    uint64_t  m_ipv6_length_error;
2661    uint64_t  m_ip_not_first_fragment_error;
2662    uint64_t  m_ip_ttl_is_zero_error;
2663    uint64_t  m_ip_multicast_error;
2664    uint64_t  m_ip_header_options;
2665
2666    /* TCP/UDP */
2667    uint64_t  m_non_tcp_udp;
2668    uint64_t  m_non_tcp_udp_ah;
2669    uint64_t  m_non_tcp_udp_esp;
2670    uint64_t  m_non_tcp_udp_icmp;
2671    uint64_t  m_non_tcp_udp_gre;
2672    uint64_t  m_non_tcp_udp_ip;
2673    uint64_t  m_tcp_header_options;
2674    uint64_t  m_tcp_udp_pkt_length_error;
2675    uint64_t  m_tcp;
2676    uint64_t  m_udp;
2677    uint64_t  m_valid_udp_tcp;
2678
2679public:
2680    void Clear();
2681    uint64_t getTotalErrors();
2682    void Dump(FILE *fd);
2683};
2684
2685
2686class CPacketIndication {
2687
2688public:
2689    uint32_t            m_ticks;
2690    CPacketDescriptor   m_desc;
2691    CCapPktRaw *        m_packet;
2692
2693    CFlow *          m_flow;
2694    EthernetHeader * m_ether;
2695    union {
2696        IPHeader       * m_ipv4;
2697        IPv6Header     * m_ipv6;
2698    } l3;
2699    bool        m_is_ipv6;
2700    union {
2701        TCPHeader * m_tcp;
2702        UDPHeader * m_udp;
2703        ICMPHeader * m_icmp;
2704    } l4;
2705    uint8_t *       m_payload;
2706    uint16_t        m_payload_len;
2707    uint16_t        m_packet_padding; /* total packet size - IP total length */
2708
2709    dsec_t          m_cap_ipg; /* ipg from cap file */
2710
2711    CFlowKey            m_flow_key;
2712
2713    uint8_t             m_ether_offset;
2714    uint8_t             m_ip_offset;
2715    uint8_t             m_udp_tcp_offset;
2716    uint8_t             m_payload_offset;
2717
2718public:
2719
2720    void Dump(FILE *fd,int verbose);
2721    void Clean();
2722    bool ConvertPacketToIpv6InPlace(CCapPktRaw * pkt,
2723                                    int offset);
2724    void ProcessPacket(CPacketParser *parser,CCapPktRaw * pkt);
2725    void Clone(CPacketIndication * obj,CCapPktRaw * pkt);
2726    void RefreshPointers(void);
2727    void UpdatePacketPadding();
2728
2729public:
2730    bool is_ipv6(){
2731        return (m_is_ipv6);
2732    }
2733    char * getBasePtr(){
2734        return ((char *)m_packet->raw);
2735    }
2736
2737    uint32_t getEtherOffset(){
2738        BP_ASSERT(m_ether);
2739        return (uint32_t)((uintptr_t) (((char *)m_ether)- getBasePtr()) );
2740    }
2741    uint32_t getIpOffset(){
2742        if (l3.m_ipv4 != NULL) {
2743            return (uint32_t)((uintptr_t)( ((char *)l3.m_ipv4)-getBasePtr()) );
2744        }else{
2745            BP_ASSERT(0);
2746            return (0);
2747        }
2748    }
2749
2750
2751    /**
2752     * return the application ipv4/ipv6 option offset
2753     * if learn bit is ON , it is always the first options ( IPV6/IPV4)
2754     *
2755     * @return
2756     */
2757    uint32_t getIpAppOptionOffset(){
2758        if ( is_ipv6() ) {
2759            return  ( getIpOffset()+IPv6Header::DefaultSize);
2760        }else{
2761            return  ( getIpOffset()+IPHeader::DefaultSize);
2762        }
2763    }
2764
2765    uint32_t getTcpOffset(){
2766        BP_ASSERT(l4.m_tcp);
2767        return (uint32_t)((uintptr_t) ((char *)l4.m_tcp-getBasePtr()) );
2768    }
2769    uint32_t getPayloadOffset(){
2770        if (m_payload) {
2771            return (uint32_t)((uintptr_t) ((char *)m_payload-getBasePtr()) );
2772        }else{
2773            return (0);
2774        }
2775    }
2776
2777    // if is_nat is true, turn on MSB of IP_ID, else turn it off
2778    void setIpIdNat(bool is_nat) {
2779        BP_ASSERT(l3.m_ipv4);
2780        if (! is_ipv6()) {
2781            if (is_nat) {
2782                l3.m_ipv4->setId(l3.m_ipv4->getId() | 0x8000);
2783            } else {
2784                l3.m_ipv4->setId(l3.m_ipv4->getId() & 0x7fff);
2785            }
2786        }
2787    }
2788
2789    void  setTOSReserve(){
2790        BP_ASSERT(l3.m_ipv4);
2791        if (is_ipv6()) {
2792            l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass() | TOS_TTL_RESERVE_DUPLICATE );
2793        }else{
2794            l3.m_ipv4->setTOS(l3.m_ipv4->getTOS()| TOS_TTL_RESERVE_DUPLICATE );
2795        }
2796    }
2797
2798    void  clearTOSReserve(){
2799        BP_ASSERT(l3.m_ipv4);
2800        if (is_ipv6()) {
2801            l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass()& (~TOS_TTL_RESERVE_DUPLICATE) );
2802        }else{
2803            l3.m_ipv4->setTOS(l3.m_ipv4->getTOS() & (~TOS_TTL_RESERVE_DUPLICATE) );
2804        }
2805    }
2806
2807    uint8_t getTTL(){
2808        BP_ASSERT(l3.m_ipv4);
2809        if (is_ipv6()) {
2810            return(l3.m_ipv6->getHopLimit());
2811        }else{
2812            return(l3.m_ipv4->getTimeToLive());
2813        }
2814    }
2815    void setTTL(uint8_t ttl){
2816        BP_ASSERT(l3.m_ipv4);
2817        if (is_ipv6()) {
2818            l3.m_ipv6->setHopLimit(ttl);
2819        }else{
2820            l3.m_ipv4->setTimeToLive(ttl);
2821            l3.m_ipv4->updateCheckSum();
2822        }
2823    }
2824
2825    uint8_t getIpProto(){
2826        BP_ASSERT(l3.m_ipv4);
2827        if (is_ipv6()) {
2828            return(l3.m_ipv6->getNextHdr());
2829        }else{
2830            return(l3.m_ipv4->getProtocol());
2831        }
2832    }
2833
2834    uint8_t getFastEtherOffset(void){
2835        return (m_ether_offset);
2836    }
2837    uint8_t getFastIpOffsetFast(void){
2838        return (m_ip_offset);
2839    }
2840    uint8_t getFastTcpOffset(void){
2841        return (m_udp_tcp_offset );
2842    }
2843    uint8_t getFastPayloadOffset(void){
2844        return (m_payload_offset );
2845    }
2846private:
2847    void SetKey(void);
2848    uint8_t ProcessIpPacketProtocol(CCPacketParserCounters *m_cnt,
2849                                    uint8_t protocol, int *offset);
2850    void ProcessIpPacket(CPacketParser *parser,int offset);
2851    void ProcessIpv6Packet(CPacketParser *parser,int offset);
2852    void _ProcessPacket(CPacketParser *parser,CCapPktRaw * pkt);
2853
2854    void UpdateOffsets();
2855};
2856
2857
2858
2859#define SRC_IP_BASE 0x10000001
2860#define DST_IP_BASE 0x20000001
2861
2862class CFlowTemplateGenerator {
2863public:
2864    CFlowTemplateGenerator(uint64_t fid){
2865        src_ip_base=((SRC_IP_BASE + (uint32_t)fid )& 0x7fffffff);
2866        dst_ip_base=((DST_IP_BASE + (uint32_t) ((fid & 0xffffffff00000000ULL)>>32)) & 0x7fffffff);
2867    }
2868public:
2869    uint32_t src_ip_base;
2870    uint32_t dst_ip_base;
2871};
2872
2873
2874class CPacketParser {
2875
2876public:
2877    bool Create();
2878    void Delete();
2879    bool ProcessPacket(CPacketIndication * pkt_indication,
2880                       CCapPktRaw * raw_packet);
2881public:
2882    CCPacketParserCounters m_counter;
2883public:
2884    void Dump(FILE *fd);
2885};
2886
2887
2888class CFlowTableStats {
2889public:
2890    uint64_t  m_lookup;
2891    uint64_t  m_found;
2892    uint64_t  m_fif;
2893    uint64_t  m_add;
2894    uint64_t  m_remove;
2895    uint64_t  m_fif_err;
2896    uint64_t  m_active;
2897public:
2898    void Clear();
2899    void Dump(FILE *fd);
2900};
2901
2902
2903
2904class CFlow {
2905public:
2906    CFlow(){
2907        is_fif_swap=0;
2908        pkt_id=0;
2909    }
2910    ~CFlow(){
2911       }
2912public:
2913    void Dump(FILE *fd);
2914public:
2915    uint8_t   is_fif_swap;
2916    uint32_t  pkt_id;
2917    uint32_t  flow_id;
2918};
2919
2920class CFlowTableInterator {
2921public:
2922    virtual void do_flow(CFlow *flow)=0;
2923};
2924
2925class CFlowTableManagerBase {
2926public:
2927    virtual bool Create(int max_size)=0;
2928    virtual void Delete()=0;
2929public:
2930    CFlow * process(const CFlowKey & key,bool &is_fif  );
2931    virtual void remove(const CFlowKey & key )=0;
2932    virtual void remove_all()=0;
2933    virtual uint64_t count()=0;
2934public:
2935    void Dump(FILE *fd);
2936protected:
2937    virtual CFlow * lookup(const CFlowKey & key )=0;
2938    virtual CFlow * add(const CFlowKey & key )=0;
2939
2940    //virtual IterateFlows(CFlowTableInterator * iter)=0;
2941protected:
2942    CFlowTableStats  m_stats;
2943};
2944
2945
2946
2947typedef CFlow * flow_ptr;
2948typedef std::map<CFlowKey, flow_ptr, std::less<CFlowKey> > flow_map_t;
2949typedef flow_map_t::iterator flow_map_iter_t;
2950
2951
2952class CFlowTableMap  : public CFlowTableManagerBase {
2953public:
2954    virtual bool Create(int max_size);
2955    virtual void Delete();
2956    virtual void remove(const CFlowKey & key );
2957
2958protected:
2959    virtual CFlow * lookup(const CFlowKey & key );
2960    virtual CFlow * add(const CFlowKey & key );
2961    virtual void remove_all(void);
2962    uint64_t count(void);
2963private:
2964    flow_map_t m_map;
2965};
2966
2967class CFlowInfo {
2968public:
2969    uint32_t client_ip;
2970    uint32_t server_ip;
2971    uint32_t client_port;
2972    uint32_t server_port;
2973    bool     is_init_ip_dir;
2974    bool     is_init_port_dir;
2975
2976    bool     replace_server_port;
2977    CMiniVMCmdBase ** vm_program;/* pointer to vm program */
2978};
2979
2980class CFlowPktInfo {
2981public:
2982    bool Create(CPacketIndication  * pkt_ind);
2983    void Delete();
2984    void Dump(FILE *fd);
2985    inline void replace_tuple(CGenNode * node);
2986
2987    /* generate a new packet */
2988    inline rte_mbuf_t * generate_new_mbuf(CGenNode * node);
2989    inline rte_mbuf_t * do_generate_new_mbuf(CGenNode * node);
2990    inline rte_mbuf_t * do_generate_new_mbuf_big(CGenNode * node);
2991
2992    /* new packet with rx check info in IP option */
2993    void do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
2994                                 CGenNode * node,
2995                                 bool single_port);
2996
2997    inline rte_mbuf_t * do_generate_new_mbuf_ex(CGenNode * node,CFlowInfo * flow_info);
2998    inline rte_mbuf_t * do_generate_new_mbuf_ex_big(CGenNode * node,CFlowInfo * flow_info);
2999    inline rte_mbuf_t * do_generate_new_mbuf_ex_vm(CGenNode * node,
3000                                    CFlowInfo * flow_info, int16_t * s_size);
3001
3002public:
3003    /* push the number of bytes into the packets and make more room
3004      should be used by NAT feature that should have ipv4 option in the first packet
3005      this function should not be called in runtime, only when template is loaded due to it heavey cost of operation ( malloc/free memory )
3006    */
3007    char * push_ipv4_option_offline(uint8_t bytes);
3008    char * push_ipv6_option_offline(uint8_t bytes);
3009
3010
3011
3012    /**
3013     * mark this packet as learn packet
3014     * should
3015     * 1. push ipv4 option ( 8 bytes)
3016     * 2. mark the packet as learn
3017     * 3. update the option pointer
3018     */
3019    void   mark_as_learn();
3020
3021private:
3022    inline void append_big_mbuf(rte_mbuf_t * m,
3023                                              CGenNode * node);
3024
3025    inline void update_pkt_info(char *p,
3026                                       CGenNode * node);
3027    inline void update_pkt_info2(char *p,
3028                                 CFlowInfo * flow_info,
3029                                 int update_len,
3030                                 CGenNode * node
3031                                 );
3032
3033    void alloc_const_mbuf();
3034
3035    void free_const_mbuf();
3036
3037    rte_mbuf_t    *  get_big_mbuf(socket_id_t socket_id){
3038        return (m_big_mbuf[socket_id]);
3039    }
3040
3041
3042public:
3043    CPacketIndication   m_pkt_indication;
3044    CCapPktRaw        * m_packet;
3045    rte_mbuf_t        * m_big_mbuf[MAX_SOCKETS_SUPPORTED]; /* allocate big mbug per socket */
3046};
3047
3048
3049inline void CFlowPktInfo::replace_tuple(CGenNode * node){
3050    update_pkt_info(m_packet->raw,node);
3051}
3052
3053inline void CFlowPktInfo::update_pkt_info2(char *p,
3054                                           CFlowInfo * flow_info,
3055                                           int update_len ,
3056                                           CGenNode * node
3057                                           ){
3058    IPHeader       * ipv4=
3059        (IPHeader       *)(p + m_pkt_indication.getFastIpOffsetFast());
3060
3061    EthernetHeader * et  =
3062        (EthernetHeader * )(p + m_pkt_indication.getFastEtherOffset());
3063
3064    (void)et;
3065
3066    if ( unlikely (m_pkt_indication.is_ipv6())) {
3067        IPv6Header *ipv6= (IPv6Header *)ipv4;
3068
3069        if ( update_len ){
3070            ipv6->setPayloadLen(ipv6->getPayloadLen() + update_len);
3071        }
3072
3073        if ( flow_info->is_init_ip_dir  ) {
3074            ipv6->updateLSBIpv6Src(flow_info->client_ip);
3075            ipv6->updateLSBIpv6Dst(flow_info->server_ip);
3076        }else{
3077            ipv6->updateLSBIpv6Src(flow_info->server_ip);
3078            ipv6->updateLSBIpv6Dst(flow_info->client_ip);
3079        }
3080
3081    }else{
3082        if ( update_len ){
3083            ipv4->setTotalLength((ipv4->getTotalLength() + update_len));
3084        }
3085
3086        if ( flow_info->is_init_ip_dir  ) {
3087            ipv4->setSourceIp(flow_info->client_ip);
3088            ipv4->setDestIp(flow_info->server_ip);
3089        }else{
3090            ipv4->setSourceIp(flow_info->server_ip);
3091            ipv4->setDestIp(flow_info->client_ip);
3092        }
3093        ipv4->updateCheckSum();
3094    }
3095
3096
3097
3098    /* replace port base on TCP/UDP */
3099    if ( m_pkt_indication.m_desc.IsTcp() ) {
3100        TCPHeader * m_tcp = (TCPHeader *)(p +m_pkt_indication.getFastTcpOffset());
3101        BP_ASSERT(m_tcp);
3102        /* replace port */
3103        if ( flow_info->is_init_port_dir  ) {
3104            m_tcp->setSourcePort(flow_info->client_port);
3105            if ( flow_info->replace_server_port ){
3106                m_tcp->setDestPort(flow_info->server_port);
3107            }
3108        }else{
3109            m_tcp->setDestPort(flow_info->client_port);
3110            if ( flow_info->replace_server_port ){
3111                m_tcp->setSourcePort(flow_info->server_port);
3112            }
3113        }
3114
3115    }else {
3116        if ( m_pkt_indication.m_desc.IsUdp() ){
3117            UDPHeader * m_udp =(UDPHeader *)(p +m_pkt_indication.getFastTcpOffset() );
3118            BP_ASSERT(m_udp);
3119            m_udp->setLength(m_udp->getLength() + update_len);
3120            m_udp->setChecksum(0);
3121            if ( flow_info->is_init_port_dir  ) {
3122                m_udp->setSourcePort(flow_info->client_port);
3123                if ( flow_info->replace_server_port ){
3124                    m_udp->setDestPort(flow_info->server_port);
3125                }
3126            }else{
3127                m_udp->setDestPort(flow_info->client_port);
3128                if ( flow_info->replace_server_port ){
3129                    m_udp->setSourcePort(flow_info->server_port);
3130                }
3131            }
3132        }else{
3133            BP_ASSERT(0);
3134        }
3135    }
3136}
3137
3138
3139inline void CFlowPktInfo::update_pkt_info(char *p,
3140                                   CGenNode * node){
3141
3142    IPHeader       * ipv4=
3143        (IPHeader       *)(p + m_pkt_indication.getFastIpOffsetFast());
3144
3145    uint16_t src_port =   node->m_src_port;
3146    uint32_t tcp_seq_diff_client = 0;
3147    uint32_t tcp_seq_diff_server = 0;
3148
3149    pkt_dir_t ip_dir = node->cur_pkt_ip_addr_dir();
3150    pkt_dir_t port_dir = node->cur_pkt_port_addr_dir();
3151
3152
3153    if ( unlikely (m_pkt_indication.is_ipv6())) {
3154
3155        // Update the IPv6 address
3156        IPv6Header *ipv6= (IPv6Header *)ipv4;
3157
3158        if ( ip_dir ==  CLIENT_SIDE  ) {
3159            ipv6->updateLSBIpv6Src(node->m_src_ip);
3160            ipv6->updateLSBIpv6Dst(node->m_dest_ip);
3161        }else{
3162            ipv6->updateLSBIpv6Src(node->m_dest_ip);
3163            ipv6->updateLSBIpv6Dst(node->m_src_ip);
3164        }
3165    }else{
3166
3167        if ( unlikely ( CGlobalInfo::is_learn_mode()  ) ){
3168            if (m_pkt_indication.m_desc.IsLearn()) {
3169                /* might be done twice */
3170#ifdef NAT_TRACE_
3171                printf(" %.3f : DP :  learn packet !\n",now_sec());
3172#endif
3173                /* first ipv4 option add the info in case of learn packet, usualy only the first packet */
3174                if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION)) {
3175                    CNatOption *lpNat =(CNatOption *)ipv4->getOption();
3176                    lpNat->set_fid(node->get_short_fid());
3177                    lpNat->set_thread_id(node->get_thread_id());
3178                } else {
3179                    if (ipv4->getProtocol() == IPPROTO_TCP) {
3180                        TCPHeader *tcp = (TCPHeader *)(((uint8_t *)ipv4) + ipv4->getHeaderLength());
3181                        // Put NAT info in first TCP SYN
3182                        if (tcp->getSynFlag()) {
3183                            tcp->setAckNumber(CNatRxManager::calc_tcp_ack_val(node->get_short_fid(), node->get_thread_id()));
3184                        }
3185#ifdef NAT_TRACE_
3186                        printf(" %.3f : flow_id: %x thread_id %x TCP ack %x seq %x\n"
3187                               ,now_sec(), node->get_short_fid(), node->get_thread_id(), tcp->getAckNumber()
3188                               , tcp->getSeqNumber());
3189#endif
3190                    } else {
3191                        // If protocol is not TCP, put NAT info in IP_ID
3192                        ipv4->setId(CNatRxManager::calc_ip_id_val(node->get_short_fid(), node->get_thread_id()));
3193                    }
3194                }
3195            }
3196            /* in all cases update the ip using the outside ip */
3197
3198            if ( m_pkt_indication.m_desc.IsInitSide()  ) {
3199#ifdef NAT_TRACE_
3200                if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
3201                    printf(" %.3f : DP : i %x:%x -> %x  flow_id: %lx\n",now_sec(), node->m_src_ip
3202                           , node->m_src_port, node->m_dest_ip, node->m_flow_id);
3203                }
3204#endif
3205
3206                tcp_seq_diff_server = node->get_nat_tcp_seq_diff_server();
3207                ipv4->updateIpSrc(node->m_src_ip);
3208                ipv4->updateIpDst(node->m_dest_ip);
3209            } else {
3210#ifdef NAT_TRACE_
3211                if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
3212                    printf(" %.3f : r %x   -> %x:%x  flow_id: %lx \n", now_sec(), node->m_dest_ip
3213                           , node->m_src_ip, node->m_src_port, node->m_flow_id);
3214                }
3215#endif
3216                src_port = node->get_nat_ipv4_port();
3217                tcp_seq_diff_client = node->get_nat_tcp_seq_diff_client();
3218                ipv4->updateIpSrc(node->m_dest_ip);
3219                ipv4->updateIpDst(node->get_nat_ipv4_addr());
3220            }
3221
3222#ifdef NAT_TRACE_
3223            if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
3224                if ( m_pkt_indication.m_desc.IsInitSide() ==false ){
3225                    printf(" %.3f : pkt ==> %x %x:%x \n",now_sec(),node->get_nat_ipv4_addr(),
3226                           node->get_nat_ipv4_port(),node->m_src_port);
3227                }else{
3228                    printf(" %.3f : pkt ==> init pkt sent \n",now_sec());
3229                }
3230            }
3231#endif
3232
3233
3234        }else{
3235            if ( ip_dir ==  CLIENT_SIDE  ) {
3236#ifdef NAT_TRACE_
3237                if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
3238                    printf(" %.3f : i %x:%x -> %x \n",now_sec(),node->m_src_ip,node->m_src_port,node->m_dest_ip);
3239                }
3240#endif
3241                ipv4->updateIpSrc(node->m_src_ip);
3242                ipv4->updateIpDst(node->m_dest_ip);
3243            }else{
3244#ifdef NAT_TRACE_
3245                if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
3246                    printf(" %.3f : r %x   -> %x:%x  \n",now_sec(),node->m_dest_ip,node->m_src_ip,node->m_src_port);
3247                }
3248#endif
3249                ipv4->updateIpSrc(node->m_dest_ip);
3250                ipv4->updateIpDst(node->m_src_ip);
3251            }
3252        }
3253
3254#ifdef RTE_DPDK
3255        if (CGlobalInfo::m_options.preview.getChecksumOffloadEnable()) {
3256            ipv4->myChecksum = 0;
3257        } else {
3258            ipv4->updateCheckSum();
3259        }
3260#else
3261        ipv4->updateCheckSum();
3262#endif
3263    }
3264
3265
3266    /* replace port base on TCP/UDP */
3267    if ( m_pkt_indication.m_desc.IsTcp() ) {
3268        TCPHeader * m_tcp = (TCPHeader *)(p +m_pkt_indication.getFastTcpOffset());
3269        BP_ASSERT(m_tcp);
3270        /* replace port */
3271        if ( port_dir ==  CLIENT_SIDE ) {
3272            m_tcp->setSourcePort(src_port);
3273            m_tcp->setAckNumber(m_tcp->getAckNumber() + tcp_seq_diff_server);
3274        }else{
3275            m_tcp->setDestPort(src_port);
3276            m_tcp->setAckNumber(m_tcp->getAckNumber() + tcp_seq_diff_client);
3277        }
3278
3279#ifdef RTE_DPDK
3280        if (CGlobalInfo::m_options.preview.getChecksumOffloadEnable()) {
3281            /* set pseudo-header checksum */
3282            m_tcp->setChecksum(PKT_NTOHS(rte_ipv4_phdr_cksum((struct ipv4_hdr *)ipv4->getPointer(),
3283                                                             PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM)));
3284        }
3285#endif
3286    }else {
3287        if ( m_pkt_indication.m_desc.IsUdp() ){
3288            UDPHeader * m_udp =(UDPHeader *)(p +m_pkt_indication.getFastTcpOffset() );
3289            BP_ASSERT(m_udp);
3290
3291            if ( port_dir ==  CLIENT_SIDE ) {
3292                m_udp->setSourcePort(src_port);
3293            }else{
3294                m_udp->setDestPort(src_port);
3295            }
3296
3297#ifdef RTE_DPDK
3298        if (CGlobalInfo::m_options.preview.getChecksumOffloadEnable()) {
3299            /* set pseudo-header checksum */
3300            m_udp->setChecksum(PKT_NTOHS(rte_ipv4_phdr_cksum((struct ipv4_hdr *) ipv4->getPointer(),
3301                                                             PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_UDP_CKSUM)));
3302        } else {
3303            m_udp->setChecksum(0);
3304        }
3305#else
3306        m_udp->setChecksum(0);
3307#endif
3308        }else{
3309#ifdef _DEBUG
3310            if (!m_pkt_indication.m_desc.IsIcmp()) {
3311               BP_ASSERT(0);
3312            }
3313#endif
3314        }
3315    }
3316}
3317
3318
3319inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_ex(CGenNode * node,
3320                                                          CFlowInfo * flow_info){
3321    rte_mbuf_t        * m;
3322    /* alloc small packet buffer*/
3323    m =  CGlobalInfo::pktmbuf_alloc_small(node->get_socket_id());
3324    assert(m);
3325    uint16_t len= ( m_packet->pkt_len > FIRST_PKT_SIZE) ?FIRST_PKT_SIZE:m_packet->pkt_len;
3326    /* append*/
3327    char *p=rte_pktmbuf_append(m, len);
3328
3329    BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ;
3330
3331    memcpy(p,m_packet->raw,len);
3332
3333    update_pkt_info2(p,flow_info,0,node);
3334
3335    append_big_mbuf(m,node);
3336
3337    return(m);
3338}
3339
3340
3341inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_ex_big(CGenNode * node,
3342                                                          CFlowInfo * flow_info){
3343    rte_mbuf_t        * m;
3344    uint16_t len =  m_packet->pkt_len;
3345
3346    /* alloc big buffer to update it*/
3347    m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), len);
3348    assert(m);
3349
3350    /* append*/
3351    char *p=rte_pktmbuf_append(m, len);
3352
3353    BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ;
3354
3355    memcpy(p,m_packet->raw,len);
3356
3357    update_pkt_info2(p,flow_info,0,node);
3358
3359    return(m);
3360}
3361
3362
3363inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_ex_vm(CGenNode * node,
3364                                              CFlowInfo * flow_info, int16_t * s_size){
3365    rte_mbuf_t        * m;
3366
3367    /* sanity check we need to have payload */
3368    if ( unlikely( m_pkt_indication.m_payload_len == 0) ){
3369        printf(" ERROR nothing to do \n");
3370        return (do_generate_new_mbuf_ex(node,flow_info));
3371    }
3372
3373    CMiniVMCmdBase ** cmds=flow_info->vm_program;
3374    BP_ASSERT(cmds);
3375
3376        /* packet is going to be changed update len with what we expect ( written in first command ) */
3377    uint16_t len =  m_packet->pkt_len + cmds[0]->m_add_pkt_len;
3378
3379    /* alloc big buffer to update it*/
3380    m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), len);
3381    assert(m);
3382
3383    /* append the additional bytes requested and update later */
3384    char *p=rte_pktmbuf_append(m, len);
3385
3386    BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ;
3387
3388    /* copy the headers until the payload  */
3389    memcpy(p, m_packet->raw, m_pkt_indication.getPayloadOffset() );
3390    CMiniVM vm;
3391    vm.m_pkt_info = this;
3392    vm.m_pyload_mbuf_ptr = p+m_pkt_indication.getPayloadOffset();
3393    vm.mini_vm_run(cmds);
3394
3395    /* need to update the mbuf size here .., this is not must but needed for accuracy  */
3396    uint16_t buf_adjust = len - vm.m_new_pkt_size;
3397    int rc = rte_pktmbuf_trim(m, buf_adjust);
3398    (void)rc;
3399
3400    /* update IP length , and TCP checksum , we can accelerate this using hardware ! */
3401    uint16_t pkt_adjust = vm.m_new_pkt_size - m_packet->pkt_len;
3402    update_pkt_info2(p,flow_info,pkt_adjust,node);
3403
3404    /* return change in packet size due to packet tranforms */
3405    *s_size = vm.m_new_pkt_size - m_packet->pkt_len;
3406
3407    //printf(" new length : actual %d , update:%d \n",m_packet->pkt_len,m_packet->pkt_len + vm.m_new_pkt_size);
3408    return(m);
3409}
3410
3411
3412inline void CFlowPktInfo::append_big_mbuf(rte_mbuf_t * m,
3413                                          CGenNode * node){
3414
3415    rte_mbuf_t * mbig= get_big_mbuf(node->get_socket_id());
3416
3417    if (  mbig == NULL) {
3418        return ;
3419    }
3420
3421    utl_rte_pktmbuf_add_after(m,mbig);
3422}
3423
3424
3425inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf(CGenNode * node){
3426    rte_mbuf_t        * m;
3427    /* alloc small packet buffer*/
3428    m = CGlobalInfo::pktmbuf_alloc_small(node->get_socket_id());
3429    assert(m);
3430    uint16_t len= ( m_packet->pkt_len > FIRST_PKT_SIZE) ?FIRST_PKT_SIZE:m_packet->pkt_len;
3431    /* append*/
3432    char *p=rte_pktmbuf_append(m, len);
3433
3434    BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ;
3435
3436    memcpy(p,m_packet->raw,len);
3437
3438#ifdef RTE_DPDK
3439    if (CGlobalInfo::m_options.preview.getChecksumOffloadEnable()) {
3440        if (m_pkt_indication.m_desc.IsTcp()) {
3441            m->l2_len = 14;
3442            m->l3_len = 20;
3443            m->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM;
3444        } else {
3445            if (m_pkt_indication.m_desc.IsUdp()) {
3446                m->l2_len = 14;
3447                m->l3_len = 20;
3448                m->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_UDP_CKSUM;
3449            }
3450        }
3451    }
3452#endif
3453
3454    update_pkt_info(p,node);
3455
3456    append_big_mbuf(m,node);
3457
3458    return m;
3459}
3460
3461
3462inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_big(CGenNode * node){
3463    rte_mbuf_t        * m;
3464    uint16_t len =  m_packet->pkt_len;
3465
3466    /* alloc big buffer to update it*/
3467    m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(),  len);
3468    assert(m);
3469
3470    /* append*/
3471    char *p=rte_pktmbuf_append(m, len);
3472
3473    BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ;
3474
3475    memcpy(p,m_packet->raw,len);
3476
3477    update_pkt_info(p,node);
3478
3479    return(m);
3480}
3481
3482
3483inline rte_mbuf_t * CFlowPktInfo::generate_new_mbuf(CGenNode * node){
3484
3485    if ( m_pkt_indication.m_desc.IsPluginEnable() ) {
3486        return ( on_node_generate_mbuf( node->get_plugin_id(),node,this) );
3487    }
3488    return  (do_generate_new_mbuf(node));
3489}
3490
3491
3492
3493typedef CFlowPktInfo * flow_pkt_info_t;
3494
3495class CCCapFileMemoryUsage {
3496
3497public:
3498
3499  enum { SIZE_MIN = 64,
3500         SIZE_64  = 64,
3501        SIZE_128  = 128,
3502        SIZE_256   = 256,
3503        SIZE_512   = 512,
3504        SIZE_1024  = 1024,
3505        SIZE_2048  = 2048,
3506        SIZE_4096  = 4096,
3507        SIZE_8192  = 8192,
3508        SIZE_16384  = 16384,
3509
3510        MASK_SIZE =9
3511      };
3512
3513  void clear(){
3514      int i;
3515      for (i=0; i<CCCapFileMemoryUsage::MASK_SIZE; i++) {
3516          m_buf[i] = 0;
3517      }
3518      m_total_bytes=0;
3519  }
3520
3521  void add_size(uint32_t size){
3522      m_total_bytes+=size;
3523      int c_size=CCCapFileMemoryUsage::SIZE_MIN;
3524      int i;
3525      for (i=0; i<CCCapFileMemoryUsage::MASK_SIZE; i++) {
3526          if (size<c_size) {
3527              m_buf[i]+=1;
3528              return;
3529          }
3530          c_size = c_size*2;
3531      }
3532      printf("ERROR pkt size bigger than %d is not supported !\n",CCCapFileMemoryUsage::SIZE_2048);
3533      exit(1);
3534  }
3535  void dump(FILE *fd);
3536
3537  void Add(const CCCapFileMemoryUsage & obj);
3538
3539public:
3540    uint32_t m_buf[MASK_SIZE];
3541    uint64_t m_total_bytes;
3542};
3543
3544
3545
3546class CCapFileFlowInfo {
3547public:
3548    const int LEARN_MODE_MIN_IPG = 10; // msec
3549
3550    enum load_cap_file_err {
3551    kOK = 0,
3552    kFileNotExist,
3553    kNegTimestamp,
3554    kNoSyn,
3555    kTCPOffsetTooBig,
3556    kNoTCPFromServer,
3557    kNoTCPSynAck,
3558    kTCPLearnModeBadFlow,
3559    kPktNotSupp,
3560    kPktProcessFail,
3561    kCapFileErr,
3562    kPlugInWithLearn,
3563    kIPOptionNotAllowed,
3564    kTCPIpgTooLow
3565    };
3566
3567    bool Create();
3568    void Delete();
3569    uint64_t Size(void){
3570        return (m_flow_pkts.size());
3571    }
3572    inline CFlowPktInfo * GetPacket(uint32_t index);
3573    void Append(CPacketIndication * pkt_indication);
3574    void RemoveAll();
3575    void dump_pkt_sizes(void);
3576    enum load_cap_file_err load_cap_file(std::string cap_file, uint16_t _id, uint8_t plugin_id);
3577
3578    /* update flow info */
3579    void update_info(CFlowYamlInfo *  info);
3580
3581    enum CCapFileFlowInfo::load_cap_file_err is_valid_template_load_time();
3582
3583    void save_to_erf(std::string cap_file_name,int pcap);
3584
3585    void generate_flow(CTupleTemplateGeneratorSmart   * tuple_gen,
3586                              CNodeGenerator * gen,
3587                              dsec_t time,
3588                              uint64_t flow_id,
3589                              CFlowYamlInfo *  template_info,
3590                              CGenNode *     node);
3591
3592    inline uint64_t get_total_bytes(){
3593        return (m_total_bytes);
3594    }
3595    inline uint64_t get_total_flows(){
3596        return (m_total_flows);
3597    }
3598
3599    inline uint64_t get_total_errors(){
3600        return (m_total_errors);
3601    }
3602
3603    // return the cap file length in sec
3604    double get_cap_file_length_sec();
3605
3606    void get_total_memory(CCCapFileMemoryUsage & memory);
3607
3608public:
3609    void update_min_ipg(dsec_t min_ipg, dsec_t override_ipg);
3610    void update_ipg_by_factor(double factor,CFlowYamlInfo *  flow_info);
3611    void update_pcap_mode();
3612    void Dump(FILE *fd);
3613
3614private:
3615    std::vector<flow_pkt_info_t> m_flow_pkts;
3616    uint64_t                     m_total_bytes;
3617    uint64_t                     m_total_flows;
3618    uint64_t                     m_total_errors;
3619};
3620
3621
3622
3623inline CFlowPktInfo * CCapFileFlowInfo::GetPacket(uint32_t index){
3624    BP_ASSERT(index<m_flow_pkts.size());
3625    return (m_flow_pkts[index]);
3626}
3627
3628
3629
3630
3631struct CFlowsYamlInfo {
3632public:
3633    double          m_duration_sec;    //duration in sec for the cap file
3634
3635// IPv4 addressing
3636
3637// IPv6 addressing
3638    std::vector     <uint16_t> m_src_ipv6;
3639    std::vector     <uint16_t> m_dst_ipv6;
3640    bool             m_ipv6_set;
3641
3642// new section
3643    bool            m_cap_mode;
3644    bool            m_cap_mode_set;
3645
3646    double          m_cap_ipg_min;
3647    bool            m_cap_ipg_min_set;
3648
3649    double          m_cap_overide_ipg;
3650    bool            m_cap_overide_ipg_set;
3651
3652    uint32_t        m_wlength;
3653    bool            m_wlength_set;
3654
3655    bool            m_one_app_server;
3656    bool            m_one_app_server_was_set;
3657    bool            m_mac_replace_by_ip;
3658
3659    CVlanYamlInfo   m_vlan_info;
3660    CTupleGenYamlInfo m_tuple_gen;
3661    bool              m_tuple_gen_was_set;
3662
3663
3664    std::vector     <uint8_t> m_mac_base;
3665
3666    std::vector     <CFlowYamlInfo> m_vec;
3667
3668    bool            m_is_plugin_configured; /* any plugin  is configured */
3669
3670    CTimerWheelYamlInfo         m_tw;
3671
3672public:
3673    void Dump(FILE *fd);
3674    int load_from_yaml_file(std::string file_name);
3675    bool verify_correctness(uint32_t num_threads) ;
3676    bool is_any_plugin_configured(){
3677        return ( m_is_plugin_configured);
3678    }
3679};
3680
3681
3682
3683
3684class CFlowStats {
3685public:
3686    CFlowStats(){
3687        Clear();
3688    }
3689    uint16_t    m_id;
3690    std::string m_name;
3691    double m_pkt;
3692    double m_bytes;
3693    double duration_sec;
3694    double m_cps;
3695    double m_mb_sec;
3696    double m_mB_sec;
3697    double m_c_flows;
3698    double m_pps ;
3699    double m_total_Mbytes ;
3700    uint64_t m_errors ;
3701    uint64_t m_flows  ;
3702    CCCapFileMemoryUsage m_memory;
3703
3704    /* normalized CPS by the number of flows */
3705    double get_normal_cps(){
3706        return ( m_cps*(double)m_flows  );
3707    }
3708public:
3709    void Clear();
3710    void Add(const CFlowStats & obj);
3711
3712public:
3713    static void DumpHeader(FILE *fd);
3714    void Dump(FILE *fd);
3715};
3716
3717
3718class CFlowGeneratorRecPerThread {
3719
3720public:
3721    bool Create(CTupleGeneratorSmart  * global_gen,
3722                CFlowYamlInfo *         info,
3723                CFlowsYamlInfo *        yaml_flow_info,
3724                CCapFileFlowInfo *      flow_info,
3725                uint16_t _id,
3726                uint32_t thread_id );
3727    void Delete();
3728public:
3729    void Dump(FILE *fd);
3730    inline void generate_flow(CNodeGenerator * gen,
3731                              dsec_t time,
3732                              uint64_t flow_id,
3733                              CGenNode * node);
3734    void getFlowStats(CFlowStats * stats);
3735
3736public:
3737    CTupleTemplateGeneratorSmart  tuple_gen;
3738
3739    CCapFileFlowInfo *      m_flow_info;
3740    CFlowYamlInfo *         m_info;
3741    CFlowsYamlInfo *        m_flows_info;
3742    CPolicer                m_policer;
3743    uint16_t                m_id ;
3744    uint32_t                m_thread_id;
3745    bool                    m_tuple_gen_was_set;
3746} __rte_cache_aligned;
3747
3748
3749
3750
3751class CFlowGeneratorRec {
3752
3753public:
3754    bool Create(CFlowYamlInfo * info,
3755                CFlowsYamlInfo * flow_info,
3756                uint16_t _id);
3757    void Delete();
3758public:
3759
3760    void Dump(FILE *fd);
3761    void getFlowStats(CFlowStats * stats);
3762    void updateIpg(double factor);
3763
3764public:
3765    CCapFileFlowInfo m_flow_info;
3766    CFlowYamlInfo *  m_info;
3767    CFlowsYamlInfo * m_flows_info;
3768    CPolicer         m_policer;
3769    uint16_t         m_id;
3770private:
3771    void fixup_ipg_if_needed();
3772};
3773
3774class CPPSMeasure {
3775public:
3776    CPPSMeasure(){
3777        reset();
3778    }
3779    //reset
3780    void reset(void){
3781        m_start=false;
3782        m_last_time_msec=0;
3783        m_last_pkts=0;
3784        m_last_result=0.0;
3785    }
3786    //add packet size
3787    float add(uint64_t pkts);
3788
3789private:
3790    float calc_pps(uint32_t dtime_msec,
3791                                 uint32_t pkts){
3792        float rate=( (  (float)pkts*(float)os_get_time_freq())/((float)dtime_msec) );
3793        return (rate);
3794
3795    }
3796
3797public:
3798   bool      m_start;
3799   uint32_t  m_last_time_msec;
3800   uint64_t  m_last_pkts;
3801   float     m_last_result;
3802};
3803
3804
3805
3806class CBwMeasure {
3807public:
3808    CBwMeasure();
3809    //reset
3810    void reset(void);
3811    //add packet size
3812    double add(uint64_t size);
3813
3814private:
3815    double calc_MBsec(uint32_t dtime_msec,
3816                     uint64_t dbytes);
3817
3818public:
3819   bool      m_start;
3820   uint32_t  m_last_time_msec;
3821   uint64_t  m_last_bytes;
3822   double     m_last_result;
3823};
3824
3825
3826class CFlowGenList;
3827
3828typedef uint32_t flow_id_t;
3829
3830
3831class CTcpSeq {
3832public:
3833    CTcpSeq (){
3834        client_seq_delta = 0;
3835        server_seq_delta = 0;
3836        server_seq_init=false;
3837    };
3838    void update(uint8_t *p, CFlowPktInfo *pkt_info, int16_t s_size);
3839private:
3840    uint32_t       client_seq_delta;  /* Delta to TCP seq number for client */
3841    uint32_t       server_seq_delta;  /* Delta to TCP seq number for server */
3842    bool           server_seq_init;  /* TCP seq been init for server? */
3843};
3844
3845
3846
3847
3848/////////////////////////////////////////////////////////////////////////////////
3849/* per thread info  */
3850class CFlowGenListPerThread {
3851
3852public:
3853
3854
3855    friend class CNodeGenerator;
3856    friend class CPluginCallbackSimple;
3857    friend class CCapFileFlowInfo;
3858
3859    typedef  CGenericMap<flow_id_t,CGenNode> flow_id_node_t;
3860
3861    bool Create(uint32_t           thread_id,
3862                uint32_t           core_id,
3863                CFlowGenList  *    flow_list,
3864                uint32_t           max_threads);
3865    void Delete();
3866
3867    void set_terminate_mode(bool is_terminate){
3868        m_terminated_by_master =is_terminate;
3869    }
3870    bool is_terminated_by_master(){
3871        return (m_terminated_by_master);
3872    }
3873
3874    void set_vif(CVirtualIF * v_if){
3875        m_node_gen.set_vif(v_if);
3876    }
3877
3878    void flush_tx_queue() {
3879        m_node_gen.m_v_if->flush_tx_queue();
3880    }
3881
3882    void tickle() {
3883        m_monitor.tickle();
3884    }
3885
3886    template<bool TEARDOWN>
3887    inline void on_flow_tick(CGenNode *node);
3888
3889
3890    /* return the dual port ID this thread is attached to in 4 ports configuration
3891       there are 2 dual-ports
3892
3893      thread 0 - dual 0
3894      thread 1 - dual 1
3895
3896      thread 2 - dual 0
3897      thread 3 - dual 1
3898
3899     */
3900    uint32_t getDualPortId();
3901public :
3902    double get_total_kcps();
3903    double get_total_kcps(uint8_t pool_idx, bool is_client);
3904    double get_delta_flow_is_sec();
3905    double get_longest_flow();
3906    double get_longest_flow(uint8_t pool_idx, bool is_client);
3907    void inc_current_template(void);
3908    int generate_flows_roundrobin(bool *done);
3909    int reschedule_flow(CGenNode *node);
3910
3911
3912    inline CGenNode * create_node(void);
3913
3914    inline CGenNodeStateless * create_node_sl(void){
3915        return ((CGenNodeStateless*)create_node() );
3916    }
3917
3918    inline CGenNodePCAP * allocate_pcap_node(void) {
3919        return ((CGenNodePCAP*)create_node());
3920    }
3921
3922    inline void free_node(CGenNode *p);
3923    inline void free_last_flow_node(CGenNode *p);
3924
3925
3926
3927public:
3928    void Clean();
3929    void start_generate_stateful(std::string erf_file_name,CPreviewMode &preview);
3930    void start_stateless_daemon(CPreviewMode &preview);
3931
3932    void start_stateless_daemon_simulation();
3933
3934    /* open a file for simulation */
3935    void start_stateless_simulation_file(std::string erf_file_name,CPreviewMode &preview, uint64_t limit = 0);
3936    /* close a file for simulation */
3937    void stop_stateless_simulation_file();
3938
3939    /* return true if we need to shedule next_stream,  */
3940    bool  set_stateless_next_node( CGenNodeStateless * cur_node,
3941                                   CGenNodeStateless * next_node);
3942
3943    void stop_stateless_traffic(uint8_t port_id) {
3944        m_stateless_dp_info.stop_traffic(port_id, false, 0);
3945    }
3946
3947    /**
3948     * return true if a core currently has some pending CP
3949     * messages
3950     */
3951    bool are_any_pending_cp_messages() {
3952        if (get_is_stateless()) {
3953            return m_stateless_dp_info.are_any_pending_cp_messages();
3954        } else {
3955            /* for stateful this is always false */
3956            return false;
3957        }
3958    }
3959
3960    /**
3961     * a core provides services for two interfaces
3962     * it can either be idle, active for one port
3963     * or active for both
3964     */
3965    bool is_port_active(uint8_t port_id) {
3966        /* for stateful (batch) core is always active,
3967           for stateless relay the query to the next level
3968         */
3969        if (get_is_stateless()) {
3970            return m_stateless_dp_info.is_port_active(port_id);
3971        } else {
3972            return true;
3973        }
3974    }
3975
3976
3977    /**
3978     * returns the two ports associated with this core
3979     *
3980     */
3981    void get_port_ids(uint8_t &p1, uint8_t &p2) {
3982        p1 = 2 * getDualPortId();
3983        p2 = p1 + 1;
3984    }
3985
3986    void Dump(FILE *fd);
3987    void DumpCsv(FILE *fd);
3988    void DumpStats(FILE *fd);
3989    void Update(void){
3990        m_cpu_cp_u.Update();
3991    }
3992    double getCpuUtil(void){
3993        return ( m_cpu_cp_u.GetVal());
3994    }
3995
3996
3997    bool check_msgs();
3998
3999private:
4000
4001    FORCE_NO_INLINE void   no_memory_error();
4002
4003    bool check_msgs_from_rx();
4004
4005    void handle_nat_msg(CGenNodeNatInfo * msg);
4006    void handle_latency_pkt_msg(CGenNodeLatencyPktInfo * msg);
4007
4008    void terminate_nat_flows(CGenNode *node);
4009
4010
4011    void init_from_global();
4012    void defer_client_port_free(CGenNode *p);
4013    void defer_client_port_free(bool is_tcp,uint32_t c_ip,uint16_t port,
4014                                uint8_t pool_idx, CTupleGeneratorSmart*gen);
4015
4016
4017    FORCE_NO_INLINE void   handler_defer_job(CGenNode *p);
4018    FORCE_NO_INLINE void   handler_defer_job_flush(void);
4019
4020
4021    inline CGenNodeDeferPort     * get_tcp_defer(void){
4022        if (m_tcp_dpc==0) {
4023            m_tcp_dpc =(CGenNodeDeferPort     *)create_node();
4024            m_tcp_dpc->init();
4025        }
4026        return (m_tcp_dpc);
4027    }
4028
4029    inline CGenNodeDeferPort     * get_udp_defer(void){
4030        if (m_udp_dpc==0) {
4031            m_udp_dpc =(CGenNodeDeferPort     *)create_node();
4032            m_udp_dpc->init();
4033        }
4034        return (m_udp_dpc);
4035    }
4036
4037private:
4038     FORCE_NO_INLINE void associate(uint32_t fid,CGenNode *     node ){
4039         assert(m_flow_id_to_node_lookup.lookup(fid)==0);
4040        m_stats.m_nat_lookup_add_flow_id++;
4041        m_flow_id_to_node_lookup.add(fid,node);
4042    }
4043
4044public:
4045    uint32_t                         m_thread_id; /* virtual */
4046    uint32_t                         m_core_id;   /* phsical */
4047
4048    uint32_t                         m_max_threads;
4049    CFlowGenList                *    m_flow_list;
4050    rte_mempool_t *                  m_node_pool;
4051
4052    std::vector<CFlowGeneratorRecPerThread *> m_cap_gen;
4053
4054    CFlowsYamlInfo                   m_yaml_info;
4055
4056    CTupleGeneratorSmart             m_smart_gen;
4057
4058    TrexMonitor                      m_monitor;
4059
4060public:
4061    CNodeGenerator                   m_node_gen;
4062    CNATimerWheel                    m_tw;
4063
4064public:
4065    uint32_t                         m_cur_template;
4066    uint32_t                         m_non_active_nodes; /* the number of non active nodes -> nodes that try to stop somthing */
4067    uint64_t                         m_cur_flow_id;
4068    double                           m_cur_time_sec;
4069    double                           m_stop_time_sec;
4070
4071    CPreviewMode                     m_preview_mode;
4072public:
4073    CFlowGenStats                    m_stats;
4074    CBwMeasure                       m_mb_sec;
4075    CCpuUtlDp                        m_cpu_dp_u;
4076    CCpuUtlCp                        m_cpu_cp_u;
4077
4078private:
4079    CGenNodeDeferPort     *          m_tcp_dpc;
4080    CGenNodeDeferPort     *          m_udp_dpc;
4081
4082    CNodeRing *                      m_ring_from_rx; /* ring rx thread -> dp */
4083    CNodeRing *                      m_ring_to_rx;   /* ring dp -> rx thread */
4084
4085    flow_id_node_t                   m_flow_id_to_node_lookup;
4086
4087    TrexStatelessDpCore              m_stateless_dp_info;
4088    bool                             m_terminated_by_master;
4089
4090private:
4091    uint8_t                 m_cacheline_pad[RTE_CACHE_LINE_SIZE][19]; // improve prefech
4092} __rte_cache_aligned ;
4093
4094inline CGenNode * CFlowGenListPerThread::create_node(void){
4095    CGenNode * res;
4096    if ( unlikely (rte_mempool_sc_get(m_node_pool, (void **)&res) <0) ){
4097        no_memory_error();
4098        return (0);
4099    }
4100    return (res);
4101}
4102
4103
4104
4105inline void CFlowGenListPerThread::free_node(CGenNode *p){
4106    p->free_base();
4107    rte_mempool_sp_put(m_node_pool, p);
4108}
4109
4110inline void CFlowGenListPerThread::free_last_flow_node(CGenNode *p){
4111    m_stats.m_total_close_flows +=p->m_flow_info->get_total_flows();
4112
4113    uint8_t plugin_id =p->get_plugin_id();
4114    if ( plugin_id ) {
4115        /* free memory of the plugin */
4116        on_node_last(plugin_id,p);
4117    }
4118    defer_client_port_free(p);
4119    free_node( p);
4120}
4121
4122
4123class CFlowGenList {
4124
4125public:
4126    bool Create();
4127    void Delete();
4128    void Clean();
4129public:
4130    void generate_p_thread_info(uint32_t num_threads);
4131    void clean_p_thread_info(void);
4132
4133public:
4134
4135    int load_from_yaml(std::string csv_file,uint32_t num_threads);
4136    int load_client_config_file(std::string file_name);
4137    void set_client_config_tuple_gen_info(CTupleGenYamlInfo * tg);
4138    void get_client_cfg_ip_list(std::vector<ClientCfgCompactEntry *> &ret);
4139    void set_client_config_resolved_macs(CManyIPInfo &pretest_result);
4140    void dump_client_config(FILE *fd);
4141
4142public:
4143    void Dump(FILE *fd);
4144    void DumpCsv(FILE *fd);
4145    void DumpPktSize();
4146    void UpdateFast();
4147    double GetCpuUtil();
4148    double GetCpuUtilRaw();
4149
4150public:
4151    /* update ipg in a way for */
4152    int update_active_flows(uint32_t active_flows);
4153    double get_worse_case_active_flows();
4154
4155    double get_total_kcps();
4156    double get_total_pps();
4157    double get_total_tx_bps();
4158    uint32_t get_total_repeat_flows();
4159    double get_delta_flow_is_sec();
4160
4161public:
4162    std::vector<CFlowGeneratorRec *>        m_cap_gen;   /* global info */
4163    CFlowsYamlInfo                          m_yaml_info; /* global yaml*/
4164    std::vector<CFlowGenListPerThread   *>  m_threads_info;
4165    ClientCfgDB                             m_client_config_info;
4166};
4167
4168inline void CFlowGeneratorRecPerThread::generate_flow(CNodeGenerator * gen,
4169                                                      dsec_t time,
4170                                                      uint64_t flow_id,
4171                                                      CGenNode * node){
4172
4173    m_flow_info->generate_flow(&tuple_gen,
4174                               gen,
4175                               time,
4176                               flow_id,
4177                               m_info,
4178                               node);
4179}
4180
4181inline bool CGenNode::is_responder_pkt(){
4182    return ( m_pkt_info->m_pkt_indication.m_desc.IsInitSide() ?false:true );
4183}
4184
4185inline bool CGenNode::is_initiator_pkt(){
4186    return ( m_pkt_info->m_pkt_indication.m_desc.IsInitSide() ?true:false );
4187}
4188
4189
4190
4191inline uint16_t CGenNode::get_template_id(){
4192    return ( m_pkt_info->m_pkt_indication.m_desc.getId()  );
4193}
4194
4195
4196inline bool CGenNode::is_last_in_flow(){
4197    return ( m_pkt_info->m_pkt_indication.m_desc.IsLastPkt());
4198}
4199
4200inline bool CGenNode::is_repeat_flow(){
4201    return ( m_template_info->m_limit_was_set);
4202}
4203
4204
4205inline void CGenNode::update_next_pkt_in_flow_as(void){
4206
4207    m_time     += m_pkt_info->m_pkt_indication.m_cap_ipg;
4208    uint32_t pkt_index   = m_pkt_info->m_pkt_indication.m_packet->pkt_cnt;
4209    pkt_index++;
4210    m_pkt_info = m_flow_info->GetPacket((pkt_index-1));
4211}
4212
4213
4214inline uint32_t CGenNode::update_next_pkt_in_flow_both(void){
4215    m_time     += m_pkt_info->m_pkt_indication.m_cap_ipg;
4216    uint32_t dticks = m_pkt_info->m_pkt_indication.m_ticks;
4217    uint32_t pkt_index   = m_pkt_info->m_pkt_indication.m_packet->pkt_cnt;
4218    pkt_index++;
4219    m_pkt_info = m_flow_info->GetPacket((pkt_index-1));
4220    return (dticks);
4221}
4222
4223
4224inline uint32_t CGenNode::update_next_pkt_in_flow_tw(void){
4225
4226        uint32_t dticks = m_pkt_info->m_pkt_indication.m_ticks;
4227        uint32_t pkt_index   = m_pkt_info->m_pkt_indication.m_packet->pkt_cnt;
4228        pkt_index++;
4229        m_pkt_info = m_flow_info->GetPacket((pkt_index-1));
4230        return (dticks);
4231}
4232
4233inline void CGenNode::reset_pkt_in_flow(void){
4234        m_pkt_info = m_flow_info->GetPacket(0);
4235}
4236
4237inline void CGenNode::replace_tuple(void){
4238    m_pkt_info->replace_tuple(this);
4239}
4240
4241enum MINVM_PLUGIN_ID{
4242    mpRTSP=1,
4243    mpSIP_VOICE=2,
4244    mpDYN_PYLOAD=3,
4245    mpAVL_HTTP_BROWSIN=4  /* this is a way to change the host ip by client ip */
4246};
4247
4248class CPluginCallback {
4249public:
4250    virtual ~CPluginCallback(){
4251    }
4252    virtual void on_node_first(uint8_t plugin_id,CGenNode *     node,CFlowYamlInfo *  template_info, CTupleTemplateGeneratorSmart * tuple_gen,CFlowGenListPerThread  * flow_gen) =0;
4253    virtual void on_node_last(uint8_t plugin_id,CGenNode *     node)=0;
4254    virtual rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode *     node,CFlowPktInfo * pkt_info)=0;
4255public:
4256    static CPluginCallback * callback;
4257};
4258
4259class CPluginCallbackSimple : public CPluginCallback {
4260public:
4261    virtual void on_node_first(uint8_t plugin_id,CGenNode *     node,
4262                               CFlowYamlInfo *  template_info,
4263                               CTupleTemplateGeneratorSmart * tuple_gen,
4264                               CFlowGenListPerThread  * flow_gen);
4265    virtual void on_node_last(uint8_t plugin_id,CGenNode *     node);
4266    virtual rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode *     node,CFlowPktInfo * pkt_info);
4267
4268private:
4269    rte_mbuf_t * rtsp_plugin(uint8_t plugin_id,CGenNode *     node,CFlowPktInfo * pkt_info);
4270    rte_mbuf_t * sip_voice_plugin(uint8_t plugin_id,CGenNode *     node,CFlowPktInfo * pkt_info);
4271    rte_mbuf_t * dyn_pyload_plugin(uint8_t plugin_id,CGenNode *     node,CFlowPktInfo * pkt_info);
4272    rte_mbuf_t * http_plugin(uint8_t plugin_id,CGenNode *     node,CFlowPktInfo * pkt_info);
4273
4274};
4275
4276
4277inline bool CGenNode::can_cache_mbuf(void){
4278    if ( is_repeat_flow() && ( m_flow_info->Size()==1 ) ){
4279        return (true);
4280    }else{
4281        return (false);
4282    }
4283}
4284
4285
4286/* direction for ip addr SERVER put tuple from server side client put addr of client side */
4287inline  pkt_dir_t CGenNode::cur_pkt_ip_addr_dir(){
4288
4289    CFlowPktInfo *  lp=m_pkt_info;
4290    bool init_from_server=get_is_initiator_start_from_server_with_server_addr();
4291    bool is_init=lp->m_pkt_indication.m_desc.IsInitSide() ^ init_from_server;
4292    return ( is_init ?CLIENT_SIDE:SERVER_SIDE);
4293}
4294
4295/* direction for TCP/UDP port */
4296inline  pkt_dir_t CGenNode::cur_pkt_port_addr_dir(){
4297    CFlowPktInfo *  lp=m_pkt_info;
4298    bool is_init=lp->m_pkt_indication.m_desc.IsInitSide() ;
4299    return ( is_init ?CLIENT_SIDE:SERVER_SIDE);
4300}
4301/* from which interface dir to get out */
4302inline  pkt_dir_t CGenNode::cur_interface_dir(){
4303
4304    CFlowPktInfo *  lp=m_pkt_info;
4305
4306    bool init_from_server=(get_is_initiator_start_from_server()||
4307                            get_is_initiator_start_from_server_with_server_addr());
4308    bool is_init=lp->m_pkt_indication.m_desc.IsInitSide() ^ init_from_server;
4309
4310    if (get_is_all_flow_from_same_dir()) {
4311        return (is_eligible_from_server_side()?SERVER_SIDE:CLIENT_SIDE);
4312    }else{
4313        return ( is_init ?CLIENT_SIDE:SERVER_SIDE);
4314    }
4315}
4316
4317/* Itay: move this to a better place (common for RX STL and RX STF) */
4318class CRXCoreIgnoreStat {
4319    friend class CCPortLatency;
4320    friend class CLatencyManager;
4321    friend class RXGratARP;
4322 public:
4323    inline CRXCoreIgnoreStat operator- (const CRXCoreIgnoreStat &t_in) const {
4324        CRXCoreIgnoreStat t_out;
4325        t_out.m_tx_arp = this->m_tx_arp - t_in.m_tx_arp;
4326        t_out.m_tx_ipv6_n_solic = this->m_tx_ipv6_n_solic - t_in.m_tx_ipv6_n_solic;
4327        t_out.m_tot_bytes = this->m_tot_bytes - t_in.m_tot_bytes;
4328        return t_out;
4329    }
4330    uint64_t get_tx_bytes() {return m_tot_bytes;}
4331    uint64_t get_tx_pkts() {return m_tx_arp + m_tx_ipv6_n_solic;}
4332    uint64_t get_tx_arp() {return m_tx_arp;}
4333    uint64_t get_tx_n_solic() {return m_tx_ipv6_n_solic;}
4334    void clear() {
4335        m_tx_arp = 0;
4336        m_tx_ipv6_n_solic = 0;
4337        m_tot_bytes = 0;
4338    }
4339
4340 private:
4341    uint64_t m_tx_arp;
4342    uint64_t m_tx_ipv6_n_solic;
4343    uint64_t m_tot_bytes;
4344};
4345
4346static_assert(sizeof(CGenNodeNatInfo) == sizeof(CGenNode), "sizeof(CGenNodeNatInfo) != sizeof(CGenNode)" );
4347static_assert(sizeof(CGenNodeLatencyPktInfo) == sizeof(CGenNode), "sizeof(CGenNodeLatencyPktInfo) != sizeof(CGenNode)" );
4348
4349#endif
4350