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