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