From 8b52a31ed2c299b759f330c4f976b9c70f5765f4 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 24 Jun 2015 14:03:29 +0300 Subject: first version --- src/bp_sim.h | 3990 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3990 insertions(+) create mode 100755 src/bp_sim.h (limited to 'src/bp_sim.h') diff --git a/src/bp_sim.h b/src/bp_sim.h new file mode 100755 index 00000000..002c9d0a --- /dev/null +++ b/src/bp_sim.h @@ -0,0 +1,3990 @@ +#ifndef BP_SIM_H +#define BP_SIM_H +/* + Hanoh Haim + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mbuf.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "os_time.h" +#include "pal_utl.h" +#include "rx_check_header.h" +#include "rx_check.h" +#include "time_histogram.h" +#include "utl_cpuu.h" +#include "tuple_gen.h" +#include "utl_jitter.h" +#include "msg_manager.h" +#include "nat_check.h" +#include +#include +#include "platform_cfg.h" + +#undef NAT_TRACE_ + + +#define FORCE_NO_INLINE __attribute__ ((noinline)) + +#define MAX_LATENCY_PORTS 12 + +/* IP address, last 32-bits of IPv6 remaps IPv4 */ +typedef struct { + uint16_t v6[6]; /* First 96-bits of IPv6 */ + uint32_t v4; /* Last 32-bits IPv6 overloads v4 */ +} ipaddr_t; + +/* reserve both 0xFF and 0xFE , router will -1 FF */ +#define TTL_RESERVE_DUPLICATE 0xff + +/* + * Length of string needed to hold the largest port (16-bit) address + */ +#define INET_PORTSTRLEN 5 + + + + + +/* VM commands */ + +class CMiniVMCmdBase { +public: + enum MV_FLAGS { + MIN_VM_V6=1 // IPv6 addressing + }; + uint8_t m_cmd; + uint8_t m_flags; + uint16_t m_start_0; + uint16_t m_stop_1; + uint16_t m_add_pkt_len; /* request more length for mbuf packet the size */ +}; + +class CMiniVMReplaceIP : public CMiniVMCmdBase { +public: + ipaddr_t m_server_ip; +}; + +class CMiniVMReplaceIPWithPort : public CMiniVMReplaceIP { +public: + uint16_t m_start_port; + uint16_t m_stop_port; + uint16_t m_client_port; + uint16_t m_server_port; +}; + +/* this command replace IP in 2 diffrent location and port + +c = 10.1.1.2 +o = 10.1.1.2 +m = audio 102000 + +==> + +c = xx.xx.xx.xx +o = xx.xx.xx.xx +m = audio yyyy + +*/ + +class CMiniVMReplaceIP_IP_Port : public CMiniVMCmdBase { +public: + ipaddr_t m_ip; + uint16_t m_ip0_start; + uint16_t m_ip0_stop; + + uint16_t m_ip1_start; + uint16_t m_ip1_stop; + + + uint16_t m_port; + uint16_t m_port_start; + uint16_t m_port_stop; +}; + +class CMiniVMReplaceIP_PORT_IP_IP_Port : public CMiniVMReplaceIP_IP_Port { +public: + ipaddr_t m_ip_via; + uint16_t m_port_via; + + uint16_t m_ip_via_start; + uint16_t m_ip_via_stop; +}; + +class CMiniVMDynPyload : public CMiniVMCmdBase { +public: + void * m_ptr; + ipaddr_t m_ip; +} ; + +/* VM with SIMD commands for RTSP we can add SIP/FTP commands too */ + +typedef enum { VM_REPLACE_IP_OFFSET =0x12, /* fix ip at offset */ + VM_REPLACE_IP_PORT_OFFSET, /* fix ip at offset and client port*/ + VM_REPLACE_IP_PORT_RESPONSE_OFFSET, /* fix client port and server port */ + VM_REPLACE_IP_IP_PORT,/* SMID command to replace IPV4 , IPV4, PORT in 3 diffrent location , see CMiniVMReplaceIP_IP_Port*/ + 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*/ + VM_DYN_PYLOAD, + + + VM_EOP /* end of program */ + } mini_vm_op_code_t; + + +/* work only on x86 littel */ +#define MY_B(b) (((int)b)&0xff) + +// Routine to create IPv4 address string +inline int ip_to_str(uint32_t ip,char * str){ + uint32_t ipv4 = PKT_HTONL(ip); + inet_ntop(AF_INET, (const char *)&ipv4, str, INET_ADDRSTRLEN); + return(strlen(str)); +} + +// Routine to create IPv6 address string +inline int ipv6_to_str(ipaddr_t *ip,char * str){ + int idx=0; + uint16_t ipv6[8]; + for (uint8_t i=0; i<6; i++) { + ipv6[i] = PKT_HTONS(ip->v6[i]); + } + uint32_t ipv4 = PKT_HTONL(ip->v4); + ipv6[6] = ipv4 & 0xffff; + ipv6[7] = ipv4 >> 16; + + str[idx++] = '['; + inet_ntop(AF_INET6, (const char *)&ipv6, &str[1], INET6_ADDRSTRLEN); + idx = strlen(str); + str[idx++] = ']'; + str[idx] = 0; + return(idx); +} + +class CFlowPktInfo ; + +class CMiniVM { + +public: + CMiniVM(){ + m_new_pkt_size=0; + } + + int mini_vm_run(CMiniVMCmdBase * cmds[]); + int mini_vm_replace_ip(CMiniVMReplaceIP * cmd); + int mini_vm_replace_port_ip(CMiniVMReplaceIPWithPort * cmd); + int mini_vm_replace_ports(CMiniVMReplaceIPWithPort * cmd); + int mini_vm_replace_ip_ip_ports(CMiniVMReplaceIP_IP_Port * cmd); + int mini_vm_replace_ip_via_ip_ip_ports(CMiniVMReplaceIP_PORT_IP_IP_Port * cmd); + int mini_vm_dyn_payload( CMiniVMDynPyload * cmd); + + +private: + int append_with_end_of_line(uint16_t len){ + //assert(m_new_pkt_size<=0); + if (m_new_pkt_size <0 ) { + memset(m_pyload_mbuf_ptr+len+m_new_pkt_size,0xa,(-m_new_pkt_size)); + } + + } +public: + int16_t m_new_pkt_size; /* New packet size after transform by plugin */ + CFlowPktInfo * m_pkt_info; + char * m_pyload_mbuf_ptr; /* pointer to the pyload pointer of new allocated packet from mbuf */ +}; + + + + + +class CGenNode; +class CFlowYamlInfo; +class CFlowGenListPerThread ; + + +/* callback */ +void on_node_first(uint8_t plugin_id,CGenNode * node, + CFlowYamlInfo * template_info, + CTupleTemplateGeneratorSmart * tuple_gen, + CFlowGenListPerThread * flow_gen + ); + +void on_node_last(uint8_t plugin_id,CGenNode * node); + +rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info); + + + + +class CPreviewMode ; +struct CGenNode; +/* represent the virtual interface +*/ + +/* counters per side */ +class CVirtualIFPerSideStats { +public: + CVirtualIFPerSideStats(){ + Clear(); + m_template.Clear(); + } + + uint64_t m_tx_pkt; + uint64_t m_tx_rx_check_pkt; + uint64_t m_tx_bytes; + uint64_t m_tx_drop; + uint64_t m_tx_queue_full; + uint64_t m_tx_alloc_error; + + CPerTxthreadTemplateInfo m_template; + +public: + + void Add(CVirtualIFPerSideStats * obj){ + m_tx_pkt += obj->m_tx_pkt; + m_tx_rx_check_pkt +=obj->m_tx_rx_check_pkt; + m_tx_bytes += obj->m_tx_bytes; + m_tx_drop += obj->m_tx_drop; + m_tx_alloc_error += obj->m_tx_alloc_error; + m_tx_queue_full +=obj->m_tx_queue_full; + m_template.Add(&obj->m_template); + } + + void Clear(){ + m_tx_pkt=0; + m_tx_rx_check_pkt=0; + m_tx_bytes=0; + m_tx_drop=0; + m_tx_alloc_error=0; + m_tx_queue_full=0; + m_template.Clear(); + } + + inline void Dump(FILE *fd); + +}; + + +void CVirtualIFPerSideStats::Dump(FILE *fd){ + + #define DP_B(f) if (f) printf(" %-40s : %llu \n",#f,f) + DP_B(m_tx_pkt); + DP_B(m_tx_rx_check_pkt); + DP_B(m_tx_bytes); + DP_B(m_tx_drop); + DP_B(m_tx_alloc_error); + DP_B(m_tx_queue_full); + m_template.Dump(fd); +} + + + + + + +class CVirtualIF { +public: + + + CVirtualIF (){ + m_preview_mode =NULL; + } +public: + + virtual int open_file(std::string file_name)=0; + + virtual int close_file(void)=0; + + + /** + * send one packet + * + * @param node + * + * @return + */ + virtual int send_node(CGenNode * node) =0; + + + /** + * send one packet to a specific dir. flush all packets + * + * @param dir + * @param m + */ + virtual void send_one_pkt(pkt_dir_t dir, rte_mbuf_t *m){ + } + + + /** + * flush all pending packets into the stream + * + * @return + */ + virtual int flush_tx_queue(void)=0; + +public: + + + void set_review_mode(CPreviewMode * preview_mode){ + m_preview_mode =preview_mode; + } + +protected : + CPreviewMode * m_preview_mode; + +public: + CVirtualIFPerSideStats m_stats[CS_NUM]; +}; + + + +/* global info */ + +#define CONST_NB_MBUF 16380 + + +#define MAX_BUF_SIZE (2048) +#define CONST_MBUF_SIZE (MAX_BUF_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) + +/* this is the first small part of the packet that we manipulate */ +#define FIRST_PKT_SIZE 64 +#define CONST_SMALL_MBUF_SIZE (FIRST_PKT_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) + + +#define _128_MBUF_SIZE 128 +#define _256_MBUF_SIZE 256 +#define _512_MBUF_SIZE 512 +#define _1024_MBUF_SIZE 1024 + + + +#define CONST_128_MBUF_SIZE (128 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) +#define CONST_256_MBUF_SIZE (256 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) +#define CONST_512_MBUF_SIZE (512 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) +#define CONST_1024_MBUF_SIZE (1024 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) + + +class CPreviewMode { +public: + CPreviewMode(){ + clean(); + } + void clean(){ + m_flags = 0; + m_flags1=0; + setCores(1); + set_zmq_publish_enable(true); + } + + void setFileWrite(bool enable){ + btSetMaskBit32(m_flags,0,0,enable?1:0); + } + + bool getFileWrite(){ + return (btGetMaskBit32(m_flags,0,0) ? true:false); + } + + void setDisableMbufCache(bool enable){ + btSetMaskBit32(m_flags,2,2,enable?1:0); + } + + bool isMbufCacheDisabled(){ + return (btGetMaskBit32(m_flags,2,2) ? true:false); + } + + void set_disable_flow_control_setting(bool enable){ + btSetMaskBit32(m_flags,4,4,enable?1:0); + } + + bool get_is_disable_flow_control_setting(){ + return (btGetMaskBit32(m_flags,4,4) ? true:false); + } + + + /* learn & verify mode */ + void set_lean_and_verify_mode_enable(bool enable){ + btSetMaskBit32(m_flags,5,5,enable?1:0); + } + + bool get_learn_and_verify_mode_enable(){ + return (btGetMaskBit32(m_flags,5,5) ? true:false); + } + + + /* learn mode */ + void set_lean_mode_enable(bool enable){ + btSetMaskBit32(m_flags,6,6,enable?1:0); + } + + bool get_learn_mode_enable(){ + return (btGetMaskBit32(m_flags,6,6) ? true:false); + } + + + /* IPv6 enable/disable */ + void set_ipv6_mode_enable(bool enable){ + btSetMaskBit32(m_flags,7,7,enable?1:0); + } + + bool get_ipv6_mode_enable(){ + return (btGetMaskBit32(m_flags,7,7) ? true:false); + } + + void setVMode(uint8_t vmode){ + btSetMaskBit32(m_flags,10,8,vmode); + } + uint8_t getVMode(){ + return (btGetMaskBit32(m_flags,10,8) ); + } + + + void setRealTime(bool enable){ + btSetMaskBit32(m_flags,11,11,enable?1:0); + } + + bool getRealTime(){ + return (btGetMaskBit32(m_flags,11,11) ? true:false); + } + + void setClientServerFlip(bool enable){ + btSetMaskBit32(m_flags,12,12,enable?1:0); + } + + bool getClientServerFlip(){ + return (btGetMaskBit32(m_flags,12,12) ? true:false); + } + + void setSingleCore(bool enable){ + btSetMaskBit32(m_flags,13,13,enable?1:0); + } + + bool getSingleCore(){ + return (btGetMaskBit32(m_flags,13,13) ? true:false); + } + + /* -p */ + void setClientServerFlowFlip(bool enable){ + btSetMaskBit32(m_flags,14,14,enable?1:0); + } + + bool getClientServerFlowFlip(){ + return (btGetMaskBit32(m_flags,14,14) ? true:false); + } + + + + void setNoCleanFlowClose(bool enable){ + btSetMaskBit32(m_flags,15,15,enable?1:0); + } + + bool getNoCleanFlowClose(){ + return (btGetMaskBit32(m_flags,15,15) ? true:false); + } + + void setCores(uint8_t cores){ + btSetMaskBit32(m_flags,24,16,cores); + } + + uint8_t getCores(){ + return (btGetMaskBit32(m_flags,24,16) ); + } + + bool getIsOneCore(){ + return (getCores()==1?true:false); + } + + void setOnlyLatency(bool enable){ + btSetMaskBit32(m_flags,25,25,enable?1:0); + } + + bool getOnlyLatency(){ + return (btGetMaskBit32(m_flags,25,25) ? true:false); + } + + + void set_1g_mode(bool enable){ + btSetMaskBit32(m_flags,26,26,enable?1:0); + } + + bool get_1g_mode(){ + return (btGetMaskBit32(m_flags,26,26) ? true:false); + } + + + void set_zmq_publish_enable(bool enable){ + btSetMaskBit32(m_flags,27,27,enable?1:0); + } + + bool get_zmq_publish_enable(){ + return (btGetMaskBit32(m_flags,27,27) ? true:false); + } + + void set_pcap_mode_enable(bool enable){ + btSetMaskBit32(m_flags,28,28,enable?1:0); + } + + bool get_pcap_mode_enable(){ + return (btGetMaskBit32(m_flags,28,28) ? true:false); + } + + /* VLAN enable/disable */ + bool get_vlan_mode_enable(){ + return (btGetMaskBit32(m_flags,29,29) ? true:false); + } + + void set_vlan_mode_enable(bool enable){ + btSetMaskBit32(m_flags,29,29,enable?1:0); + } + + bool get_mac_ip_overide_enable(){ + return (btGetMaskBit32(m_flags,30,30) ? true:false); + } + + void set_mac_ip_overide_enable(bool enable){ + btSetMaskBit32(m_flags,30,30,enable?1:0); + if (enable) { + set_mac_ip_features_enable(enable); + } + } + + bool get_is_rx_check_enable(){ + return (btGetMaskBit32(m_flags,31,31) ? true:false); + } + + void set_rx_check_enable(bool enable){ + btSetMaskBit32(m_flags,31,31,enable?1:0); + } + + + bool get_mac_ip_features_enable(){ + return (btGetMaskBit32(m_flags1,0,0) ? true:false); + } + + void set_mac_ip_features_enable(bool enable){ + btSetMaskBit32(m_flags1,0,0,enable?1:0); + } + + bool get_mac_ip_mapping_enable(){ + return (btGetMaskBit32(m_flags1,1,1) ? true:false); + } + + void set_mac_ip_mapping_enable(bool enable){ + btSetMaskBit32(m_flags1,1,1,enable?1:0); + if (enable) { + set_mac_ip_features_enable(enable); + } + } + + bool get_vm_one_queue_enable(){ + return (btGetMaskBit32(m_flags1,2,2) ? true:false); + } + + void set_no_keyboard(bool enable){ + btSetMaskBit32(m_flags1,5,5,enable?1:0); + } + + bool get_no_keyboard(){ + return (btGetMaskBit32(m_flags1,5,5) ? true:false); + } + + void set_vm_one_queue_enable(bool enable){ + btSetMaskBit32(m_flags1,2,2,enable?1:0); + } + + /* -e */ + void setClientServerFlowFlipAddr(bool enable){ + btSetMaskBit32(m_flags1,3,3,enable?1:0); + } + + bool getClientServerFlowFlipAddr(){ + return (btGetMaskBit32(m_flags1,3,3) ? true:false); + } + + + /* split mac is enabled */ + void setDestMacSplit(bool enable){ + btSetMaskBit32(m_flags1,4,4,enable?1:0); + } + + bool getDestMacSplit(){ + return (btGetMaskBit32(m_flags1,4,4) ? true:false); + } + + + + +public: + void Dump(FILE *fd); + +private: + uint32_t m_flags; + uint32_t m_flags1; + + +}; + + + +typedef struct mac_align_t_ { + uint8_t dest[6]; + uint8_t src[6]; + uint8_t pad[4]; +} mac_align_t ; + +struct CMacAddrCfg { +public: + CMacAddrCfg (){ + memset(u.m_data,0,sizeof(u.m_data)); + u.m_mac.dest[3]=1; + u.m_mac.src[3]=1; + } + union { + mac_align_t m_mac; + uint8_t m_data[16]; + } u; +} __rte_cache_aligned; ; + +struct CParserOption { + +public: + /* Runtime flags */ + enum { + RUN_FLAGS_RXCHECK_CONST_TS =1, + }; + +public: + CParserOption(){ + m_factor=1.0; + m_duration=0.0; + m_latency_rate =0; + m_latency_mask =0xffffffff; + m_latency_prev=0; + m_zmq_port=4500; + m_telnet_port =4501; + m_platform_factor=1.0; + m_expected_portd = 4; /* should be at least the number of ports found in the system but could be less */ + m_vlan_port[0]=100; + m_vlan_port[1]=100; + m_rx_check_sampe=0; + m_rx_check_hops = 0; + m_io_mode=1; + m_run_flags=0; + prefix=""; + m_mac_splitter=0; + } + + CPreviewMode preview; + float m_factor; + float m_duration; + float m_platform_factor; + uint16_t m_vlan_port[2]; /* vlan value */ + uint16_t m_src_ipv6[6]; /* Most signficant 96-bits */ + uint16_t m_dst_ipv6[6]; /* Most signficant 96-bits */ + uint16_t m_tcp_aging; + uint16_t m_udp_aging; + + uint32_t m_latency_rate; /* pkt/sec for each thread/port zero disable */ + uint32_t m_latency_mask; + uint32_t m_latency_prev; + uint16_t m_rx_check_sampe; /* the sample rate of flows */ + uint16_t m_rx_check_hops; + uint16_t m_zmq_port; + uint16_t m_telnet_port; + uint16_t m_expected_portd; + uint16_t m_io_mode; //0,1,2 0 disable, 1- normal , 2 - short + uint16_t m_run_flags; + uint8_t m_mac_splitter; + uint8_t m_pad; + + + std::string cfg_file; + std::string mac_file; + std::string platform_cfg_file; + + std::string out_file; + std::string prefix; + + + CMacAddrCfg m_mac_addr[MAX_LATENCY_PORTS]; + + uint8_t * get_src_mac_addr(int if_index){ + return (m_mac_addr[if_index].u.m_mac.src); + } + uint8_t * get_dst_src_mac_addr(int if_index){ + return (m_mac_addr[if_index].u.m_mac.dest); + } + +public: + uint32_t get_expected_ports(){ + return (m_expected_portd); + } + + /* how many dual ports supported */ + uint32_t get_expected_dual_ports(void){ + return (m_expected_portd>>1); + } + + uint32_t get_number_of_dp_cores_needed() { + return ( (m_expected_portd>>1) * preview.getCores()); + } + bool is_latency_disabled(){ + return ( m_latency_rate == 0 ?true:false); + } + + bool is_latency_enabled(){ + return ( !is_latency_disabled() ); + } + inline void set_rxcheck_const_ts(){ + m_run_flags |= RUN_FLAGS_RXCHECK_CONST_TS; + } + inline void clear_rxcheck_const_ts(){ + m_run_flags &=~ RUN_FLAGS_RXCHECK_CONST_TS; + } + + inline bool is_rxcheck_const_ts(){ + return ( (m_run_flags &RUN_FLAGS_RXCHECK_CONST_TS)?true:false ); + } + + void dump(FILE *fd); +}; + + +class CGlobalMemory { + +public: + CGlobalMemory(){ + CPlatformMemoryYamlInfo info; + set(info,1.0); + m_num_cores=1; + } + void set(const CPlatformMemoryYamlInfo &info,float mul); + + uint32_t get_2k_num_blocks(){ + return ( m_mbuf[MBUF_2048]); + } + + uint32_t get_each_core_dp_flows(){ + return ( m_mbuf[MBUF_DP_FLOWS]/m_num_cores ); + } + void set_number_of_dp_cors(uint32_t cores){ + m_num_cores = cores; + } + + void Dump(FILE *fd); + +public: + uint32_t m_mbuf[MBUF_SIZE]; // relative to traffic norm to 2x10G ports + uint32_t m_num_cores; + +}; + +typedef uint8_t socket_id_t; +typedef uint8_t port_id_t; +/* the real phsical thread id */ +typedef uint8_t physical_thread_id_t; + + +typedef uint8_t virtual_thread_id_t; +/* + + virtual thread 0 (v0)- is always the master + +for 2 dual ports ( 2x2 =4 ports) the virtual thread looks like that +----------------- +DEFAULT: +----------------- + (0,1) (2,3) + dual-if0 dual-if-1 + v1 v2 + v3 v4 + v5 v6 + v7 v8 + + latency is v9 + + */ + +#define MAX_SOCKETS_SUPPORTED (4) +#define MAX_THREADS_SUPPORTED (120) + + +class CPlatformSocketInfoBase { + + +public: + /* sockets API */ + + /* is socket enabled */ + virtual bool is_sockets_enable(socket_id_t socket)=0; + + /* number of main active sockets. socket #0 is always used */ + virtual socket_id_t max_num_active_sockets()=0; + +public: + /* which socket to allocate memory to each port */ + virtual socket_id_t port_to_socket(port_id_t port)=0; + +public: + /* this is from CLI, number of thread per dual port */ + virtual void set_number_of_threads_per_ports(uint8_t num_threads)=0; + virtual void set_latency_thread_is_enabled(bool enable)=0; + virtual void set_number_of_dual_ports(uint8_t num_dual_ports)=0; + + + virtual bool sanity_check()=0; + + /* return the core mask */ + virtual uint64_t get_cores_mask()=0; + + /* virtual thread_id is always from 1..number of threads virtual */ + virtual virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t phy_id)=0; + + /* return the map betwean virtual to phy id */ + virtual physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id)=0; + + virtual bool thread_phy_is_master(physical_thread_id_t phy_id)=0; + virtual bool thread_phy_is_latency(physical_thread_id_t phy_id)=0; + + virtual void dump(FILE *fd)=0; +}; + +class CPlatformSocketInfoNoConfig : public CPlatformSocketInfoBase { + +public: + CPlatformSocketInfoNoConfig(){ + m_dual_if=0; + m_threads_per_dual_if=0; + m_latency_is_enabled=false; + } + + /* is socket enabled */ + bool is_sockets_enable(socket_id_t socket); + + /* number of main active sockets. socket #0 is always used */ + socket_id_t max_num_active_sockets(); + +public: + /* which socket to allocate memory to each port */ + socket_id_t port_to_socket(port_id_t port); + +public: + /* this is from CLI, number of thread per dual port */ + void set_number_of_threads_per_ports(uint8_t num_threads); + void set_latency_thread_is_enabled(bool enable); + void set_number_of_dual_ports(uint8_t num_dual_ports); + + bool sanity_check(); + + /* return the core mask */ + uint64_t get_cores_mask(); + + /* virtual thread_id is always from 1..number of threads virtual */ + virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t phy_id); + + /* return the map betwean virtual to phy id */ + physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id); + + bool thread_phy_is_master(physical_thread_id_t phy_id); + bool thread_phy_is_latency(physical_thread_id_t phy_id); + + virtual void dump(FILE *fd); + +private: + uint32_t m_dual_if; + uint32_t m_threads_per_dual_if; + bool m_latency_is_enabled; +}; + + + +/* there is a configuration file */ +class CPlatformSocketInfoConfig : public CPlatformSocketInfoBase { +public: + bool Create(CPlatformCoresYamlInfo * platform); + void Delete(); + + /* is socket enabled */ + bool is_sockets_enable(socket_id_t socket); + + /* number of main active sockets. socket #0 is always used */ + socket_id_t max_num_active_sockets(); + +public: + /* which socket to allocate memory to each port */ + socket_id_t port_to_socket(port_id_t port); + +public: + /* this is from CLI, number of thread per dual port */ + void set_number_of_threads_per_ports(uint8_t num_threads); + void set_latency_thread_is_enabled(bool enable); + void set_number_of_dual_ports(uint8_t num_dual_ports); + + bool sanity_check(); + + /* return the core mask */ + uint64_t get_cores_mask(); + + /* virtual thread_id is always from 1..number of threads virtual */ + virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t phy_id); + + /* return the map betwean virtual to phy id */ + physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id); + + bool thread_phy_is_master(physical_thread_id_t phy_id); + bool thread_phy_is_latency(physical_thread_id_t phy_id); + +public: + virtual void dump(FILE *fd); +private: + void reset(); + bool init(); + +private: + bool m_sockets_enable[MAX_SOCKETS_SUPPORTED]; + uint32_t m_sockets_enabled; + socket_id_t m_socket_per_dual_if[(MAX_LATENCY_PORTS>>1)]; + + uint32_t m_max_threads_per_dual_if; + + uint32_t m_num_dual_if; + uint32_t m_threads_per_dual_if; + bool m_latency_is_enabled; + uint8_t m_thread_virt_to_phy[MAX_THREADS_SUPPORTED]; + uint8_t m_thread_phy_to_virtual[MAX_THREADS_SUPPORTED]; + + CPlatformCoresYamlInfo * m_platform; +}; + + + +class CPlatformSocketInfo { + +public: + bool Create(CPlatformCoresYamlInfo * platform); + void Delete(); + +public: + /* sockets API */ + + /* is socket enabled */ + bool is_sockets_enable(socket_id_t socket); + + /* number of main active sockets. socket #0 is always used */ + socket_id_t max_num_active_sockets(); + +public: + /* which socket to allocate memory to each port */ + socket_id_t port_to_socket(port_id_t port); + +public: + /* this is from CLI, number of thread per dual port */ + void set_number_of_threads_per_ports(uint8_t num_threads); + void set_latency_thread_is_enabled(bool enable); + void set_number_of_dual_ports(uint8_t num_dual_ports); + + + bool sanity_check(); + + /* return the core mask */ + uint64_t get_cores_mask(); + + /* virtual thread_id is always from 1..number of threads virtual */ + virtual_thread_id_t thread_phy_to_virt(physical_thread_id_t phy_id); + + /* return the map betwean virtual to phy id */ + physical_thread_id_t thread_virt_to_phy(virtual_thread_id_t virt_id); + + bool thread_phy_is_master(physical_thread_id_t phy_id); + bool thread_phy_is_latency(physical_thread_id_t phy_id); + + void dump(FILE *fd); + + +private: + CPlatformSocketInfoBase * m_obj; + CPlatformCoresYamlInfo * m_platform; +}; + +class CRteMemPool { + +public: + inline rte_mbuf_t * _rte_pktmbuf_alloc(rte_mempool_t * mp ){ + rte_mbuf_t * m=rte_pktmbuf_alloc(mp); + if ( likely(m>0) ) { + return (m); + } + dump_in_case_of_error(stderr); + assert(0); + } + + inline rte_mbuf_t * pktmbuf_alloc(uint16_t size){ + + rte_mbuf_t * m; + if ( size < _128_MBUF_SIZE) { + m = _rte_pktmbuf_alloc(m_mbuf_pool_128); + }else if ( size < _256_MBUF_SIZE) { + m = _rte_pktmbuf_alloc(m_mbuf_pool_256); + }else if (size < _512_MBUF_SIZE) { + m = _rte_pktmbuf_alloc(m_mbuf_pool_512); + }else if (size < _1024_MBUF_SIZE) { + m = _rte_pktmbuf_alloc(m_mbuf_pool_1024); + }else{ + assert(sizem_time); + } + bool operator ==(const CGenNode * rsh ) const { + return (m_time==rsh->m_time); + } + bool operator >(const CGenNode * rsh ) const { + return (m_time>rsh->m_time); + } +public: + void Dump(FILE *fd); + + void set_socket_id(socket_id_t socket){ + m_socket_id=socket; + } + + socket_id_t get_socket_id(){ + return ( m_socket_id ); + } + + + static void DumpHeader(FILE *fd); + inline bool is_last_in_flow(); + inline uint16_t get_template_id(); + inline bool is_repeat_flow(); + inline bool can_cache_mbuf(void); + + /* is it possible to cache MBUF */ + + inline void update_next_pkt_in_flow(void); + inline void reset_pkt_in_flow(void); + inline uint8_t get_plugin_id(void){ + return ( m_template_info->m_plugin_id); + } + + inline bool is_responder_pkt(); + inline bool is_initiator_pkt(); + + + inline bool is_eligible_from_server_side(){ + return ( (m_src_ip&1==1)?true:false); + } + + + inline void set_initiator_start_from_server_side_with_server_addr(bool enable){ + if (enable) { + m_flags |= NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR; + }else{ + m_flags &=~ NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR; + } + } + + inline bool get_is_initiator_start_from_server_with_server_addr(){ + return ( (m_flags &NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR)?true:false ); + } + + inline void set_initiator_start_from_server(bool enable){ + if (enable) { + m_flags |= NODE_FLAGS_INIT_START_FROM_SERVER_SIDE; + }else{ + m_flags &=~ NODE_FLAGS_INIT_START_FROM_SERVER_SIDE; + } + } + inline bool get_is_initiator_start_from_server(){ + return ( (m_flags &NODE_FLAGS_INIT_START_FROM_SERVER_SIDE)?true:false ); + } + + inline void set_all_flow_from_same_dir(bool enable){ + if (enable) { + m_flags |= NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE; + }else{ + m_flags &=~ NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE; + } + } + + inline bool get_is_all_flow_from_same_dir(void){ + return ( (m_flags &NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE)?true:false ); + } + + + /* direction for ip addr */ + inline pkt_dir_t cur_pkt_ip_addr_dir(); + /* direction for TCP/UDP port */ + inline pkt_dir_t cur_pkt_port_addr_dir(); + /* from which interface dir to get out */ + inline pkt_dir_t cur_interface_dir(); + + + inline void set_mbuf_cache_dir(pkt_dir_t dir){ + if (dir) { + m_flags |=NODE_FLAGS_DIR; + }else{ + m_flags &=~NODE_FLAGS_DIR; + } + } + + inline pkt_dir_t get_mbuf_cache_dir(){ + return ((pkt_dir_t)( m_flags &1)); + } + + inline void set_cache_mbuf(rte_mbuf_t * m){ + m_plugin_info=(void *)m; + m_flags |= NODE_FLAGS_MBUF_CACHE; + } + + inline rte_mbuf_t * get_cache_mbuf(){ + if ( m_flags &NODE_FLAGS_MBUF_CACHE ) { + return ((rte_mbuf_t *)m_plugin_info); + }else{ + return ((rte_mbuf_t *)0); + } + } + +public: + + inline void set_rx_check(){ + m_flags |= NODE_FLAGS_SAMPLE_RX_CHECK; + } + + inline bool is_rx_check_enabled(){ + return ((m_flags & NODE_FLAGS_SAMPLE_RX_CHECK)?true:false); + } + +public: + + inline void set_nat_first_state(){ + btSetMaskBit16(m_flags,4,3,1); + m_type=FLOW_PKT_NAT; + } + + inline bool is_nat_first_state(){ + return (btGetMaskBit16(m_flags,4,3)==1?true:false) ; + } + + inline void set_nat_wait_state(){ + btSetMaskBit16(m_flags,4,3,2); + } + + + inline bool is_nat_wait_state(){ + return (btGetMaskBit16(m_flags,4,3)==2?true:false) ; + } + + inline void set_nat_learn_state(){ + m_type=FLOW_PKT; /* normal operation .. repeat might work too */ + } + +public: + + + inline uint32_t get_short_fid(void){ + return ((uint32_t)m_flow_id); + } + + inline uint8_t get_thread_id(void){ + return (m_thread_id); + } + + inline void set_nat_ipv4_addr_server(uint32_t ip){ + m_nat_external_ipv4_server =ip; + } + + inline uint32_t get_nat_ipv4_addr_server(){ + return ( m_nat_external_ipv4_server ); + } + + + inline void set_nat_ipv4_addr(uint32_t ip){ + m_nat_external_ipv4 =ip; + } + + inline void set_nat_ipv4_port(uint16_t port){ + m_nat_external_port = port; + } + + inline uint32_t get_nat_ipv4_addr(){ + return ( m_nat_external_ipv4 ); + } + + inline uint16_t get_nat_ipv4_port(){ + return ( m_nat_external_port ); + } + + bool is_external_is_eq_to_internal_ip(){ + /* this API is used to check TRex itself */ + if ( (get_nat_ipv4_addr() == m_src_ip ) && + (get_nat_ipv4_port()==m_src_port) && + ( get_nat_ipv4_addr_server() == m_dest_ip) ) { + return (true); + }else{ + return (false); + } + } + + +public: + inline void replace_tuple(void); + +} __rte_cache_aligned; + + +#if __x86_64__ +/* size of 64 bytes */ + #define DEFER_CLIENTS_NUM (18) +#else + #define DEFER_CLIENTS_NUM (16) +#endif + +/* this class must be in the same size of CGenNode */ +struct CGenNodeDeferPort { + /* this header must be the same as CGenNode */ + uint8_t m_type; + uint8_t m_pad3; + uint16_t m_pad2; + uint32_t m_cnt; + double m_time; + + uint32_t m_clients[DEFER_CLIENTS_NUM]; + uint16_t m_ports[DEFER_CLIENTS_NUM]; +public: + void init(void){ + m_type=CGenNode::FLOW_DEFER_PORT_RELEASE; + m_cnt=0; + } + + /* return true if object is full */ + bool add_client(uint32_t client, + uint16_t port){ + m_clients[m_cnt]=client; + m_ports[m_cnt]=port; + m_cnt++; + if ( m_cnt == DEFER_CLIENTS_NUM ) { + return (true); + } + return (false); + } + +} __rte_cache_aligned ; + +/* run time verification of objects size and offsets + need to clean this up and derive this objects from base object but require too much refactoring right now + hhaim +*/ +inline int check_objects_sizes(void){ + if ( sizeof(CGenNodeDeferPort) != sizeof(CGenNode) ) { + printf("ERROR sizeof(CGenNodeDeferPort) %d != sizeof(CGenNode) %d must be the same size \n",sizeof(CGenNodeDeferPort),sizeof(CGenNode)); + assert(0); + } + if ( (int)offsetof(struct CGenNodeDeferPort,m_type)!=offsetof(struct CGenNode,m_type) ){ + printf("ERROR offsetof(struct CGenNodeDeferPort,m_type)!=offsetof(struct CGenNode,m_type) \n"); + assert(0); + } + if ( (int)offsetof(struct CGenNodeDeferPort,m_time)!=offsetof(struct CGenNode,m_time) ){ + printf("ERROR offsetof(struct CGenNodeDeferPort,m_time)!=offsetof(struct CGenNode,m_time) \n"); + assert(0); + } + return (0); +} + + +struct CGenNodeCompare +{ + bool operator() (const CGenNode * lhs, const CGenNode * rhs) + { + return lhs->m_time > rhs->m_time; + } +}; + + +class CCapPktRaw; +class CFileWriterBase; + + + +class CFlowGenStats { +public: + CFlowGenStats(){ + clear(); + } + // stats + uint64_t m_total_bytes; + uint64_t m_total_pkt; + uint64_t m_total_open_flows; + uint64_t m_total_close_flows; + uint64_t m_nat_lookup_no_flow_id; + uint64_t m_nat_lookup_remove_flow_id; + uint64_t m_nat_lookup_add_flow_id; + uint64_t m_nat_flow_timeout; + uint64_t m_nat_flow_learn_error; + +public: + void clear(); + void dump(FILE *fd); +}; + + + +typedef std::priority_queue,CGenNodeCompare> pqueue_t; + + + +class CErfIF : public CVirtualIF { + +public: + CErfIF(){ + m_writer=NULL; + m_raw=NULL; + } +public: + + virtual int open_file(std::string file_name); + virtual int write_pkt(CCapPktRaw *pkt_raw); + virtual int close_file(void); + + + /** + * send one packet + * + * @param node + * + * @return + */ + virtual int send_node(CGenNode * node); + + + + /** + * flush all pending packets into the stream + * + * @return + */ + virtual int flush_tx_queue(void); + + +private: + CFileWriterBase * m_writer; + CCapPktRaw * m_raw; +}; + +static inline int fill_pkt(CCapPktRaw * raw,rte_mbuf_t * m){ + raw->pkt_len = m->pkt_len; + char *p=raw->raw; + + rte_mbuf_t *m_next; + + while (m != NULL) { + m_next = m->next; + rte_memcpy(p,m->buf_addr,m->data_len); + p+=m->data_len; + m = m_next; + } + return (0); +} + + +class CNullIF : public CVirtualIF { + +public: + CNullIF(){ + } + +public: + + virtual int open_file(std::string file_name){ + return (0); + } + + virtual int write_pkt(CCapPktRaw *pkt_raw){ + return (0); + } + + virtual int close_file(void){ + return (0); + } + + + virtual int send_node(CGenNode * node); + + virtual int flush_tx_queue(void){ + return (0); + + } +}; + + +class CNodeGenerator { +public: + bool Create(CFlowGenListPerThread * parent); + void Delete(); + + void set_vif(CVirtualIF * v_if); + + CFlowGenListPerThread * Parent(){ + return (m_parent); + } +public: + void add_node(CGenNode * mynode); + void remove_all(CFlowGenListPerThread * thread); + int open_file(std::string file_name, + CPreviewMode * preview); + int close_file(CFlowGenListPerThread * thread); + int flush_file(dsec_t max_time, + dsec_t d_time, + bool always, + CFlowGenListPerThread * thread, + double & old_offset); + int defer_handler(CFlowGenListPerThread * thread); + + void schedule_node(CGenNode * node,double delay){ + node->m_time = (now_sec()+ delay); + add_node(node); + } + + + void DumpHist(FILE *fd){ + fprintf(fd,"\n"); + fprintf(fd,"\n"); + fprintf(fd,"normal\n"); + fprintf(fd,"-------------\n"); + m_realtime_his.Dump(fd); + } + + void dump_json(std::string & json); + + +private: + int flush_one_node_to_file(CGenNode * node); + int update_stats(CGenNode * node); + FORCE_NO_INLINE void handle_slow_messages(uint8_t type, + CGenNode * node, + CFlowGenListPerThread * thread, + bool always); + + +public: + pqueue_t m_p_queue; + socket_id_t m_socket_id; + bool m_is_realtime; + CVirtualIF * m_v_if; + CFlowGenListPerThread * m_parent; + CPreviewMode m_preview_mode; + uint64_t m_cnt; + CTimeHistogram m_realtime_his; +}; + + +class CPolicer { + +public: + + CPolicer(){ + ClearMeter(); + } + + void ClearMeter(){ + m_cir=0.0; + m_bucket_size=1.0; + m_level=0.0; + m_last_time=0.0; + } + + bool update(double dsize,dsec_t now_sec); + + void set_cir(double cir){ + BP_ASSERT(cir>=0.0); + m_cir=cir; + } + void set_level(double level){ + m_level =level; + } + + void set_bucket_size(double bucket){ + m_bucket_size =bucket; + } + +private: + + double m_cir; + + double m_bucket_size; + + double m_level; + + double m_last_time; +}; + +class CFlowKey { +public: + uint32_t m_ipaddr1; + uint32_t m_ipaddr2; + + uint16_t m_port1; + uint16_t m_port2; + + uint8_t m_ip_proto; /* TCP/UDP 6/17*/ + uint8_t m_l2_proto; /*IPV4/IPV6*/ + uint16_t m_vrfid; + +public: + inline bool operator <(const CFlowKey& rhs) const; + inline bool operator >(const CFlowKey& rhs) const; + inline bool operator ==(const CFlowKey& rhs) const; +public: + void Dump(FILE *fd); + void Clean(); +}; + + +inline bool CFlowKey::operator <(const CFlowKey& rhs) const{ + int cmp=memcmp(&m_ipaddr1,&rhs.m_ipaddr1 ,sizeof(CFlowKey)); + if (cmp>0) { + return (true); + }else{ + return (false); + } +} + +inline bool CFlowKey::operator >(const CFlowKey& rhs) const{ + int cmp=memcmp(&m_ipaddr1,&rhs.m_ipaddr1 ,sizeof(CFlowKey)); + if (cmp<0) { + return (true); + }else{ + return (false); + } +} + +inline bool CFlowKey::operator ==(const CFlowKey& rhs) const{ + int cmp=memcmp(&m_ipaddr1,&rhs.m_ipaddr1 ,sizeof(CFlowKey)); + if (cmp==0) { + return (true); + }else{ + return (false); + } +} + + + +/***********************************************************/ +/* descriptor flags */ + +#define IS_SWAP_S 0 +#define IS_SWAP_E 0 + +#define IS_VALID_S 1 +#define IS_VALID_E 1 + +#define IS_TCP_S 2 +#define IS_TCP_E 2 + +#define IS_UDP_S 3 +#define IS_UDP_E 3 + +#define IS_INIT_SIDE 4 + +#define IS_LAST_PKT_S 5 +#define IS_LAST_PKT_E 5 + +#define IS_RTT 6 + +#define IS_PCAP_TIMING 7 + +// 8-12 is used +#define FLOW_ID 8 + + +#define PLUGIN_ENABLE_S 13 +#define PLUGIN_ENABLE_E 13 +#define BOTH_DIR_FLOW_SE 14 +#define LEARN_MODE_ENABLE 15 + +/***********************************************************/ + +class CPacketDescriptorPerDir { +public: + CPacketDescriptorPerDir(){ + m_dir_pkt_num=0; + m_max_dir_flow_pkts=0; + } +public: + void SetMaxPkts( uint32_t val){ + assert(val<65000); + m_max_dir_flow_pkts = (uint16_t)val; + } + uint16_t GetMaxPkts(void){ + return (m_max_dir_flow_pkts); + } + + void SetPktNum(uint32_t pkt_id){ + assert(pkt_id<65000); + m_dir_pkt_num=(uint16_t)pkt_id; + } + + uint16_t GetPktNum(void){ + return (m_dir_pkt_num); + } + +private: + // per direction info + uint16_t m_dir_pkt_num; // pkt id + uint16_t m_max_dir_flow_pkts; +}; + + +class CPacketDescriptor { + +public: + + inline void Clear(){ + m_flags = 0; + m_flow_pkt_num=0; + m_plugin_id=0; + m_max_flow_pkts=0; + m_max_flow_aging=0; + } + + inline uint8_t getPluginId(){ + return (m_plugin_id); + } + inline void SetPluginId(uint8_t plugin_id){ + m_plugin_id=plugin_id; + } + + inline bool IsLearn(){ + return (btGetMaskBit32(m_flags,LEARN_MODE_ENABLE,LEARN_MODE_ENABLE) ? true:false); + } + inline void SetLearn(bool enable){ + btSetMaskBit32(m_flags,LEARN_MODE_ENABLE ,LEARN_MODE_ENABLE ,enable?1:0); + } + + + inline bool IsPluginEnable(){ + return (btGetMaskBit32(m_flags,PLUGIN_ENABLE_S,PLUGIN_ENABLE_S) ? true:false); + } + inline void SetPluginEnable(bool enable){ + btSetMaskBit32(m_flags,PLUGIN_ENABLE_S ,PLUGIN_ENABLE_S ,enable?1:0); + } + + inline bool IsBiDirectionalFlow(){ + return (btGetMaskBit32(m_flags,BOTH_DIR_FLOW_SE,BOTH_DIR_FLOW_SE) ? true:false); + } + inline void SetBiPluginEnable(bool enable){ + btSetMaskBit32(m_flags,BOTH_DIR_FLOW_SE ,BOTH_DIR_FLOW_SE ,enable?1:0); + } + + + /* packet number inside the global flow */ + inline void SetFlowPktNum(uint32_t pkt_id){ + m_flow_pkt_num = pkt_id; + + } + /** + * start from zero 0,1,2,.. , it is on global flow if you have couple of flows it will count all of the flows + * + * flow FlowPktNum + * 0 0 + * 0 1 + * 0 2 + * 1 0 + * 1 1 + * 2 0 + * + * @return + */ + inline uint32_t getFlowPktNum(){ + return ( m_flow_pkt_num); + } + + + inline void SetFlowId(uint16_t flow_id){ + btSetMaskBit32(m_flags,12,8,flow_id); + + } + inline uint16_t getFlowId(){ + return ( ( uint16_t)btGetMaskBit32(m_flags,12,8)); + } + + inline void SetPcapTiming(bool is_pcap){ + btSetMaskBit32(m_flags,IS_PCAP_TIMING,IS_PCAP_TIMING,is_pcap?1:0); + } + inline bool IsPcapTiming(){ + return (btGetMaskBit32(m_flags,IS_PCAP_TIMING,IS_PCAP_TIMING) ? true:false); + } + + + /* return true if this packet in diff direction from prev flow packet , + if true need to choose RTT else IPG for inter packet gap */ + inline bool IsRtt(){ + return (btGetMaskBit32(m_flags,IS_RTT,IS_RTT) ? true:false); + } + inline void SetRtt(bool is_rtt){ + btSetMaskBit32(m_flags,IS_RTT,IS_RTT,is_rtt?1:0); + } + + /* this is in respect to the first flow */ + inline bool IsInitSide(){ + return (btGetMaskBit32(m_flags,IS_INIT_SIDE,IS_INIT_SIDE) ? true:false); + } + + /* this is in respect to the first flow , this is what is needed when we replace IP source / destiniation */ + inline void SetInitSide(bool is_init_side){ + btSetMaskBit32(m_flags,IS_INIT_SIDE,IS_INIT_SIDE,is_init_side?1:0); + } + + /* per flow */ + inline bool IsSwapTuple(){ + return (btGetMaskBit32(m_flags,IS_SWAP_S,IS_SWAP_E) ? true:false); + } + inline void SetSwapTuple(bool is_swap){ + btSetMaskBit32(m_flags,IS_SWAP_S,IS_SWAP_E,is_swap?1:0); + } + + inline bool IsValidPkt(){ + return (btGetMaskBit32(m_flags,IS_VALID_S,IS_VALID_E) ? true:false); + } + + inline void SetIsValidPkt(bool is_valid){ + btSetMaskBit32(m_flags,IS_VALID_S,IS_VALID_E,is_valid?1:0); + } + + inline void SetIsTcp(bool is_valid){ + btSetMaskBit32(m_flags,IS_TCP_S,IS_TCP_E,is_valid?1:0); + } + + inline bool IsTcp(){ + return (btGetMaskBit32(m_flags,IS_TCP_S,IS_TCP_E) ? true:false); + } + + inline void SetIsUdp(bool is_valid){ + btSetMaskBit32(m_flags,IS_UDP_S,IS_UDP_E,is_valid?1:0); + } + + inline bool IsUdp(){ + return (btGetMaskBit32(m_flags,IS_UDP_S,IS_UDP_E) ? true:false); + } + + inline void SetId(uint16_t _id){ + btSetMaskBit32(m_flags,31,16,_id); + + } + inline uint16_t getId(){ + return ( ( uint16_t)btGetMaskBit32(m_flags,31,16)); + } + + inline void SetIsLastPkt(bool is_last){ + btSetMaskBit32(m_flags,IS_LAST_PKT_S,IS_LAST_PKT_E,is_last?1:0); + } + + /* last packet of couple of flows */ + inline bool IsLastPkt(){ + return (btGetMaskBit32(m_flags,IS_LAST_PKT_S,IS_LAST_PKT_E) ? true:false); + } + + // there could be couple of flows per template in case of plugin + inline void SetMaxPktsPerFlow(uint32_t pkts){ + assert(pkts<65000); + m_max_flow_pkts=pkts; + } + inline uint16_t GetMaxPktsPerFlow(){ + return ( m_max_flow_pkts ); + } + // there could be couple of flows per template in case of plugin + inline void SetMaxFlowTimeout(double sec){ + //assert (sec<65000); + sec = sec*2.0+5.0; + if ( sec > 65000) { + printf("Warning pcap file aging is %f truncating it \n",sec); + sec = 65000; + } + m_max_flow_aging = (uint16_t)sec; + } + + inline uint16_t GetMaxFlowTimeout(void){ + return ( m_max_flow_aging ); + } + + /* return per dir info , the dir is with respect to the first flow client/server side , this is tricky */ + CPacketDescriptorPerDir * GetDirInfo(void){ + return (&m_per_dir[IsInitSide()?CLIENT_SIDE:SERVER_SIDE]); + } + + bool IsOneDirectionalFlow(void){ + if ( ( m_per_dir[CLIENT_SIDE].GetMaxPkts() == GetMaxPktsPerFlow()) || ( m_per_dir[SERVER_SIDE].GetMaxPkts() == GetMaxPktsPerFlow()) ) { + return (true); + }else{ + return (false); + } + } + +public: + void Dump(FILE *fd); + +private: + uint32_t m_flags; + uint16_t m_flow_pkt_num; // packet number inside the flow + uint8_t m_plugin_id; // packet number inside the flow + uint8_t m_pad; + uint16_t m_max_flow_pkts; // how many packet per this flow getFlowId() + uint16_t m_max_flow_aging; // maximum aging in sec + CPacketDescriptorPerDir m_per_dir[CS_NUM]; // per direction info +}; + + +class CPacketParser; +class CFlow ; + + +class CCPacketParserCounters { +public: + uint64_t m_pkt; + uint64_t m_ipv4; + uint64_t m_ipv6; + uint64_t m_non_ip; + uint64_t m_vlan; + uint64_t m_arp; + uint64_t m_mpls; + + + /* IP stats */ + uint64_t m_non_valid_ipv4_ver; + uint64_t m_non_valid_ipv6_ver; + uint64_t m_ip_checksum_error; + uint64_t m_ip_length_error; + uint64_t m_ipv6_length_error; + uint64_t m_ip_not_first_fragment_error; + uint64_t m_ip_ttl_is_zero_error; + uint64_t m_ip_multicast_error; + uint64_t m_ip_header_options; + + /* TCP/UDP */ + uint64_t m_non_tcp_udp; + uint64_t m_non_tcp_udp_ah; + uint64_t m_non_tcp_udp_esp; + uint64_t m_non_tcp_udp_icmp; + uint64_t m_non_tcp_udp_gre; + uint64_t m_non_tcp_udp_ip; + uint64_t m_tcp_header_options; + uint64_t m_tcp_udp_pkt_length_error; + uint64_t m_tcp; + uint64_t m_udp; + uint64_t m_valid_udp_tcp; + +public: + void Clear(); + uint64_t getTotalErrors(); + void Dump(FILE *fd); +}; + + +class CPacketIndication { + +public: + dsec_t m_cap_ipg; /* ipg from cap file */ + CCapPktRaw * m_packet; + + CFlow * m_flow; + EthernetHeader * m_ether; + union { + IPHeader * m_ipv4; + IPv6Header * m_ipv6; + } l3; + bool m_is_ipv6; + union { + TCPHeader * m_tcp; + UDPHeader * m_udp; + } l4; + uint8_t * m_payload; + uint16_t m_payload_len; + uint16_t m_packet_padding; /* total packet size - IP total length */ + + + CFlowKey m_flow_key; + CPacketDescriptor m_desc; + + uint8_t m_ether_offset; + uint8_t m_ip_offset; + uint8_t m_udp_tcp_offset; + uint8_t m_payload_offset; + +public: + + void Dump(FILE *fd,int verbose); + void Clean(); + bool ConvertPacketToIpv6InPlace(CCapPktRaw * pkt, + int offset); + void ProcessPacket(CPacketParser *parser,CCapPktRaw * pkt); + void Clone(CPacketIndication * obj,CCapPktRaw * pkt); + void RefreshPointers(void); + void UpdatePacketPadding(); + +public: + bool is_ipv6(){ + return (m_is_ipv6); + } + char * getBasePtr(){ + return ((char *)m_packet->raw); + } + + uint32_t getEtherOffset(){ + BP_ASSERT(m_ether); + return (uint32_t)((uintptr_t) (((char *)m_ether)- getBasePtr()) ); + } + uint32_t getIpOffset(){ + if (l3.m_ipv4 != NULL) { + return (uint32_t)((uintptr_t)( ((char *)l3.m_ipv4)-getBasePtr()) ); + }else{ + BP_ASSERT(0); + } + } + + + /** + * return the application ipv4/ipv6 option offset + * if learn bit is ON , it is always the first options ( IPV6/IPV4) + * + * @return + */ + uint32_t getIpAppOptionOffset(){ + if ( is_ipv6() ) { + return ( getIpOffset()+IPv6Header::DefaultSize); + }else{ + return ( getIpOffset()+IPHeader::DefaultSize); + } + } + + uint32_t getTcpOffset(){ + BP_ASSERT(l4.m_tcp); + return (uint32_t)((uintptr_t) ((char *)l4.m_tcp-getBasePtr()) ); + } + uint32_t getPayloadOffset(){ + if (m_payload) { + return (uint32_t)((uintptr_t) ((char *)m_payload-getBasePtr()) ); + }else{ + return (0); + } + } + uint8_t getTTL(){ + BP_ASSERT(l3.m_ipv4); + if (is_ipv6()) { + return(l3.m_ipv6->getHopLimit()); + }else{ + return(l3.m_ipv4->getTimeToLive()); + } + } + void setTTL(uint8_t ttl){ + BP_ASSERT(l3.m_ipv4); + if (is_ipv6()) { + l3.m_ipv6->setHopLimit(ttl); + }else{ + l3.m_ipv4->setTimeToLive(ttl); + l3.m_ipv4->updateCheckSum(); + } + } + + + uint8_t getFastEtherOffset(void){ + return (m_ether_offset); + } + uint8_t getFastIpOffsetFast(void){ + return (m_ip_offset); + } + uint8_t getFastTcpOffset(void){ + return (m_udp_tcp_offset ); + } + uint8_t getFastPayloadOffset(void){ + return (m_payload_offset ); + } +private: + void SetKey(void); + uint8_t ProcessIpPacketProtocol(CCPacketParserCounters *m_cnt, + uint8_t protocol, int *offset); + void ProcessIpPacket(CPacketParser *parser,int offset); + void ProcessIpv6Packet(CPacketParser *parser,int offset); + void _ProcessPacket(CPacketParser *parser,CCapPktRaw * pkt); + + void UpdateOffsets(); +}; + + + +#define SRC_IP_BASE 0x10000001 +#define DST_IP_BASE 0x20000001 + +class CFlowTemplateGenerator { +public: + CFlowTemplateGenerator(uint64_t fid){ + src_ip_base=((SRC_IP_BASE + (uint32_t)fid )& 0x7fffffff); + dst_ip_base=((DST_IP_BASE + (uint32_t) ((fid & 0xffffffff00000000ULL)>>32)) & 0x7fffffff); + } +public: + uint32_t src_ip_base; + uint32_t dst_ip_base; +}; + + +class CPacketParser { + +public: + bool Create(); + void Delete(); + bool ProcessPacket(CPacketIndication * pkt_indication, + CCapPktRaw * raw_packet); +public: + CCPacketParserCounters m_counter; +public: + void Dump(FILE *fd); +}; + + +class CFlowTableStats { +public: + uint64_t m_lookup; + uint64_t m_found; + uint64_t m_fif; + uint64_t m_add; + uint64_t m_remove; + uint64_t m_fif_err; + uint64_t m_active; +public: + void Clear(); + void Dump(FILE *fd); +}; + + + +class CFlow { +public: + CFlow(){ + is_fif_swap=0; + pkt_id=0; + } + ~CFlow(){ + } +public: + void Dump(FILE *fd); +public: + uint8_t is_fif_swap; + uint32_t pkt_id; + uint32_t flow_id; +}; + +class CFlowTableInterator { +public: + virtual void do_flow(CFlow *flow)=0; +}; + +class CFlowTableManagerBase { +public: + virtual bool Create(int max_size)=0; + virtual void Delete()=0; +public: + CFlow * process(CFlowKey & key,bool &is_fif ); + virtual void remove(CFlowKey & key )=0; + virtual void remove_all()=0; + virtual uint64_t count()=0; +public: + void Dump(FILE *fd); +protected: + virtual CFlow * lookup(CFlowKey & key )=0; + virtual CFlow * add(CFlowKey & key )=0; + + //virtual IterateFlows(CFlowTableInterator * iter)=0; +protected: + CFlowTableStats m_stats; +}; + + + +typedef CFlow * flow_ptr; +typedef std::map > flow_map_t; +typedef flow_map_t::iterator flow_map_iter_t; + + +class CFlowTableMap : public CFlowTableManagerBase { +public: + virtual bool Create(int max_size); + virtual void Delete(); + virtual void remove(CFlowKey & key ); + +protected: + virtual CFlow * lookup(CFlowKey & key ); + virtual CFlow * add(CFlowKey & key ); + virtual void remove_all(void); + uint64_t count(void); +private: + flow_map_t m_map; +}; + +class CFlowInfo { +public: + uint32_t client_ip; + uint32_t server_ip; + uint32_t client_port; + uint32_t server_port; + bool is_init_ip_dir; + bool is_init_port_dir; + + bool replace_server_port; + CMiniVMCmdBase ** vm_program;/* pointer to vm program */ +}; + +class CFlowPktInfo { +public: + bool Create(CPacketIndication * pkt_ind); + void Delete(); + void Dump(FILE *fd); + inline void replace_tuple(CGenNode * node); + + /* generate a new packet */ + inline rte_mbuf_t * generate_new_mbuf(CGenNode * node); + inline rte_mbuf_t * do_generate_new_mbuf(CGenNode * node); + inline rte_mbuf_t * do_generate_new_mbuf_big(CGenNode * node); + + /* new packet with rx check info in IP option */ + void do_generate_new_mbuf_rxcheck(rte_mbuf_t * m, + CGenNode * node, + pkt_dir_t dir, + bool single_port); + + inline rte_mbuf_t * do_generate_new_mbuf_ex(CGenNode * node,CFlowInfo * flow_info); + inline rte_mbuf_t * do_generate_new_mbuf_ex_big(CGenNode * node,CFlowInfo * flow_info); + inline rte_mbuf_t * do_generate_new_mbuf_ex_vm(CGenNode * node, + CFlowInfo * flow_info, int16_t * s_size); + +public: + /* push the number of bytes into the packets and make more room + should be used by NAT feature that should have ipv4 option in the first packet + this function should not be called in runtime, only when template is loaded due to it heavey cost of operation ( malloc/free memory ) + */ + char * push_ipv4_option_offline(uint8_t bytes); + char * push_ipv6_option_offline(uint8_t bytes); + + + + /** + * mark this packet as learn packet + * should + * 1. push ipv4 option ( 8 bytes) + * 2. mask the packet as learn + * 3. update the option pointer + */ + void mask_as_learn(); + +private: + inline void append_big_mbuf(rte_mbuf_t * m, + CGenNode * node); + + inline void update_pkt_info(char *p, + CGenNode * node); + inline void update_pkt_info2(char *p, + CFlowInfo * flow_info, + int update_len, + CGenNode * node + ); + + void alloc_const_mbuf(); + + void free_const_mbuf(); + + rte_mbuf_t * get_big_mbuf(socket_id_t socket_id){ + return (m_big_mbuf[socket_id]); + } + + +public: + CPacketIndication m_pkt_indication; + CCapPktRaw * m_packet; + rte_mbuf_t * m_big_mbuf[MAX_SOCKETS_SUPPORTED]; /* allocate big mbug per socket */ +}; + + +inline void CFlowPktInfo::replace_tuple(CGenNode * node){ + update_pkt_info(m_packet->raw,node); +} + +inline void CFlowPktInfo::update_pkt_info2(char *p, + CFlowInfo * flow_info, + int update_len , + CGenNode * node + ){ + IPHeader * ipv4= + (IPHeader *)(p + m_pkt_indication.getFastIpOffsetFast()); + + EthernetHeader * et = + (EthernetHeader * )(p + m_pkt_indication.getFastEtherOffset()); + + if ( unlikely (m_pkt_indication.is_ipv6())) { + IPv6Header *ipv6= (IPv6Header *)ipv4; + + if ( update_len ){ + ipv6->setPayloadLen(ipv6->getPayloadLen() + update_len); + } + + if ( flow_info->is_init_ip_dir ) { + ipv6->updateLSBIpv6Src(flow_info->client_ip); + ipv6->updateLSBIpv6Dst(flow_info->server_ip); + }else{ + ipv6->updateLSBIpv6Src(flow_info->server_ip); + ipv6->updateLSBIpv6Dst(flow_info->client_ip); + } + + }else{ + if ( update_len ){ + ipv4->setTotalLength((ipv4->getTotalLength() + update_len)); + } + + if ( flow_info->is_init_ip_dir ) { + ipv4->setSourceIp(flow_info->client_ip); + ipv4->setDestIp(flow_info->server_ip); + }else{ + ipv4->setSourceIp(flow_info->server_ip); + ipv4->setDestIp(flow_info->client_ip); + } + ipv4->updateCheckSum(); + } + + + + /* replace port base on TCP/UDP */ + if ( m_pkt_indication.m_desc.IsTcp() ) { + TCPHeader * m_tcp = (TCPHeader *)(p +m_pkt_indication.getFastTcpOffset()); + BP_ASSERT(m_tcp); + /* replace port */ + if ( flow_info->is_init_port_dir ) { + m_tcp->setSourcePort(flow_info->client_port); + if ( flow_info->replace_server_port ){ + m_tcp->setDestPort(flow_info->server_port); + } + }else{ + m_tcp->setDestPort(flow_info->client_port); + if ( flow_info->replace_server_port ){ + m_tcp->setSourcePort(flow_info->server_port); + } + } + + }else { + if ( m_pkt_indication.m_desc.IsUdp() ){ + UDPHeader * m_udp =(UDPHeader *)(p +m_pkt_indication.getFastTcpOffset() ); + BP_ASSERT(m_udp); + m_udp->setLength(m_udp->getLength() + update_len); + m_udp->setChecksum(0); + if ( flow_info->is_init_port_dir ) { + m_udp->setSourcePort(flow_info->client_port); + if ( flow_info->replace_server_port ){ + m_udp->setDestPort(flow_info->server_port); + } + }else{ + m_udp->setDestPort(flow_info->client_port); + if ( flow_info->replace_server_port ){ + m_udp->setSourcePort(flow_info->server_port); + } + } + }else{ + BP_ASSERT(0); + } + } +} + + +inline void CFlowPktInfo::update_pkt_info(char *p, + CGenNode * node){ + + IPHeader * ipv4= + (IPHeader *)(p + m_pkt_indication.getFastIpOffsetFast()); + + EthernetHeader * et = + (EthernetHeader * )(p + m_pkt_indication.getFastEtherOffset()); + + uint16_t src_port = node->m_src_port; + + pkt_dir_t ip_dir = node->cur_pkt_ip_addr_dir(); + pkt_dir_t port_dir = node->cur_pkt_port_addr_dir(); + + + if ( unlikely (m_pkt_indication.is_ipv6())) { + + // Update the IPv6 address + IPv6Header *ipv6= (IPv6Header *)ipv4; + + if ( ip_dir == CLIENT_SIDE ) { + ipv6->updateLSBIpv6Src(node->m_src_ip); + ipv6->updateLSBIpv6Dst(node->m_dest_ip); + }else{ + ipv6->updateLSBIpv6Src(node->m_dest_ip); + ipv6->updateLSBIpv6Dst(node->m_src_ip); + } + }else{ + + if ( unlikely ( CGlobalInfo::is_learn_mode() ) ){ + + if (m_pkt_indication.m_desc.IsLearn()) { + /* might be done twice */ + #ifdef NAT_TRACE_ + printf(" %.3f : DP : learn packet !\n",now_sec()); + #endif + ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE); + + /* first ipv4 option add the info in case of learn packet, usualy only the first packet */ + CNatOption *lpNat =(CNatOption *)ipv4->getOption(); + lpNat->set_fid(node->get_short_fid()); + lpNat->set_thread_id(node->get_thread_id()); + lpNat->set_rx_check(node->is_rx_check_enabled()); + } + /* in call cases update the ip using the outside ip */ + + if ( m_pkt_indication.m_desc.IsInitSide() ) { + #ifdef NAT_TRACE_ + if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { + printf(" %.3f : DP : i %x:%x -> %x flow_id: %x\n",now_sec(),node->m_src_ip,node->m_src_port,node->m_dest_ip,node->m_flow_id); + } + #endif + + ipv4->updateIpSrc(node->m_src_ip); + ipv4->updateIpDst(node->m_dest_ip); + }else{ + #ifdef NAT_TRACE_ + if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { + printf(" %.3f : r %x -> %x:%x flow_id: %x \n",now_sec(),node->m_dest_ip,node->m_src_ip,node->m_src_port,node->m_flow_id); + } + #endif + src_port = node->get_nat_ipv4_port(); + ipv4->updateIpSrc(node->get_nat_ipv4_addr_server()); + ipv4->updateIpDst(node->get_nat_ipv4_addr()); + } + + /* TBD remove this */ + #ifdef NAT_TRACE_ + if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { + if ( m_pkt_indication.m_desc.IsInitSide() ==false ){ + printf(" %.3f : pkt ==> %x:%x %x:%x \n",now_sec(),node->get_nat_ipv4_addr(),node->get_nat_ipv4_addr_server(), + node->get_nat_ipv4_port(),node->m_src_port); + }else{ + printf(" %.3f : pkt ==> init pkt sent \n",now_sec()); + } + } + #endif + + + }else{ + if ( ip_dir == CLIENT_SIDE ) { + #ifdef NAT_TRACE_ + if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { + printf(" %.3f : i %x:%x -> %x \n",now_sec(),node->m_src_ip,node->m_src_port,node->m_dest_ip); + } + #endif + ipv4->updateIpSrc(node->m_src_ip); + ipv4->updateIpDst(node->m_dest_ip); + }else{ + #ifdef NAT_TRACE_ + if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) { + printf(" %.3f : r %x -> %x:%x \n",now_sec(),node->m_dest_ip,node->m_src_ip,node->m_src_port); + } + #endif + ipv4->updateIpSrc(node->m_dest_ip); + ipv4->updateIpDst(node->m_src_ip); + } + } + + ipv4->updateCheckSum(); + } + + + /* replace port base on TCP/UDP */ + if ( m_pkt_indication.m_desc.IsTcp() ) { + TCPHeader * m_tcp = (TCPHeader *)(p +m_pkt_indication.getFastTcpOffset()); + BP_ASSERT(m_tcp); + /* replace port */ + if ( port_dir == CLIENT_SIDE ) { + m_tcp->setSourcePort(src_port); + }else{ + m_tcp->setDestPort(src_port); + } + }else { + if ( m_pkt_indication.m_desc.IsUdp() ){ + UDPHeader * m_udp =(UDPHeader *)(p +m_pkt_indication.getFastTcpOffset() ); + BP_ASSERT(m_udp); + m_udp->setChecksum(0); + if ( port_dir == CLIENT_SIDE ) { + m_udp->setSourcePort(src_port); + }else{ + m_udp->setDestPort(src_port); + } + }else{ + BP_ASSERT(0); + } + } +} + + +inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_ex(CGenNode * node, + CFlowInfo * flow_info){ + rte_mbuf_t * m; + /* alloc small packet buffer*/ + m = CGlobalInfo::pktmbuf_alloc_small(node->get_socket_id()); + assert(m); + uint16_t len= ( m_packet->pkt_len > FIRST_PKT_SIZE) ?FIRST_PKT_SIZE:m_packet->pkt_len; + /* append*/ + char *p=rte_pktmbuf_append(m, len); + + BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ; + + memcpy(p,m_packet->raw,len); + + update_pkt_info2(p,flow_info,0,node); + + append_big_mbuf(m,node); + + return(m); +} + + +inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_ex_big(CGenNode * node, + CFlowInfo * flow_info){ + rte_mbuf_t * m; + uint16_t len = m_packet->pkt_len; + + /* alloc big buffer to update it*/ + m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), len); + assert(m); + + /* append*/ + char *p=rte_pktmbuf_append(m, len); + + BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ; + + memcpy(p,m_packet->raw,len); + + update_pkt_info2(p,flow_info,0,node); + + return(m); +} + + +inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_ex_vm(CGenNode * node, + CFlowInfo * flow_info, int16_t * s_size){ + rte_mbuf_t * m; + + /* sanity check we need to have payload */ + if ( unlikely( m_pkt_indication.m_payload_len == 0) ){ + printf(" ERROR nothing to do \n"); + return (do_generate_new_mbuf_ex(node,flow_info)); + } + + CMiniVMCmdBase ** cmds=flow_info->vm_program; + BP_ASSERT(cmds); + + /* packet is going to be changed update len with what we expect ( written in first command ) */ + uint16_t len = m_packet->pkt_len + cmds[0]->m_add_pkt_len; + + /* alloc big buffer to update it*/ + m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), len); + assert(m); + + /* append the additional bytes requested and update later */ + char *p=rte_pktmbuf_append(m, len); + + BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ; + + /* copy the headers until the payload */ + memcpy(p, m_packet->raw, m_pkt_indication.getPayloadOffset() ); + CMiniVM vm; + vm.m_pkt_info = this; + vm.m_pyload_mbuf_ptr = p+m_pkt_indication.getPayloadOffset(); + vm.mini_vm_run(cmds); + + /* need to update the mbuf size here .., this is not must but needed for accuracy */ + uint16_t buf_adjust = len - vm.m_new_pkt_size; + int rc = rte_pktmbuf_trim(m, buf_adjust); + + /* update IP length , and TCP checksum , we can accelerate this using hardware ! */ + uint16_t pkt_adjust = vm.m_new_pkt_size - m_packet->pkt_len; + update_pkt_info2(p,flow_info,pkt_adjust,node); + + /* return change in packet size due to packet tranforms */ + *s_size = vm.m_new_pkt_size - m_packet->pkt_len; + + //printf(" new length : actual %d , update:%d \n",m_packet->pkt_len,m_packet->pkt_len + vm.m_new_pkt_size); + return(m); +} + + +inline void CFlowPktInfo::append_big_mbuf(rte_mbuf_t * m, + CGenNode * node){ + + rte_mbuf_t * mbig= get_big_mbuf(node->get_socket_id()); + + if ( mbig == NULL) { + return ; + } + + utl_rte_pktmbuf_add_after(m,mbig); +} + + +inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf(CGenNode * node){ + rte_mbuf_t * m; + /* alloc small packet buffer*/ + m = CGlobalInfo::pktmbuf_alloc_small(node->get_socket_id()); + assert(m); + uint16_t len= ( m_packet->pkt_len > FIRST_PKT_SIZE) ?FIRST_PKT_SIZE:m_packet->pkt_len; + /* append*/ + char *p=rte_pktmbuf_append(m, len); + + BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ; + + memcpy(p,m_packet->raw,len); + + update_pkt_info(p,node); + + append_big_mbuf(m,node); + + return m; +} + + +inline rte_mbuf_t * CFlowPktInfo::do_generate_new_mbuf_big(CGenNode * node){ + rte_mbuf_t * m; + uint16_t len = m_packet->pkt_len; + + /* alloc big buffer to update it*/ + m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), len); + assert(m); + + /* append*/ + char *p=rte_pktmbuf_append(m, len); + + BP_ASSERT ( (((uintptr_t)m_packet->raw) & 0x7f )== 0) ; + + memcpy(p,m_packet->raw,len); + + update_pkt_info(p,node); + + return(m); +} + + +inline rte_mbuf_t * CFlowPktInfo::generate_new_mbuf(CGenNode * node){ + + if ( m_pkt_indication.m_desc.IsPluginEnable() ) { + return ( on_node_generate_mbuf( node->get_plugin_id(),node,this) ); + } + return (do_generate_new_mbuf(node)); +} + + + +typedef CFlowPktInfo * flow_pkt_info_t; + +class CCCapFileMemoryUsage { + +public: + + enum { SIZE_MIN = 64, + SIZE_64 = 64, + SIZE_128 = 128, + SIZE_256 = 256, + SIZE_512 = 512, + SIZE_1024 = 1024, + SIZE_2048 = 2048, + MASK_SIZE =6 + }; + + void clear(){ + int i; + for (i=0; i m_flow_pkts; + uint64_t m_total_bytes; + uint64_t m_total_flows; + uint64_t m_total_errors; +}; + + + +inline CFlowPktInfo * CCapFileFlowInfo::GetPacket(uint32_t index){ + BP_ASSERT(index m_src_ipv6; + std::vector m_dst_ipv6; + bool m_ipv6_set; + +// new section + bool m_cap_mode; + bool m_cap_mode_set; + + double m_cap_ipg_min; + bool m_cap_ipg_min_set; + + double m_cap_overide_ipg; + bool m_cap_overide_ipg_set; + + uint32_t m_wlength; + bool m_wlength_set; + + bool m_one_app_server; + bool m_one_app_server_was_set; + bool m_mac_replace_by_ip; + + CVlanYamlInfo m_vlan_info; + CTupleGenYamlInfo m_tuple_gen; + bool m_tuple_gen_was_set; + + + std::vector m_mac_base; + + std::vector m_vec; + + bool m_is_plugin_configured; /* any plugin is configured */ +public: + void Dump(FILE *fd); + int load_from_yaml_file(std::string file_name); + bool verify_correctness(uint32_t num_threads) ; + bool is_any_plugin_configured(){ + return ( m_is_plugin_configured); + } +}; + + + + +class CFlowStats { +public: + CFlowStats(){ + Clear(); + } + uint16_t m_id; + std::string m_name; + double m_pkt; + double m_bytes; + double duration_sec; + double m_cps; + double m_mb_sec; + double m_mB_sec; + double m_c_flows; + double m_pps ; + double m_total_Mbytes ; + uint64_t m_errors ; + uint64_t m_flows ; + CCCapFileMemoryUsage m_memory; + + /* normalized CPS by the number of flows */ + double get_normal_cps(){ + return ( m_cps*(double)m_flows ); + } +public: + void Clear(); + void Add(const CFlowStats & obj); + +public: + static void DumpHeader(FILE *fd); + void Dump(FILE *fd); +}; + + +class CFlowGeneratorRecPerThread { + +public: + bool Create(CTupleGeneratorSmart * global_gen, + CFlowYamlInfo * info, + CFlowsYamlInfo * yaml_flow_info, + CCapFileFlowInfo * flow_info, + uint16_t _id, + uint32_t thread_id ); + void Delete(); +public: + void Dump(FILE *fd); + inline void generate_flow(CNodeGenerator * gen, + dsec_t time, + uint64_t flow_id, + CGenNode * node); + void getFlowStats(CFlowStats * stats); + +public: + CTupleTemplateGeneratorSmart tuple_gen; + + CCapFileFlowInfo * m_flow_info; + CFlowYamlInfo * m_info; + CFlowsYamlInfo * m_flows_info; + CPolicer m_policer; + uint16_t m_id ; + uint32_t m_thread_id; +} __rte_cache_aligned; + + + + +class CFlowGeneratorRec { + +public: + bool Create(CFlowYamlInfo * info, + CFlowsYamlInfo * flow_info, + uint16_t _id); + void Delete(); +public: + + void Dump(FILE *fd); + void getFlowStats(CFlowStats * stats); +public: + CCapFileFlowInfo m_flow_info; + CFlowYamlInfo * m_info; + CFlowsYamlInfo * m_flows_info; + CPolicer m_policer; + uint16_t m_id; +private: + void fixup_ipg_if_needed(); +}; + +class CPPSMeasure { +public: + CPPSMeasure(){ + reset(); + } + //reset + void reset(void){ + m_start=false; + m_last_time_msec=0; + m_last_pkts=0; + m_last_result=0.0; + } + //add packet size + float add(uint64_t pkts); + +private: + float calc_pps(uint32_t dtime_msec, + uint32_t pkts){ + float rate=( ( (float)pkts*(float)os_get_time_freq())/((float)dtime_msec) ); + return (rate); + + } + +public: + bool m_start; + uint32_t m_last_time_msec; + uint64_t m_last_pkts; + float m_last_result; +}; + + + +class CBwMeasure { +public: + CBwMeasure(); + //reset + void reset(void); + //add packet size + double add(uint64_t size); + +private: + double calc_MBsec(uint32_t dtime_msec, + uint64_t dbytes); + +public: + bool m_start; + uint32_t m_last_time_msec; + uint64_t m_last_bytes; + double m_last_result; +}; + + +class CFlowGenList; + +typedef uint32_t flow_id_t; + + +class CTcpSeq { +public: + CTcpSeq (){ + client_seq_delta = 0; + server_seq_delta = 0; + server_seq_init=false; + }; + void update(uint8_t *p, CFlowPktInfo *pkt_info, int16_t s_size); +private: + uint32_t client_seq_delta; /* Delta to TCP seq number for client */ + uint32_t server_seq_delta; /* Delta to TCP seq number for server */ + bool server_seq_init; /* TCP seq been init for server? */ +}; + + +///////////////////////////////////////////////////////////////////////////////// +/* per thread info */ +class CFlowGenListPerThread { + +public: + friend class CNodeGenerator; + friend class CPluginCallbackSimple; + friend class CCapFileFlowInfo; + + typedef CGenericMap flow_id_node_t; + + bool Create(uint32_t thread_id, + uint32_t core_id, + CFlowGenList * flow_list, + uint32_t max_threads); + void Delete(); + + void set_vif(CVirtualIF * v_if){ + m_node_gen.set_vif(v_if); + } + + /* return the dual port ID this thread is attached to in 4 ports configuration + there are 2 dual-ports + + thread 0 - dual 0 + thread 1 - dual 1 + + thread 2 - dual 0 + thread 3 - dual 1 + + */ + uint32_t getDualPortId(); +public : + double get_total_kcps(); + double get_delta_flow_is_sec(); + double get_longest_flow(); + void inc_current_template(void); + int generate_flows_roundrobin(bool *done); + int reschedule_flow(CGenNode *node); + + + inline CGenNode * create_node(void); + inline void free_node(CGenNode *p); + inline void free_last_flow_node(CGenNode *p); + + +public: + void Clean(); + void generate_erf(std::string erf_file_name,CPreviewMode &preview); + void Dump(FILE *fd); + void DumpCsv(FILE *fd); + void DumpStats(FILE *fd); + void Update(void){ + m_cpu_cp_u.Update(); + } + double getCpuUtil(void){ + return ( m_cpu_cp_u.GetVal()); + } + +private: + void check_msgs(void); + void handel_nat_msg(CGenNodeNatInfo * msg); + void handel_latecy_pkt_msg(CGenNodeLatencyPktInfo * msg); + + void terminate_nat_flows(CGenNode *node); + + + void init_from_global(CClientPortion &); + void defer_client_port_free(CGenNode *p); + void defer_client_port_free(bool is_tcp,uint32_t c_ip,uint16_t port); + + + FORCE_NO_INLINE void handler_defer_job(CGenNode *p); + FORCE_NO_INLINE void handler_defer_job_flush(void); + + + inline CGenNodeDeferPort * get_tcp_defer(void){ + if (m_tcp_dpc==0) { + m_tcp_dpc =(CGenNodeDeferPort *)create_node(); + m_tcp_dpc->init(); + } + return (m_tcp_dpc); + } + + inline CGenNodeDeferPort * get_udp_defer(void){ + if (m_udp_dpc==0) { + m_udp_dpc =(CGenNodeDeferPort *)create_node(); + m_udp_dpc->init(); + } + return (m_udp_dpc); + } + +private: + FORCE_NO_INLINE void associate(uint32_t fid,CGenNode * node ){ + assert(m_flow_id_to_node_lookup.lookup(fid)==0); + m_stats.m_nat_lookup_add_flow_id++; + m_flow_id_to_node_lookup.add(fid,node); + } + +public: + uint32_t m_thread_id; /* virtual */ + uint32_t m_core_id; /* phsical */ + + uint32_t m_max_threads; + CFlowGenList * m_flow_list; + rte_mempool_t * m_node_pool; + + std::vector m_cap_gen; + + CFlowsYamlInfo m_yaml_info; + + CTupleGeneratorSmart m_smart_gen; + + +public: + CNodeGenerator m_node_gen; +public: + uint32_t m_cur_template; + uint64_t m_cur_flow_id; + double m_cur_time_sec; + double m_stop_time_sec; + + CPreviewMode m_preview_mode; +public: + CFlowGenStats m_stats; + CBwMeasure m_mb_sec; + CCpuUtlDp m_cpu_dp_u; + CCpuUtlCp m_cpu_cp_u; + +private: + CGenNodeDeferPort * m_tcp_dpc; + CGenNodeDeferPort * m_udp_dpc; + + CNodeRing * m_ring_from_rx; /* ring latency thread -> dp */ + CNodeRing * m_ring_to_rx; /* ring dp -> latency thread */ + + flow_id_node_t m_flow_id_to_node_lookup; +}; + +inline CGenNode * CFlowGenListPerThread::create_node(void){ + CGenNode * res; + if ( unlikely (rte_mempool_sc_get(m_node_pool, (void **)&res) <0) ){ + rte_exit(EXIT_FAILURE, "cant allocate object , need more \n"); + return (0); + } + return (res); +} + +inline void CFlowGenListPerThread::free_node(CGenNode *p){ + rte_mempool_sp_put(m_node_pool, p); +} + +inline void CFlowGenListPerThread::free_last_flow_node(CGenNode *p){ + m_stats.m_total_close_flows +=p->m_flow_info->get_total_flows(); + + uint8_t plugin_id =p->get_plugin_id(); + if ( plugin_id ) { + /* free memory of the plugin */ + on_node_last(plugin_id,p); + } + defer_client_port_free(p); + free_node( p); +} + + +typedef struct mac_mapping_ { + mac_addr_align_t mac; + uint32_t ip; +} mac_mapping_t; + +class CFlowGenList { + +public: + bool Create(); + void Delete(); + void Clean(); +public: + void generate_p_thread_info(uint32_t num_threads); + void clean_p_thread_info(void); + +public: + + int load_from_yaml(std::string csv_file,uint32_t num_threads); + int load_from_mac_file(std::string csv_file); +public: + void Dump(FILE *fd); + void DumpCsv(FILE *fd); + void DumpPktSize(); + void Update(); + double GetCpuUtil(); + +public: + double get_total_kcps(); + double get_total_pps(); + double get_total_tx_bps(); + uint32_t get_total_repeat_flows(); + bool is_ip_legal(uint32_t ip) { + return (ip >= m_yaml_info.m_tuple_gen.m_clients_ip_start && + ip <= m_yaml_info.m_tuple_gen.m_clients_ip_end ); + } + double get_delta_flow_is_sec(); +public: + std::vector m_cap_gen; /* global info */ + CFlowsYamlInfo m_yaml_info; /* global yaml*/ + std::vector m_threads_info; + bool is_mac_info_configured; + std::map m_mac_info; /* global mac info loaded form mac_file*/ +}; + + + + + + +inline void CCapFileFlowInfo::generate_flow(CTupleTemplateGeneratorSmart * tuple_gen, + CNodeGenerator * gen, + dsec_t time, + uint64_t flow_id, + CFlowYamlInfo * template_info, + CGenNode * node){ + dsec_t c_time = time; + + node->m_type=CGenNode::FLOW_PKT; + CTupleBase tuple; + tuple_gen->GenerateTuple(tuple); + + /* add the first packet of the flow */ + CFlowPktInfo * lp=GetPacket((uint32_t)0); + + node->set_socket_id(gen->m_socket_id); + + node->m_thread_id = tuple_gen->GetThreadId(); + node->m_flow_id = (flow_id & (0x000fffffffffffffULL)) | + ( ((uint64_t)(tuple_gen->GetThreadId()& 0xff)) <<56 ) ; + + node->m_time = c_time; + node->m_pkt_info = lp; + node->m_flow_info = this; + node->m_flags=0; + node->m_template_info =template_info; + node->m_src_ip= tuple.getClient(); + node->m_dest_ip = tuple.getServer(); + node->m_src_port = tuple.getClientPort(); + memcpy(&node->m_src_mac, + tuple.getClientMac(), + sizeof(mac_addr_align_t)); + node->m_plugin_info =(void *)0; + + if ( unlikely( CGlobalInfo::is_learn_mode() ) ){ + // check if flow is two direction + if ( lp->m_pkt_indication.m_desc.IsBiDirectionalFlow() ) { + /* we are in learn mode */ + CFlowGenListPerThread * lpThread=gen->Parent(); + lpThread->associate((uint32_t)flow_id,node); /* assosiate flow_id=>node */ + node->set_nat_first_state(); + } + } + + if ( unlikely( get_is_rx_check_mode()) ) { + if ( (CGlobalInfo::m_options.m_rx_check_sampe == 1 ) || + ( ( rte_rand() % CGlobalInfo::m_options.m_rx_check_sampe ) == 1 )){ + if (unlikely(!node->is_repeat_flow() )) { + node->set_rx_check(); + } + } + } + + if ( unlikely( CGlobalInfo::m_options.preview.getClientServerFlowFlipAddr() ) ){ + node->set_initiator_start_from_server_side_with_server_addr(node->is_eligible_from_server_side()); + }else{ + /* -p */ + if ( likely( CGlobalInfo::m_options.preview.getClientServerFlowFlip() ) ){ + node->set_initiator_start_from_server(node->is_eligible_from_server_side()); + node->set_all_flow_from_same_dir(true); + }else{ + /* --flip */ + if ( unlikely( CGlobalInfo::m_options.preview.getClientServerFlip() ) ){ + node->set_initiator_start_from_server(node->is_eligible_from_server_side()); + } + } + } + + + /* in case of plugin we need to call the callback */ + if ( template_info->m_plugin_id ) { + /* alloc the info , generate the ports */ + on_node_first(template_info->m_plugin_id,node,template_info,tuple_gen,gen->Parent() ); + } + + gen->add_node(node); +} + + +inline void CFlowGeneratorRecPerThread::generate_flow(CNodeGenerator * gen, + dsec_t time, + uint64_t flow_id, + CGenNode * node){ + + m_flow_info->generate_flow(&tuple_gen, + gen, + time, + flow_id, + m_info, + node); +} + + + +class CLatencyPktInfo { +public: + void Create(); + void Delete(); + void set_ip(uint32_t src, + uint32_t dst, + uint32_t dual_port_mask); + rte_mbuf_t * generate_pkt(int port_id,uint32_t extern_ip=0); + + CGenNode * getNode(){ + return (&m_dummy_node); + } + + uint16_t get_payload_offset(void){ + return ( m_pkt_indication.getFastPayloadOffset()); + } + + uint16_t get_pkt_size(void){ + return ( m_packet->pkt_len ); + } + +private: + ipaddr_t m_client_ip; + ipaddr_t m_server_ip; + uint32_t m_dual_port_mask; + + CGenNode m_dummy_node; + CFlowPktInfo m_pkt_info; + CPacketIndication m_pkt_indication; + CCapPktRaw * m_packet; +}; + + +#define LATENCY_MAGIC 0x12345600 + +struct latency_header { + + uint64_t time_stamp; + uint32_t magic; + uint32_t seq; + + uint8_t get_id(){ + return( magic & 0xff); + } +}; + + +class CSimplePacketParser { +public: + + CSimplePacketParser(rte_mbuf_t * m){ + m_m=m; + } + + bool Parse(); + uint8_t getTTl(); + uint16_t getPktSize(); + + + + inline bool IsLatencyPkt(){ + return ( (m_protocol ==0x84 )?true:false ); + } + + +public: + IPHeader * m_ipv4; + IPv6Header * m_ipv6; + uint8_t m_protocol; + uint16_t m_vlan_offset; + uint16_t m_option_offset; +private: + rte_mbuf_t * m_m ; +}; + + + +class CLatencyManager ; +// per port +class CCPortLatency { +public: + bool Create(CLatencyManager * parent, + uint8_t id, + uint16_t offset, + uint16_t pkt_size, + CCPortLatency * rx_port + ); + void Delete(); + void reset(); + bool can_send_packet(){ + if ( !CGlobalInfo::is_learn_mode() ) { + return(true); + } + return ( m_nat_can_send ); + } + uint32_t external_nat_ip(){ + return (m_nat_external_ip); + } + + void update_packet(rte_mbuf_t * m); + + bool do_learn(uint32_t external_ip); + + bool check_packet(rte_mbuf_t * m, + CRx_check_header * & rx_p); + bool check_rx_check(rte_mbuf_t * m); + + + bool dump_packet(rte_mbuf_t * m); + + void DumpCounters(FILE *fd); + void dump_counters_json(std::string & json ); + + void DumpShort(FILE *fd); + void dump_json(std::string & json ); + void dump_json_v2(std::string & json ); + + uint32_t get_jitter_usec(void){ + return ((uint32_t)(m_jitter.get_jitter()*1000000.0)); + } + + + static void DumpShortHeader(FILE *fd); + + bool is_any_err(){ + if ( (m_tx_pkt_ok == m_rx_port->m_pkt_ok ) && + + ((m_unsup_prot+ + m_no_magic+ + m_no_id+ + m_seq_error+ + m_length_error+m_no_ipv4_option+m_tx_pkt_err)==0) ) { + return (false); + } + return (true); + } + +private: + std::string get_field(std::string name,float f); + + + +private: + CLatencyManager * m_parent; + CCPortLatency * m_rx_port; /* corespond rx port */ + bool m_nat_learn; + bool m_nat_can_send; + uint32_t m_nat_external_ip; + + uint32_t m_tx_seq; + uint32_t m_rx_seq; + + uint8_t m_pad; + uint8_t m_id; + uint16_t m_offset; + + uint16_t m_pkt_size; + uint16_t pad1[3]; + +public: + uint64_t m_tx_pkt_ok; + uint64_t m_tx_pkt_err; + + uint64_t m_pkt_ok; + uint64_t m_unsup_prot; + uint64_t m_no_magic; + uint64_t m_no_id; + uint64_t m_seq_error; + uint64_t m_rx_check; + uint64_t m_no_ipv4_option; + + + uint64_t m_length_error; + CTimeHistogram m_hist; /* all window */ + CJitter m_jitter; +}; + + +class CPortLatencyHWBase { +public: + virtual int tx(rte_mbuf_t * m)=0; + virtual rte_mbuf_t * rx()=0; + virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, + uint16_t nb_pkts){ + return(0); + } +}; + + +class CLatencyManagerCfg { +public: + CLatencyManagerCfg (){ + m_max_ports=0; + m_cps=0.0; + m_client_ip.v4=0x10000000; + m_server_ip.v4=0x20000000; + m_dual_port_mask=0x01000000; + } + uint32_t m_max_ports; + double m_cps;// CPS + CPortLatencyHWBase * m_ports[MAX_LATENCY_PORTS]; + ipaddr_t m_client_ip; + ipaddr_t m_server_ip; + uint32_t m_dual_port_mask; + +}; + + + +class CLatencyManagerPerPort { +public: + CCPortLatency m_port; + CPortLatencyHWBase * m_io; + uint32_t m_flag; + +}; + + +class CLatencyManager { +public: + bool Create(CLatencyManagerCfg * cfg); + void Delete(); + +public: + void reset(); + void start(int iter); + void stop(); + bool is_active(); + + void set_ip(uint32_t client_ip, + uint32_t server_ip, + uint32_t mask_dual_port){ + m_pkt_gen.set_ip(client_ip,server_ip,mask_dual_port); + } + +public: + void Dump(FILE *fd); // dump all + void DumpShort(FILE *fd); // dump short histogram of latency + + void DumpRxCheck(FILE *fd); // dump all + void DumpShortRxCheck(FILE *fd); // dump short histogram of latency + void rx_check_dump_json(std::string & json); + uint16_t get_latency_header_offset(){ + return ( m_pkt_gen.get_payload_offset() ); + } + void update(); + void dump_json(std::string & json ); // dump to json + void dump_json_v2(std::string & json ); + + + + void DumpRxCheckVerification(FILE *fd,uint64_t total_tx_rx_check); + void set_mask(uint32_t mask){ + m_port_mask=mask; + } + + double get_max_latency(void); + double get_avr_latency(void); + bool is_any_error(); + uint64_t get_total_pkt(); + uint64_t get_total_bytes(); + CNatRxManager * get_nat_manager(){ + return ( &m_nat_check_manager ); + } + +private: + void send_pkt_all_ports(); + void try_rx(); + void try_rx_queues(); + void run_rx_queue_msgs(uint8_t thread_id, + CNodeRing * r); + void wait_for_rx_dump(); + void handle_rx_pkt(CLatencyManagerPerPort * lp, + rte_mbuf_t * m); + + +private: + /* messages handlers */ + void handle_latecy_pkt_msg(uint8_t thread_id, + CGenNodeLatencyPktInfo * msg); + + + +private: + pqueue_t m_p_queue; /* priorty queue */ + bool m_is_active; + CLatencyPktInfo m_pkt_gen; + CLatencyManagerPerPort m_ports[MAX_LATENCY_PORTS]; + uint64_t m_d_time; // calc tick betwen sending + double m_cps; + double m_delta_sec; + uint64_t m_start_time; // calc tick betwen sending + uint32_t m_port_mask; + uint32_t m_max_ports; + RxCheckManager m_rx_check_manager; + CNatRxManager m_nat_check_manager; + CCpuUtlDp m_cpu_dp_u; + CCpuUtlCp m_cpu_cp_u; + + volatile bool m_do_stop __rte_cache_aligned ; + +}; + + +inline bool CGenNode::is_responder_pkt(){ + return ( m_pkt_info->m_pkt_indication.m_desc.IsInitSide() ?false:true ); +} + +inline bool CGenNode::is_initiator_pkt(){ + return ( m_pkt_info->m_pkt_indication.m_desc.IsInitSide() ?true:false ); +} + + + +inline uint16_t CGenNode::get_template_id(){ + return ( m_pkt_info->m_pkt_indication.m_desc.getId() ); +} + + +inline bool CGenNode::is_last_in_flow(){ + return ( m_pkt_info->m_pkt_indication.m_desc.IsLastPkt()); +} + +inline bool CGenNode::is_repeat_flow(){ + return ( m_template_info->m_limit_was_set); +} + +inline void CGenNode::update_next_pkt_in_flow(void){ + if ( likely ( m_pkt_info->m_pkt_indication.m_desc.IsPcapTiming()) ){ + m_time += m_pkt_info->m_pkt_indication.m_cap_ipg ; + }else{ + if ( m_pkt_info->m_pkt_indication.m_desc.IsRtt() ){ + m_time += m_template_info->m_rtt_sec ; + }else{ + m_time += m_template_info->m_ipg_sec; + } + } + + uint32_t pkt_index = m_pkt_info->m_pkt_indication.m_packet->pkt_cnt; + pkt_index++; + m_pkt_info = m_flow_info->GetPacket((pkt_index-1)); +} + +inline void CGenNode::reset_pkt_in_flow(void){ + m_pkt_info = m_flow_info->GetPacket(0); +} + +inline void CGenNode::replace_tuple(void){ + m_pkt_info->replace_tuple(this); +} + +enum MINVM_PLUGIN_ID{ + mpRTSP=1, + mpSIP_VOICE=2, + mpDYN_PYLOAD=3, + mpAVL_HTTP_BROWSIN=4 /* this is a way to change the host ip by client ip */ +}; + +class CPluginCallback { +public: + virtual void on_node_first(uint8_t plugin_id,CGenNode * node,CFlowYamlInfo * template_info, CTupleTemplateGeneratorSmart * tuple_gen,CFlowGenListPerThread * flow_gen) =0; + virtual void on_node_last(uint8_t plugin_id,CGenNode * node)=0; + virtual rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info)=0; +public: + static CPluginCallback * callback; +}; + +class CPluginCallbackSimple : public CPluginCallback { +public: + virtual void on_node_first(uint8_t plugin_id,CGenNode * node, + CFlowYamlInfo * template_info, + CTupleTemplateGeneratorSmart * tuple_gen, + CFlowGenListPerThread * flow_gen); + virtual void on_node_last(uint8_t plugin_id,CGenNode * node); + virtual rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info); + +private: + rte_mbuf_t * rtsp_plugin(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info); + rte_mbuf_t * sip_voice_plugin(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info); + rte_mbuf_t * dyn_pyload_plugin(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info); + rte_mbuf_t * http_plugin(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info); + +}; + + +inline bool CGenNode::can_cache_mbuf(void){ + if ( is_repeat_flow() && ( m_flow_info->Size()==1 ) ){ + return (true); + }else{ + return (false); + } +} + + +/* direction for ip addr SERVER put tuple from server side client put addr of client side */ +inline pkt_dir_t CGenNode::cur_pkt_ip_addr_dir(){ + + CFlowPktInfo * lp=m_pkt_info; + bool init_from_server=get_is_initiator_start_from_server_with_server_addr(); + bool is_init=lp->m_pkt_indication.m_desc.IsInitSide() ^ init_from_server; + return ( is_init ?CLIENT_SIDE:SERVER_SIDE); +} + +/* direction for TCP/UDP port */ +inline pkt_dir_t CGenNode::cur_pkt_port_addr_dir(){ + CFlowPktInfo * lp=m_pkt_info; + bool is_init=lp->m_pkt_indication.m_desc.IsInitSide() ; + return ( is_init ?CLIENT_SIDE:SERVER_SIDE); +} +/* from which interface dir to get out */ +inline pkt_dir_t CGenNode::cur_interface_dir(){ + + CFlowPktInfo * lp=m_pkt_info; + + bool init_from_server=(get_is_initiator_start_from_server()|| + get_is_initiator_start_from_server_with_server_addr()); + bool is_init=lp->m_pkt_indication.m_desc.IsInitSide() ^ init_from_server; + + if (get_is_all_flow_from_same_dir()) { + return (is_eligible_from_server_side()?SERVER_SIDE:CLIENT_SIDE); + }else{ + return ( is_init ?CLIENT_SIDE:SERVER_SIDE); + } +} + + + +#endif -- cgit 1.2.3-korg