1ea0b6efcSimarom/*
2ea0b6efcSimarom Itay Marom
30e8c9ae6SHanoh Haim Hanoch Haim
4ea0b6efcSimarom Cisco Systems, Inc.
5ea0b6efcSimarom*/
6ea0b6efcSimarom
7ea0b6efcSimarom/*
81e93f5b1SIdo BarneaCopyright (c) 2015-2016 Cisco Systems, Inc.
9ea0b6efcSimarom
10ea0b6efcSimaromLicensed under the Apache License, Version 2.0 (the "License");
11ea0b6efcSimaromyou may not use this file except in compliance with the License.
12ea0b6efcSimaromYou may obtain a copy of the License at
13ea0b6efcSimarom
14ea0b6efcSimarom    http://www.apache.org/licenses/LICENSE-2.0
15ea0b6efcSimarom
16ea0b6efcSimaromUnless required by applicable law or agreed to in writing, software
17ea0b6efcSimaromdistributed under the License is distributed on an "AS IS" BASIS,
18ea0b6efcSimaromWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19ea0b6efcSimaromSee the License for the specific language governing permissions and
20ea0b6efcSimaromlimitations under the License.
21ea0b6efcSimarom*/
221e93f5b1SIdo Barnea#include "bp_sim.h"
231e93f5b1SIdo Barnea#include "trex_stateless_dp_core.h"
241e93f5b1SIdo Barnea#include "trex_stateless_messaging.h"
251e93f5b1SIdo Barnea#include "trex_stream.h"
261e93f5b1SIdo Barnea#include "trex_stream_node.h"
271e93f5b1SIdo Barnea#include "trex_streams_compiler.h"
288b4df272SHanoh Haim#include "mbuf.h"
290e8c9ae6SHanoh Haim
30b22e3ed1Simarom/**
31b22e3ed1Simarom * a wrapper for service mode
32b22e3ed1Simarom * it will move the fast send_node virtual call
33b22e3ed1Simarom * to send_node_service_mode which does capturing
34b22e3ed1Simarom *
35b22e3ed1Simarom */
36b22e3ed1Simaromclass ServiceModeWrapper : public CVirtualIF {
3717d58dbaSimarompublic:
38b22e3ed1Simarom
39b22e3ed1Simarom    ServiceModeWrapper() {
4017d58dbaSimarom        m_wrapped = nullptr;
4117d58dbaSimarom    }
4217d58dbaSimarom
4317d58dbaSimarom    void set_wrapped_object(CVirtualIF *wrapped) {
4417d58dbaSimarom        m_wrapped = wrapped;
4517d58dbaSimarom    }
4617d58dbaSimarom
4717d58dbaSimarom    CVirtualIF *get_wrapped_object() const {
4817d58dbaSimarom        return m_wrapped;
4917d58dbaSimarom    }
5017d58dbaSimarom
5117d58dbaSimarom    virtual int close_file(void) {
5217d58dbaSimarom        return m_wrapped->close_file();
5317d58dbaSimarom    }
5417d58dbaSimarom
5517d58dbaSimarom    virtual int flush_tx_queue(void) {
5617d58dbaSimarom        return m_wrapped->flush_tx_queue();
5717d58dbaSimarom    }
5817d58dbaSimarom
5917d58dbaSimarom    virtual int open_file(std::string file_name) {
6017d58dbaSimarom        return m_wrapped->open_file(file_name);
6117d58dbaSimarom    }
6217d58dbaSimarom
6317d58dbaSimarom    /* move to service mode */
6417d58dbaSimarom    virtual int send_node(CGenNode *node) {
6517d58dbaSimarom        return m_wrapped->send_node_service_mode(node);
6617d58dbaSimarom    }
6717d58dbaSimarom
6817d58dbaSimarom    virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t *p) {
6917d58dbaSimarom        return m_wrapped->update_mac_addr_from_global_cfg(dir, p);
7017d58dbaSimarom    }
7117d58dbaSimarom
7217d58dbaSimarom    virtual pkt_dir_t port_id_to_dir(uint8_t port_id) {
7317d58dbaSimarom        return m_wrapped->port_id_to_dir(port_id);
7417d58dbaSimarom    }
7517d58dbaSimarom
7617d58dbaSimarom    virtual void send_one_pkt(pkt_dir_t dir, rte_mbuf_t *m) {
7717d58dbaSimarom        m_wrapped->send_one_pkt(dir, m);
7817d58dbaSimarom    }
7917d58dbaSimarom
8017d58dbaSimaromprivate:
8117d58dbaSimarom    CVirtualIF *m_wrapped;
8217d58dbaSimarom};
83c2912dfcSHanoh Haim
84c2912dfcSHanoh Haim
85c2912dfcSHanoh Haimvoid CGenNodeStateless::cache_mbuf_array_init(){
86c2912dfcSHanoh Haim    m_cache_size=0;
87c2912dfcSHanoh Haim    m_cache_array_cnt=0;
88c2912dfcSHanoh Haim}
89c2912dfcSHanoh Haim
90c2912dfcSHanoh Haim
918b4df272SHanoh Haim
928b4df272SHanoh Haimvoid CGenNodeStateless::cache_mbuf_array_copy(CGenNodeCacheMbuf *obj,
938b4df272SHanoh Haim                                              uint16_t size){
948b4df272SHanoh Haim
958b4df272SHanoh Haim    int i;
968b4df272SHanoh Haim    cache_mbuf_array_alloc(size);
978b4df272SHanoh Haim    for (i=0; i<size; i++) {
988b4df272SHanoh Haim        cache_mbuf_array_set(i,obj->m_array[i]);
998b4df272SHanoh Haim    }
1008b4df272SHanoh Haim    cache_mbuf_array_set_const_mbuf(obj->m_mbuf_const);
1018b4df272SHanoh Haim}
1028b4df272SHanoh Haim
103c2912dfcSHanoh Haim
104c2912dfcSHanoh Haimrte_mbuf_t ** CGenNodeStateless::cache_mbuf_array_alloc(uint16_t size){
105c2912dfcSHanoh Haim
106c2912dfcSHanoh Haim    uint32_t buf_size = CGenNodeCacheMbuf::get_object_size(size);
107c2912dfcSHanoh Haim    /* TBD  replace with align, zero API */
108c2912dfcSHanoh Haim    m_cache_mbuf = (void *)malloc(buf_size);
109c2912dfcSHanoh Haim    assert(m_cache_mbuf);
110c2912dfcSHanoh Haim    memset(m_cache_mbuf,0,buf_size);
111c2912dfcSHanoh Haim
112c2912dfcSHanoh Haim    m_flags |= SL_NODE_CONST_MBUF_CACHE_ARRAY;
113c2912dfcSHanoh Haim    m_cache_size=size;
114c2912dfcSHanoh Haim    m_cache_array_cnt=0;
115c2912dfcSHanoh Haim    return ((rte_mbuf_t **)m_cache_mbuf);
116c2912dfcSHanoh Haim}
117c2912dfcSHanoh Haim
118c2912dfcSHanoh Haimvoid CGenNodeStateless::cache_mbuf_array_free(){
119c2912dfcSHanoh Haim
120c2912dfcSHanoh Haim    assert(m_cache_mbuf);
121c2912dfcSHanoh Haim    int i;
122c2912dfcSHanoh Haim    for (i=0; i<(int)m_cache_size; i++) {
123c2912dfcSHanoh Haim        rte_mbuf_t * m=cache_mbuf_array_get((uint16_t)i);
124c2912dfcSHanoh Haim        assert(m);
125c2912dfcSHanoh Haim        rte_pktmbuf_free(m);
126c2912dfcSHanoh Haim    }
127c2912dfcSHanoh Haim
128c2912dfcSHanoh Haim    /* free the const */
129c2912dfcSHanoh Haim    rte_mbuf_t * m=cache_mbuf_array_get_const_mbuf() ;
130c2912dfcSHanoh Haim    if (m) {
131c2912dfcSHanoh Haim        rte_pktmbuf_free(m);
132c2912dfcSHanoh Haim    }
133c2912dfcSHanoh Haim
134c2912dfcSHanoh Haim    free(m_cache_mbuf);
135c2912dfcSHanoh Haim    m_cache_mbuf=0;
136c2912dfcSHanoh Haim}
137c2912dfcSHanoh Haim
138c2912dfcSHanoh Haim
139c2912dfcSHanoh Haimrte_mbuf_t * CGenNodeStateless::cache_mbuf_array_get(uint16_t index){
140c2912dfcSHanoh Haim
141c2912dfcSHanoh Haim    CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
142c2912dfcSHanoh Haim    return (p->m_array[index]);
143c2912dfcSHanoh Haim}
144c2912dfcSHanoh Haim
145c2912dfcSHanoh Haimvoid CGenNodeStateless::cache_mbuf_array_set_const_mbuf(rte_mbuf_t * m){
146c2912dfcSHanoh Haim    CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
147c2912dfcSHanoh Haim    p->m_mbuf_const=m;
148c2912dfcSHanoh Haim}
149c2912dfcSHanoh Haim
150c2912dfcSHanoh Haimrte_mbuf_t * CGenNodeStateless::cache_mbuf_array_get_const_mbuf(){
151c2912dfcSHanoh Haim    CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
152c2912dfcSHanoh Haim    return (p->m_mbuf_const);
153c2912dfcSHanoh Haim}
154c2912dfcSHanoh Haim
155c2912dfcSHanoh Haim
156c2912dfcSHanoh Haimvoid CGenNodeStateless::cache_mbuf_array_set(uint16_t index,
157c2912dfcSHanoh Haim                                             rte_mbuf_t * m){
158c2912dfcSHanoh Haim    CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
159c2912dfcSHanoh Haim    p->m_array[index]=m;
160c2912dfcSHanoh Haim}
161c2912dfcSHanoh Haim
162c2912dfcSHanoh Haim
1630e8c9ae6SHanoh Haimvoid CDpOneStream::Delete(CFlowGenListPerThread   * core){
1640e8c9ae6SHanoh Haim    assert(m_node->get_state() == CGenNodeStateless::ss_INACTIVE);
1650e8c9ae6SHanoh Haim    core->free_node((CGenNode *)m_node);
1660e8c9ae6SHanoh Haim    delete m_dp_stream;
1670e8c9ae6SHanoh Haim    m_node=0;
1680e8c9ae6SHanoh Haim    m_dp_stream=0;
1690e8c9ae6SHanoh Haim}
1700e8c9ae6SHanoh Haim
1710e8c9ae6SHanoh Haimvoid CDpOneStream::DeleteOnlyStream(){
1720e8c9ae6SHanoh Haim    assert(m_dp_stream);
1730e8c9ae6SHanoh Haim    delete m_dp_stream;
1740e8c9ae6SHanoh Haim    m_dp_stream=0;
1750e8c9ae6SHanoh Haim}
1760e8c9ae6SHanoh Haim
1770e8c9ae6SHanoh Haimint CGenNodeStateless::get_stream_id(){
1780e8c9ae6SHanoh Haim    if (m_state ==CGenNodeStateless::ss_FREE_RESUSE) {
1790e8c9ae6SHanoh Haim        return (-1); // not valid
1800e8c9ae6SHanoh Haim    }
1810e8c9ae6SHanoh Haim    assert(m_ref_stream_info);
1820e8c9ae6SHanoh Haim    return ((int)m_ref_stream_info->m_stream_id);
1830e8c9ae6SHanoh Haim}
1840e8c9ae6SHanoh Haim
1850e8c9ae6SHanoh Haim
1860e8c9ae6SHanoh Haimvoid CGenNodeStateless::DumpHeader(FILE *fd){
1870e8c9ae6SHanoh Haim    fprintf(fd," pkt_id, time, port , action , state, stream_id , stype , m-burst# , burst# \n");
1880e8c9ae6SHanoh Haim
1890e8c9ae6SHanoh Haim}
1900e8c9ae6SHanoh Haimvoid CGenNodeStateless::Dump(FILE *fd){
1910e8c9ae6SHanoh Haim    fprintf(fd," %2.4f, %3lu, %s,%s, %3d, %s, %3lu, %3lu  \n",
1920e8c9ae6SHanoh Haim            m_time,
1930e8c9ae6SHanoh Haim            (ulong)m_port_id,
1940e8c9ae6SHanoh Haim            "s-pkt", //action
1950e8c9ae6SHanoh Haim            get_stream_state_str(m_state ).c_str(),
1960e8c9ae6SHanoh Haim            get_stream_id(),   //stream_id
1970e8c9ae6SHanoh Haim            TrexStream::get_stream_type_str(m_stream_type).c_str(), //stype
1980e8c9ae6SHanoh Haim            (ulong)m_multi_bursts,
1990e8c9ae6SHanoh Haim            (ulong)m_single_burst
2000e8c9ae6SHanoh Haim            );
2010e8c9ae6SHanoh Haim}
2020e8c9ae6SHanoh Haim
2030e8c9ae6SHanoh Haim
204e946a09eSimaromvoid CGenNodeStateless::generate_random_seed() {
205e946a09eSimarom    /* seed can be provided by the user */
206e946a09eSimarom    uint32_t unique_seed;
207e946a09eSimarom    if (m_ref_stream_info->m_random_seed) {
208e946a09eSimarom        unique_seed = m_ref_stream_info->m_random_seed;
209e946a09eSimarom    } else {
210e946a09eSimarom        unsigned int tmp = (unsigned int)time(NULL);
211e946a09eSimarom        unique_seed = rand_r(&tmp);
212e946a09eSimarom    }
213e946a09eSimarom
214e946a09eSimarom    /* per thread divergence */
215e946a09eSimarom    unique_seed = (unique_seed * ( (m_thread_id + 1) * 514229 ) ) & 0xFFFFFFFF;
216e946a09eSimarom
217e946a09eSimarom    /* set random */
218e946a09eSimarom    set_random_seed(unique_seed);
219e946a09eSimarom}
22032bdea5fSHanoh Haim
221e946a09eSimarom
222e946a09eSimaromvoid CGenNodeStateless::refresh_vm_bss() {
22332bdea5fSHanoh Haim    if ( m_vm_flow_var ) {
22432bdea5fSHanoh Haim        StreamVmDp  * vm_s=m_ref_stream_info->m_vm_dp;
22532bdea5fSHanoh Haim        assert(vm_s);
22632bdea5fSHanoh Haim        memcpy(m_vm_flow_var,vm_s->get_bss(),vm_s->get_bss_size());
2274ae35508SHanoh Haim
228e946a09eSimarom        if ( vm_s->is_random_seed() ) {
229e946a09eSimarom            generate_random_seed();
2304ae35508SHanoh Haim        }
231e946a09eSimarom
23232bdea5fSHanoh Haim    }
23332bdea5fSHanoh Haim}
23432bdea5fSHanoh Haim
23532bdea5fSHanoh Haim
236e946a09eSimarom
2370e3021bbSHanoh Haim/**
2380e3021bbSHanoh Haim * this function called when stream restart after it was inactive
2390e3021bbSHanoh Haim */
2400e8c9ae6SHanoh Haimvoid CGenNodeStateless::refresh(){
2410e8c9ae6SHanoh Haim
2420e8c9ae6SHanoh Haim    /* refill the stream info */
2430e8c9ae6SHanoh Haim    m_single_burst    = m_single_burst_refill;
2440e8c9ae6SHanoh Haim    m_multi_bursts    = m_ref_stream_info->m_num_bursts;
2450e8c9ae6SHanoh Haim    m_state           = CGenNodeStateless::ss_ACTIVE;
24632bdea5fSHanoh Haim
24732bdea5fSHanoh Haim    /* refresh init value */
24803d70c42SIdo Barnea#if 0
24932bdea5fSHanoh Haim    /* TBD should add a JSON varible for that */
25032bdea5fSHanoh Haim    refresh_vm_bss();
25132bdea5fSHanoh Haim#endif
2520e8c9ae6SHanoh Haim}
2530e8c9ae6SHanoh Haim
2540e8c9ae6SHanoh Haim
2550e8c9ae6SHanoh Haimvoid CGenNodeCommand::free_command(){
25603d70c42SIdo Barnea
2570e8c9ae6SHanoh Haim    assert(m_cmd);
2583408c030SHanoh Haim    m_cmd->on_node_remove();
2590e8c9ae6SHanoh Haim    delete m_cmd;
260c0a49eefSimarom}
261c0a49eefSimarom
262bc7d9ee8Simarom
2630e8c9ae6SHanoh Haimstd::string CGenNodeStateless::get_stream_state_str(stream_state_t stream_state){
2640e8c9ae6SHanoh Haim    std::string res;
2650e8c9ae6SHanoh Haim
2660e8c9ae6SHanoh Haim    switch (stream_state) {
2670e8c9ae6SHanoh Haim    case CGenNodeStateless::ss_FREE_RESUSE :
2680e8c9ae6SHanoh Haim         res="FREE    ";
2690e8c9ae6SHanoh Haim        break;
2700e8c9ae6SHanoh Haim    case CGenNodeStateless::ss_INACTIVE :
2710e8c9ae6SHanoh Haim        res="INACTIVE ";
2720e8c9ae6SHanoh Haim        break;
2730e8c9ae6SHanoh Haim    case CGenNodeStateless::ss_ACTIVE :
2740e8c9ae6SHanoh Haim        res="ACTIVE   ";
2750e8c9ae6SHanoh Haim        break;
2760e8c9ae6SHanoh Haim    default:
2770e8c9ae6SHanoh Haim        res="Unknow   ";
2780e8c9ae6SHanoh Haim    };
2790e8c9ae6SHanoh Haim    return(res);
2800e8c9ae6SHanoh Haim}
2810e8c9ae6SHanoh Haim
28203d70c42SIdo Barnea/*
28303d70c42SIdo Barnea * Allocate mbuf for flow stat (and latency) info sending
28403d70c42SIdo Barnea * m - Original mbuf (can be complicated mbuf data structure)
28503d70c42SIdo Barnea * fsp_head - return pointer in which the flow stat info should be filled
28603d70c42SIdo Barnea * is_const - is the given mbuf const
28703d70c42SIdo Barnea * return new mbuf structure in which the fsp_head can be written. If needed, orginal mbuf is freed.
28803d70c42SIdo Barnea */
28903d70c42SIdo Barnearte_mbuf_t * CGenNodeStateless::alloc_flow_stat_mbuf(rte_mbuf_t *m, struct flow_stat_payload_header *&fsp_head
29003d70c42SIdo Barnea                                                     , bool is_const) {
29103d70c42SIdo Barnea    rte_mbuf_t *m_ret = NULL, *m_lat = NULL;
29203d70c42SIdo Barnea    uint16_t fsp_head_size = sizeof(struct flow_stat_payload_header);
29303d70c42SIdo Barnea
29403d70c42SIdo Barnea    if (is_const) {
29503d70c42SIdo Barnea        // const mbuf case
29603d70c42SIdo Barnea        if (rte_pktmbuf_data_len(m) > 128) {
29703d70c42SIdo Barnea            m_ret = CGlobalInfo::pktmbuf_alloc_small(get_socket_id());
29803d70c42SIdo Barnea            assert(m_ret);
29903d70c42SIdo Barnea            // alloc mbuf just for the latency header
30003d70c42SIdo Barnea            m_lat = CGlobalInfo::pktmbuf_alloc( get_socket_id(), fsp_head_size);
30103d70c42SIdo Barnea            assert(m_lat);
30203d70c42SIdo Barnea            fsp_head = (struct flow_stat_payload_header *)rte_pktmbuf_append(m_lat, fsp_head_size);
30303d70c42SIdo Barnea            rte_pktmbuf_attach(m_ret, m);
30403d70c42SIdo Barnea            rte_pktmbuf_trim(m_ret, sizeof(struct flow_stat_payload_header));
30503d70c42SIdo Barnea            utl_rte_pktmbuf_add_after2(m_ret, m_lat);
306131be7a0SIdo Barnea            // ref count was updated when we took the (const) mbuf, and again in rte_pktmbuf_attach
307131be7a0SIdo Barnea            // so need do decrease now, to avoid leak.
308131be7a0SIdo Barnea            rte_pktmbuf_refcnt_update(m, -1);
30903d70c42SIdo Barnea            return m_ret;
31003d70c42SIdo Barnea        } else {
31103d70c42SIdo Barnea            // Short packet. Just copy all bytes.
31203d70c42SIdo Barnea            m_ret = CGlobalInfo::pktmbuf_alloc( get_socket_id(), rte_pktmbuf_data_len(m) );
31303d70c42SIdo Barnea            assert(m_ret);
31403d70c42SIdo Barnea            char *p = rte_pktmbuf_mtod(m, char*);
31503d70c42SIdo Barnea            char *p_new = rte_pktmbuf_append(m_ret, rte_pktmbuf_data_len(m));
31603d70c42SIdo Barnea            memcpy(p_new , p, rte_pktmbuf_data_len(m));
31703d70c42SIdo Barnea            fsp_head = (struct flow_stat_payload_header *)(p_new + rte_pktmbuf_data_len(m) - fsp_head_size);
31803d70c42SIdo Barnea            rte_pktmbuf_free(m);
31903d70c42SIdo Barnea            return m_ret;
32003d70c42SIdo Barnea        }
32103d70c42SIdo Barnea    } else {
32203d70c42SIdo Barnea        // Field engine (vm)
32303d70c42SIdo Barnea        if (rte_pktmbuf_is_contiguous(m)) {
32403d70c42SIdo Barnea            // one, r/w mbuf
32503d70c42SIdo Barnea            char *p = rte_pktmbuf_mtod(m, char*);
32603d70c42SIdo Barnea            fsp_head = (struct flow_stat_payload_header *)(p + rte_pktmbuf_data_len(m) - fsp_head_size);
32703d70c42SIdo Barnea            return m;
32803d70c42SIdo Barnea        } else {
329d49f3784SIdo Barnea            // We have: r/w --> read only.
330d49f3784SIdo Barnea            // Changing to:
331d49f3784SIdo Barnea            // (original) r/w -> (new) indirect (direct is original read_only, after trimming last bytes) -> (new) latency info
332d49f3784SIdo Barnea            rte_mbuf_t *m_read_only = m->next, *m_indirect;
333d49f3784SIdo Barnea
334d49f3784SIdo Barnea            m_indirect = CGlobalInfo::pktmbuf_alloc_small(get_socket_id());
335d49f3784SIdo Barnea            assert(m_indirect);
336d49f3784SIdo Barnea            // alloc mbuf just for the latency header
337d49f3784SIdo Barnea            m_lat = CGlobalInfo::pktmbuf_alloc( get_socket_id(), fsp_head_size);
338d49f3784SIdo Barnea            assert(m_lat);
339d49f3784SIdo Barnea            fsp_head = (struct flow_stat_payload_header *)rte_pktmbuf_append(m_lat, fsp_head_size);
340d49f3784SIdo Barnea            utl_rte_pktmbuf_chain_with_indirect(m, m_indirect, m_read_only, m_lat);
341d49f3784SIdo Barnea            m_indirect->data_len = (uint16_t)(m_indirect->data_len - fsp_head_size);
342d49f3784SIdo Barnea            return m;
34303d70c42SIdo Barnea        }
34403d70c42SIdo Barnea    }
34503d70c42SIdo Barnea}
346a53f6be0SIdo Barnea
34703d70c42SIdo Barnea// test the const case of alloc_flow_stat_mbuf. The more complicated non const case is tested in the simulation.
34803d70c42SIdo Barneabool CGenNodeStateless::alloc_flow_stat_mbuf_test_const() {
34903d70c42SIdo Barnea    rte_mbuf_t *m, *m_test;
35003d70c42SIdo Barnea    uint16_t sizes[2] = {64, 500};
35103d70c42SIdo Barnea    uint16_t size;
35203d70c42SIdo Barnea    struct flow_stat_payload_header *fsp_head;
35303d70c42SIdo Barnea    char *p;
35403d70c42SIdo Barnea
35503d70c42SIdo Barnea    set_socket_id(0);
35603d70c42SIdo Barnea    for (int test_num = 0; test_num < sizeof(sizes)/sizeof(sizes[0]); test_num++) {
35703d70c42SIdo Barnea        size = sizes[test_num];
35803d70c42SIdo Barnea        m = CGlobalInfo::pktmbuf_alloc(get_socket_id(), size);
35903d70c42SIdo Barnea        p = rte_pktmbuf_append(m, size);
36003d70c42SIdo Barnea        for (int i = 0; i < size; i++) {
36103d70c42SIdo Barnea            p[i] = (char)i;
36203d70c42SIdo Barnea        }
36303d70c42SIdo Barnea        m_test = alloc_flow_stat_mbuf(m, fsp_head, true);
36403d70c42SIdo Barnea        p = rte_pktmbuf_mtod(m_test, char*);
36503d70c42SIdo Barnea        assert(rte_pktmbuf_pkt_len(m_test) == size);
36603d70c42SIdo Barnea        for (int i = 0; i < rte_pktmbuf_pkt_len(m_test) - sizeof(*fsp_head); i++) {
36703d70c42SIdo Barnea            assert(p[i] == (char)i);
36803d70c42SIdo Barnea        }
36903d70c42SIdo Barnea        // verify fsp_head points correctly
37003d70c42SIdo Barnea        if (size > 128) { // should match threshould in alloc_flow_stat_mbuf
37103d70c42SIdo Barnea            assert(rte_pktmbuf_data_len(m_test) == size - sizeof(*fsp_head));
37203d70c42SIdo Barnea            assert(rte_pktmbuf_data_len(m_test->next) == sizeof(*fsp_head));
37303d70c42SIdo Barnea            assert((char *)fsp_head == rte_pktmbuf_mtod((m_test->next), char*));
37403d70c42SIdo Barnea        } else {
37503d70c42SIdo Barnea            assert(rte_pktmbuf_data_len(m_test) == size);
37603d70c42SIdo Barnea            assert (((char *)fsp_head) + sizeof (*fsp_head) == p + rte_pktmbuf_data_len(m_test));
37703d70c42SIdo Barnea        }
37803d70c42SIdo Barnea        rte_pktmbuf_free(m_test);
37903d70c42SIdo Barnea    }
38003d70c42SIdo Barnea    return true;
381a53f6be0SIdo Barnea}
382cc352e04SHanoh Haim
3832e51cea3SHanoh Haimrte_mbuf_t   * CGenNodeStateless::alloc_node_with_vm(){
3842e51cea3SHanoh Haim
3852e51cea3SHanoh Haim    rte_mbuf_t        * m;
3862e51cea3SHanoh Haim    /* alloc small packet buffer*/
3872e51cea3SHanoh Haim    uint16_t prefix_size = prefix_header_size();
3882e51cea3SHanoh Haim    m = CGlobalInfo::pktmbuf_alloc( get_socket_id(), prefix_size );
3892e51cea3SHanoh Haim    if (m==0) {
3902e51cea3SHanoh Haim        return (m);
3912e51cea3SHanoh Haim    }
3922e51cea3SHanoh Haim    /* TBD remove this, should handle cases of error */
3932e51cea3SHanoh Haim    assert(m);
3942e51cea3SHanoh Haim    char *p=rte_pktmbuf_append(m, prefix_size);
39503d70c42SIdo Barnea    memcpy( p ,m_original_packet_data_prefix, prefix_size);
3962e51cea3SHanoh Haim
397e7ffce7bSHanoh Haim
398e7ffce7bSHanoh Haim    /* run the VM program */
399e7ffce7bSHanoh Haim    StreamDPVmInstructionsRunner runner;
4004f91be3fSHanoh Haim    runner.set_mbuf(m);
401e7ffce7bSHanoh Haim
4020e3021bbSHanoh Haim    runner.run( (uint32_t*)m_vm_flow_var,
40303d70c42SIdo Barnea                m_vm_program_size,
404e7ffce7bSHanoh Haim                m_vm_program,
405e7ffce7bSHanoh Haim                m_vm_flow_var,
406e7ffce7bSHanoh Haim                (uint8_t*)p);
407e7ffce7bSHanoh Haim
408a1364603SHanoh Haim    uint16_t pkt_new_size=runner.get_new_pkt_size();
409a1364603SHanoh Haim    if ( likely( pkt_new_size == 0) ) {
410a1364603SHanoh Haim        /* no packet size change */
411a1364603SHanoh Haim        rte_mbuf_t * m_const = get_const_mbuf();
412a1364603SHanoh Haim        if (  m_const != NULL) {
413a1364603SHanoh Haim            utl_rte_pktmbuf_add_after(m,m_const);
414a1364603SHanoh Haim        }
415a1364603SHanoh Haim        return (m);
416a1364603SHanoh Haim    }
4172e51cea3SHanoh Haim
418a1364603SHanoh Haim    /* packet size change there are a few changes */
4192e51cea3SHanoh Haim    rte_mbuf_t * m_const = get_const_mbuf();
420a1364603SHanoh Haim    if ( (m_const == 0 ) || (pkt_new_size<=prefix_size) ) {
421a1364603SHanoh Haim        /* one mbuf , just trim it */
422a1364603SHanoh Haim        m->data_len = pkt_new_size;
423a1364603SHanoh Haim        m->pkt_len  = pkt_new_size;
424a1364603SHanoh Haim        return (m);
425a1364603SHanoh Haim    }
426a1364603SHanoh Haim
427a1364603SHanoh Haim    rte_mbuf_t * mi= CGlobalInfo::pktmbuf_alloc_small(get_socket_id());
428a1364603SHanoh Haim    assert(mi);
429a1364603SHanoh Haim    rte_pktmbuf_attach(mi,m_const);
4309e16960dSHanoh Haim    utl_rte_pktmbuf_add_after2(m,mi);
431a1364603SHanoh Haim
432a1364603SHanoh Haim    if ( pkt_new_size < m->pkt_len) {
433a1364603SHanoh Haim        /* need to trim it */
434a1364603SHanoh Haim        mi->data_len = (pkt_new_size - prefix_size);
435a1364603SHanoh Haim        m->pkt_len   = pkt_new_size;
4362e51cea3SHanoh Haim    }
4372e51cea3SHanoh Haim    return (m);
4382e51cea3SHanoh Haim}
4392e51cea3SHanoh Haim
4408b4df272SHanoh Haimvoid CGenNodeStateless::free_stl_vm_buf(){
4418b4df272SHanoh Haim        rte_mbuf_t * m ;
4428b4df272SHanoh Haim         m=get_const_mbuf();
4438b4df272SHanoh Haim         if (m) {
4448b4df272SHanoh Haim             rte_pktmbuf_free(m); /* reduce the ref counter */
4458b4df272SHanoh Haim             /* clear the const marker */
4468b4df272SHanoh Haim             clear_const_mbuf();
4478b4df272SHanoh Haim         }
4488b4df272SHanoh Haim
4498b4df272SHanoh Haim         free_prefix_header();
4508b4df272SHanoh Haim
4518b4df272SHanoh Haim         if (m_vm_flow_var) {
4528b4df272SHanoh Haim             /* free flow var */
4538b4df272SHanoh Haim             free(m_vm_flow_var);
4548b4df272SHanoh Haim             m_vm_flow_var=0;
4558b4df272SHanoh Haim         }
4568b4df272SHanoh Haim}
4578b4df272SHanoh Haim
4588b4df272SHanoh Haim
4592e51cea3SHanoh Haim
460cc352e04SHanoh Haimvoid CGenNodeStateless::free_stl_node(){
461c2912dfcSHanoh Haim
462c2912dfcSHanoh Haim    if ( is_cache_mbuf_array() ){
463c2912dfcSHanoh Haim        /* do we have cache of mbuf pre allocated */
464c2912dfcSHanoh Haim        cache_mbuf_array_free();
4652e51cea3SHanoh Haim    }else{
466c2912dfcSHanoh Haim        /* if we have cache mbuf free it */
467c2912dfcSHanoh Haim        rte_mbuf_t * m=get_cache_mbuf();
468c2912dfcSHanoh Haim        if (m) {
469c2912dfcSHanoh Haim                rte_pktmbuf_free(m);
470c2912dfcSHanoh Haim                m_cache_mbuf=0;
471c2912dfcSHanoh Haim        }
472cc352e04SHanoh Haim    }
4738b4df272SHanoh Haim    free_stl_vm_buf();
474cc352e04SHanoh Haim}
475cc352e04SHanoh Haim
476cc352e04SHanoh Haim
4770e8c9ae6SHanoh Haimbool TrexStatelessDpPerPort::update_number_of_active_streams(uint32_t d){
4780e8c9ae6SHanoh Haim    m_active_streams-=d; /* reduce the number of streams */
4790e8c9ae6SHanoh Haim    if (m_active_streams == 0) {
4800e8c9ae6SHanoh Haim        return (true);
4810e8c9ae6SHanoh Haim    }
4820e8c9ae6SHanoh Haim    return (false);
4830e8c9ae6SHanoh Haim}
4840e8c9ae6SHanoh Haim
485bd8b6400SHanoh Haimbool TrexStatelessDpPerPort::resume_traffic(uint8_t port_id){
486bd8b6400SHanoh Haim
487bd8b6400SHanoh Haim    /* we are working with continues streams so we must be in transmit mode */
488bd8b6400SHanoh Haim    assert(m_state == TrexStatelessDpPerPort::ppSTATE_PAUSE);
489bd8b6400SHanoh Haim
490bd8b6400SHanoh Haim    for (auto dp_stream : m_active_nodes) {
49103d70c42SIdo Barnea        CGenNodeStateless * node =dp_stream.m_node;
492bd8b6400SHanoh Haim        assert(node->get_port_id() == port_id);
493bd8b6400SHanoh Haim        assert(node->is_pause() == true);
494bd8b6400SHanoh Haim        node->set_pause(false);
495bd8b6400SHanoh Haim    }
496bd8b6400SHanoh Haim    m_state = TrexStatelessDpPerPort::ppSTATE_TRANSMITTING;
497bd8b6400SHanoh Haim    return (true);
498bd8b6400SHanoh Haim}
499bd8b6400SHanoh Haim
50059548ae8Simarombool TrexStatelessDpPerPort::update_traffic(uint8_t port_id, double factor) {
501d9a11302Simarom
50203d70c42SIdo Barnea    assert( (m_state == TrexStatelessDpPerPort::ppSTATE_TRANSMITTING ||
503d9a11302Simarom            (m_state == TrexStatelessDpPerPort::ppSTATE_PAUSE)) );
504d9a11302Simarom
505d9a11302Simarom    for (auto dp_stream : m_active_nodes) {
50603d70c42SIdo Barnea        CGenNodeStateless * node = dp_stream.m_node;
507d9a11302Simarom        assert(node->get_port_id() == port_id);
508d9a11302Simarom
50959548ae8Simarom        node->update_rate(factor);
510d9a11302Simarom    }
511d9a11302Simarom
512d9a11302Simarom    return (true);
513d9a11302Simarom}
514bd8b6400SHanoh Haim
515bd8b6400SHanoh Haimbool TrexStatelessDpPerPort::pause_traffic(uint8_t port_id){
516bd8b6400SHanoh Haim
517bd8b6400SHanoh Haim    /* we are working with continues streams so we must be in transmit mode */
518bd8b6400SHanoh Haim    assert(m_state == TrexStatelessDpPerPort::ppSTATE_TRANSMITTING);
519bd8b6400SHanoh Haim
520bd8b6400SHanoh Haim    for (auto dp_stream : m_active_nodes) {
52103d70c42SIdo Barnea        CGenNodeStateless * node =dp_stream.m_node;
522bd8b6400SHanoh Haim        assert(node->get_port_id() == port_id);
523bd8b6400SHanoh Haim        assert(node->is_pause() == false);
524bd8b6400SHanoh Haim        node->set_pause(true);
525bd8b6400SHanoh Haim    }
526bd8b6400SHanoh Haim    m_state = TrexStatelessDpPerPort::ppSTATE_PAUSE;
527bd8b6400SHanoh Haim    return (true);
528bd8b6400SHanoh Haim}
529bd8b6400SHanoh Haim
53075ce59e5Simarombool TrexStatelessDpPerPort::push_pcap(uint8_t port_id,
53175ce59e5Simarom                                       const std::string &pcap_filename,
53275ce59e5Simarom                                       double ipg_usec,
533e4c8e44bSYaroslav Brustinov                                       double min_ipg_sec,
53475ce59e5Simarom                                       double speedup,
53504eae221Simarom                                       uint32_t count,
53604eae221Simarom                                       bool is_dual) {
5378691f401Simarom
5388691f401Simarom    /* push pcap can only happen on an idle port from the core prespective */
5398691f401Simarom    assert(m_state == TrexStatelessDpPerPort::ppSTATE_IDLE);
5408691f401Simarom
5418691f401Simarom    CGenNodePCAP *pcap_node = m_core->allocate_pcap_node();
5428691f401Simarom    if (!pcap_node) {
5438691f401Simarom        return (false);
5448691f401Simarom    }
5458691f401Simarom
5463ef23bf8Simarom    pkt_dir_t dir          = m_core->m_node_gen.m_v_if->port_id_to_dir(port_id);
5473ef23bf8Simarom    socket_id_t socket_id  = m_core->m_node_gen.m_socket_id;
5488691f401Simarom
549b87818b8Simarom    /* main port */
5508691f401Simarom    uint8_t mac_addr[12];
5518691f401Simarom    m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir, mac_addr);
5528691f401Simarom
553b87818b8Simarom    /* for dual */
554b87818b8Simarom    uint8_t slave_mac_addr[12];
555b87818b8Simarom    m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir ^ 0x1, slave_mac_addr);
556b87818b8Simarom
55775ce59e5Simarom    bool rc = pcap_node->create(port_id,
55875ce59e5Simarom                                dir,
5593ef23bf8Simarom                                socket_id,
56075ce59e5Simarom                                mac_addr,
561b87818b8Simarom                                slave_mac_addr,
56275ce59e5Simarom                                pcap_filename,
56375ce59e5Simarom                                ipg_usec,
564e4c8e44bSYaroslav Brustinov                                min_ipg_sec,
56575ce59e5Simarom                                speedup,
56604eae221Simarom                                count,
56704eae221Simarom                                is_dual);
5688691f401Simarom    if (!rc) {
5698691f401Simarom        m_core->free_node((CGenNode *)pcap_node);
5708691f401Simarom        return (false);
5718691f401Simarom    }
5728691f401Simarom
5738691f401Simarom    /* schedule the node for now */
5748691f401Simarom    pcap_node->m_time = m_core->m_cur_time_sec;
5758691f401Simarom    m_core->m_node_gen.add_node((CGenNode *)pcap_node);
5768691f401Simarom
57775ce59e5Simarom    /* hold a pointer to the node */
57875ce59e5Simarom    assert(m_active_pcap_node == NULL);
57975ce59e5Simarom    m_active_pcap_node = pcap_node;
5808691f401Simarom
581db9145d2Simarom    m_state = TrexStatelessDpPerPort::ppSTATE_PCAP_TX;
5828691f401Simarom    return (true);
5838691f401Simarom}
5848691f401Simarom
5850e8c9ae6SHanoh Haim
58659a3b58dSimarombool TrexStatelessDpPerPort::stop_traffic(uint8_t  port_id,
58703d70c42SIdo Barnea                                          bool     stop_on_id,
58859a3b58dSimarom                                          int      event_id){
5890e8c9ae6SHanoh Haim
59054c1f0fcSHanoh Haim
5918c1cf5d7SHanoh Haim    if (m_state == TrexStatelessDpPerPort::ppSTATE_IDLE) {
5928c1cf5d7SHanoh Haim        assert(m_active_streams==0);
59336dc8ea5SHanoh Haim        return false;
5948c1cf5d7SHanoh Haim    }
5950e8c9ae6SHanoh Haim
5963408c030SHanoh Haim    /* there could be race of stop after stop */
5973408c030SHanoh Haim    if ( stop_on_id ) {
5983408c030SHanoh Haim        if (event_id != m_event_id){
5993408c030SHanoh Haim            /* we can't stop it is an old message */
6003408c030SHanoh Haim            return false;
6013408c030SHanoh Haim        }
6023408c030SHanoh Haim    }
6033408c030SHanoh Haim
6040e8c9ae6SHanoh Haim    for (auto dp_stream : m_active_nodes) {
60503d70c42SIdo Barnea        CGenNodeStateless * node =dp_stream.m_node;
6060e8c9ae6SHanoh Haim        assert(node->get_port_id() == port_id);
6070e8c9ae6SHanoh Haim        if ( node->get_state() == CGenNodeStateless::ss_ACTIVE) {
6080e8c9ae6SHanoh Haim            node->mark_for_free();
6090e8c9ae6SHanoh Haim            m_active_streams--;
6100e8c9ae6SHanoh Haim            dp_stream.DeleteOnlyStream();
6110e8c9ae6SHanoh Haim
6120e8c9ae6SHanoh Haim        }else{
6130e8c9ae6SHanoh Haim            dp_stream.Delete(m_core);
6140e8c9ae6SHanoh Haim        }
6150e8c9ae6SHanoh Haim    }
6160e8c9ae6SHanoh Haim
61775ce59e5Simarom    /* check for active PCAP node */
61875ce59e5Simarom    if (m_active_pcap_node) {
61975ce59e5Simarom        /* when got async stop from outside or duration */
62075ce59e5Simarom        if (m_active_pcap_node->is_active()) {
62175ce59e5Simarom            m_active_pcap_node->mark_for_free();
62275ce59e5Simarom        } else {
62375ce59e5Simarom            /* graceful stop - node was put out by the scheduler */
62475ce59e5Simarom            m_core->free_node( (CGenNode *)m_active_pcap_node);
62575ce59e5Simarom        }
62675ce59e5Simarom
62775ce59e5Simarom        m_active_pcap_node = NULL;
62875ce59e5Simarom    }
62975ce59e5Simarom
6300e8c9ae6SHanoh Haim    /* active stream should be zero */
6310e8c9ae6SHanoh Haim    assert(m_active_streams==0);
6320e8c9ae6SHanoh Haim    m_active_nodes.clear();
6330e8c9ae6SHanoh Haim    m_state=TrexStatelessDpPerPort::ppSTATE_IDLE;
63436dc8ea5SHanoh Haim    return (true);
6350e8c9ae6SHanoh Haim}
6360e8c9ae6SHanoh Haim
6370e8c9ae6SHanoh Haim
6380e8c9ae6SHanoh Haimvoid TrexStatelessDpPerPort::create(CFlowGenListPerThread   *  core){
6390e8c9ae6SHanoh Haim    m_core=core;
6400e8c9ae6SHanoh Haim    m_state=TrexStatelessDpPerPort::ppSTATE_IDLE;
6410e8c9ae6SHanoh Haim    m_active_streams=0;
6420e8c9ae6SHanoh Haim    m_active_nodes.clear();
64375ce59e5Simarom    m_active_pcap_node = NULL;
6440e8c9ae6SHanoh Haim}
6450e8c9ae6SHanoh Haim
6460e8c9ae6SHanoh Haim
64717d58dbaSimaromTrexStatelessDpCore::TrexStatelessDpCore() {
64817d58dbaSimarom    m_thread_id       = 0;
64917d58dbaSimarom    m_core            = NULL;
65017d58dbaSimarom    m_duration        = -1;
65117d58dbaSimarom    m_is_service_mode = NULL;
652b22e3ed1Simarom    m_wrapper         = new ServiceModeWrapper();
65317d58dbaSimarom}
65417d58dbaSimarom
65517d58dbaSimaromTrexStatelessDpCore::~TrexStatelessDpCore() {
65617d58dbaSimarom    delete m_wrapper;
65717d58dbaSimarom}
65817d58dbaSimarom
659cc352e04SHanoh Haim
660bc7d9ee8Simaromvoid
661bc7d9ee8SimaromTrexStatelessDpCore::create(uint8_t thread_id, CFlowGenListPerThread *core) {
662ea0b6efcSimarom    m_thread_id = thread_id;
663ea0b6efcSimarom    m_core = core;
6640e8c9ae6SHanoh Haim    m_local_port_offset = 2*core->getDualPortId();
665ea0b6efcSimarom
666ea0b6efcSimarom    CMessagingManager * cp_dp = CMsgIns::Ins()->getCpDp();
667ea0b6efcSimarom
668ea0b6efcSimarom    m_ring_from_cp = cp_dp->getRingCpToDp(thread_id);
669ea0b6efcSimarom    m_ring_to_cp   = cp_dp->getRingDpToCp(thread_id);
6703978adceSimarom
6713978adceSimarom    m_state = STATE_IDLE;
6720e8c9ae6SHanoh Haim
6730e8c9ae6SHanoh Haim    int i;
6740e8c9ae6SHanoh Haim    for (i=0; i<NUM_PORTS_PER_CORE; i++) {
6750e8c9ae6SHanoh Haim        m_ports[i].create(core);
6760e8c9ae6SHanoh Haim    }
6770e8c9ae6SHanoh Haim}
6780e8c9ae6SHanoh Haim
6790e8c9ae6SHanoh Haim
6800e8c9ae6SHanoh Haim/* move to the next stream, old stream move to INACTIVE */
6810e8c9ae6SHanoh Haimbool TrexStatelessDpCore::set_stateless_next_node(CGenNodeStateless * cur_node,
6820e8c9ae6SHanoh Haim                                                  CGenNodeStateless * next_node){
6830e8c9ae6SHanoh Haim
6840e8c9ae6SHanoh Haim    assert(cur_node);
6850e8c9ae6SHanoh Haim    TrexStatelessDpPerPort * lp_port = get_port_db(cur_node->m_port_id);
6860e8c9ae6SHanoh Haim    bool schedule =false;
6870e8c9ae6SHanoh Haim
6880e8c9ae6SHanoh Haim    bool to_stop_port=false;
6890e8c9ae6SHanoh Haim
6900e8c9ae6SHanoh Haim    if (next_node == NULL) {
6910e8c9ae6SHanoh Haim        /* there is no next stream , reduce the number of active streams*/
6920e8c9ae6SHanoh Haim        to_stop_port = lp_port->update_number_of_active_streams(1);
6930e8c9ae6SHanoh Haim
6940e8c9ae6SHanoh Haim    }else{
6950e8c9ae6SHanoh Haim        uint8_t state=next_node->get_state();
6960e8c9ae6SHanoh Haim
6970e8c9ae6SHanoh Haim        /* can't be FREE_RESUSE */
6980e8c9ae6SHanoh Haim        assert(state != CGenNodeStateless::ss_FREE_RESUSE);
6990e3021bbSHanoh Haim        if (state == CGenNodeStateless::ss_INACTIVE ) {
7000e8c9ae6SHanoh Haim
701ecbb10f1SHanoh Haim            if (cur_node->m_action_counter > 0) {
702ecbb10f1SHanoh Haim                cur_node->m_action_counter--;
703ecbb10f1SHanoh Haim                if (cur_node->m_action_counter==0) {
704ecbb10f1SHanoh Haim                    to_stop_port = lp_port->update_number_of_active_streams(1);
705ecbb10f1SHanoh Haim                }else{
706ecbb10f1SHanoh Haim                    /* refill start info and scedule, no update in active streams  */
707ecbb10f1SHanoh Haim                    next_node->refresh();
708ecbb10f1SHanoh Haim                    schedule = true;
709ecbb10f1SHanoh Haim                }
710ecbb10f1SHanoh Haim            }else{
711ecbb10f1SHanoh Haim                /* refill start info and scedule, no update in active streams  */
712ecbb10f1SHanoh Haim                next_node->refresh();
713ecbb10f1SHanoh Haim                schedule = true;
714ecbb10f1SHanoh Haim            }
7150e8c9ae6SHanoh Haim
7160e8c9ae6SHanoh Haim        }else{
7170e8c9ae6SHanoh Haim            to_stop_port = lp_port->update_number_of_active_streams(1);
7180e8c9ae6SHanoh Haim        }
7190e8c9ae6SHanoh Haim    }
7200e8c9ae6SHanoh Haim
7210e8c9ae6SHanoh Haim    if ( to_stop_port ) {
7220e8c9ae6SHanoh Haim        /* call stop port explictly to move the state */
7233408c030SHanoh Haim        stop_traffic(cur_node->m_port_id,false,0);
7240e8c9ae6SHanoh Haim    }
7250e8c9ae6SHanoh Haim
7260e8c9ae6SHanoh Haim    return ( schedule );
727ea0b6efcSimarom}
728ea0b6efcSimarom
7290e8c9ae6SHanoh Haim
7300e8c9ae6SHanoh Haim
731ee2c7f45Simarom/**
73203d70c42SIdo Barnea * in idle state loop, the processor most of the time sleeps
73303d70c42SIdo Barnea * and periodically checks for messages
73403d70c42SIdo Barnea *
735ee2c7f45Simarom * @author imarom (01-Nov-15)
736ee2c7f45Simarom */
73703d70c42SIdo Barneavoid
738ee2c7f45SimaromTrexStatelessDpCore::idle_state_loop() {
739ea0b6efcSimarom
7409c62e2a6Simarom    const int SHORT_DELAY_MS    = 2;
7419c62e2a6Simarom    const int LONG_DELAY_MS     = 50;
7429c62e2a6Simarom    const int DEEP_SLEEP_LIMIT  = 2000;
7439c62e2a6Simarom
7449c62e2a6Simarom    int counter = 0;
7459c62e2a6Simarom
746ee2c7f45Simarom    while (m_state == STATE_IDLE) {
7473c4a29e1Simarom        m_core->tickle();
748abc0cb87Simarom
749abc0cb87Simarom        bool had_msg = m_core->check_msgs();
7509c62e2a6Simarom        if (had_msg) {
7519c62e2a6Simarom            counter = 0;
7529c62e2a6Simarom            continue;
7539c62e2a6Simarom        }
7549c62e2a6Simarom
7559c62e2a6Simarom        /* enter deep sleep only if enough time had passed */
7569c62e2a6Simarom        if (counter < DEEP_SLEEP_LIMIT) {
7579c62e2a6Simarom            delay(SHORT_DELAY_MS);
7589c62e2a6Simarom            counter++;
7599c62e2a6Simarom        } else {
7609c62e2a6Simarom            delay(LONG_DELAY_MS);
761857bdcf0Simarom        }
76203d70c42SIdo Barnea
763ee2c7f45Simarom    }
764ee2c7f45Simarom}
765ee2c7f45Simarom
7663b8eb91eSHanoh Haim
7673b8eb91eSHanoh Haim
7683b8eb91eSHanoh Haimvoid TrexStatelessDpCore::quit_main_loop(){
7693b8eb91eSHanoh Haim    m_core->set_terminate_mode(true); /* mark it as terminated */
7700e8c9ae6SHanoh Haim    m_state = STATE_TERMINATE;
7710e8c9ae6SHanoh Haim    add_global_duration(0.0001);
7723b8eb91eSHanoh Haim}
7733b8eb91eSHanoh Haim
7743b8eb91eSHanoh Haim
775ee2c7f45Simarom/**
77603d70c42SIdo Barnea * scehduler runs when traffic exists
77703d70c42SIdo Barnea * it will return when no more transmitting is done on this
77803d70c42SIdo Barnea * core
77903d70c42SIdo Barnea *
780ee2c7f45Simarom * @author imarom (01-Nov-15)
781ee2c7f45Simarom */
782ee2c7f45Simaromvoid
783ee2c7f45SimaromTrexStatelessDpCore::start_scheduler() {
78417d58dbaSimarom
785ea0b6efcSimarom    /* creates a maintenace job using the scheduler */
786ea0b6efcSimarom    CGenNode * node_sync = m_core->create_node() ;
787ea0b6efcSimarom    node_sync->m_type = CGenNode::FLOW_SYNC;
788ea0b6efcSimarom    node_sync->m_time = m_core->m_cur_time_sec + SYNC_TIME_OUT;
789c3a0d758Simarom
790ea0b6efcSimarom    m_core->m_node_gen.add_node(node_sync);
791ea0b6efcSimarom
792ea0b6efcSimarom    double old_offset = 0.0;
793bc7d9ee8Simarom    m_core->m_node_gen.flush_file(-1, 0.0, false, m_core, old_offset);
7948c1cf5d7SHanoh Haim    /* bail out in case of terminate */
7958c1cf5d7SHanoh Haim    if (m_state != TrexStatelessDpCore::STATE_TERMINATE) {
7968c1cf5d7SHanoh Haim        m_core->m_node_gen.close_file(m_core);
79712a19244SHanoh Haim        m_state = STATE_IDLE; /* we exit from all ports and we have nothing to do, we move to IDLE state */
7988c1cf5d7SHanoh Haim    }
799ee2c7f45Simarom}
800ee2c7f45Simarom
801cc352e04SHanoh Haim
80203d70c42SIdo Barneavoid
803cc352e04SHanoh HaimTrexStatelessDpCore::run_once(){
804cc352e04SHanoh Haim
805cc352e04SHanoh Haim    idle_state_loop();
8060e8c9ae6SHanoh Haim
8070e8c9ae6SHanoh Haim    if ( m_state == STATE_TERMINATE ){
8080e8c9ae6SHanoh Haim        return;
8090e8c9ae6SHanoh Haim    }
8100e8c9ae6SHanoh Haim
811cc352e04SHanoh Haim    start_scheduler();
812cc352e04SHanoh Haim}
813cc352e04SHanoh Haim
814cc352e04SHanoh Haim
815bd8b6400SHanoh Haim
816bd8b6400SHanoh Haim
817ee2c7f45Simaromvoid
818ee2c7f45SimaromTrexStatelessDpCore::start() {
819ee2c7f45Simarom
820ee2c7f45Simarom    while (true) {
821cc352e04SHanoh Haim        run_once();
8223b8eb91eSHanoh Haim
8233b8eb91eSHanoh Haim        if ( m_core->is_terminated_by_master() ) {
8243b8eb91eSHanoh Haim            break;
8253b8eb91eSHanoh Haim        }
826cc352e04SHanoh Haim    }
827cc352e04SHanoh Haim}
828cc352e04SHanoh Haim
8290e8c9ae6SHanoh Haim/* only if both port are idle we can exit */
83003d70c42SIdo Barneavoid
8310e8c9ae6SHanoh HaimTrexStatelessDpCore::schedule_exit(){
8320e8c9ae6SHanoh Haim
8330e8c9ae6SHanoh Haim    CGenNodeCommand *node = (CGenNodeCommand *)m_core->create_node() ;
8340e8c9ae6SHanoh Haim
8350e8c9ae6SHanoh Haim    node->m_type = CGenNode::COMMAND;
8360e8c9ae6SHanoh Haim
8370e8c9ae6SHanoh Haim    node->m_cmd = new TrexStatelessDpCanQuit();
8380e8c9ae6SHanoh Haim
8390e8c9ae6SHanoh Haim    /* make sure it will be scheduled after the current node */
8400e8c9ae6SHanoh Haim    node->m_time = m_core->m_cur_time_sec ;
8410e8c9ae6SHanoh Haim
8420e8c9ae6SHanoh Haim    m_core->m_node_gen.add_node((CGenNode *)node);
8430e8c9ae6SHanoh Haim}
8440e8c9ae6SHanoh Haim
8450e8c9ae6SHanoh Haim
84603d70c42SIdo Barneavoid
8470e8c9ae6SHanoh HaimTrexStatelessDpCore::add_global_duration(double duration){
848cc352e04SHanoh Haim    if (duration > 0.0) {
849cc352e04SHanoh Haim        CGenNode *node = m_core->create_node() ;
850cc352e04SHanoh Haim
851cc352e04SHanoh Haim        node->m_type = CGenNode::EXIT_SCHED;
852cc352e04SHanoh Haim
853cc352e04SHanoh Haim        /* make sure it will be scheduled after the current node */
854cc352e04SHanoh Haim        node->m_time = m_core->m_cur_time_sec + duration ;
855cc352e04SHanoh Haim
856cc352e04SHanoh Haim        m_core->m_node_gen.add_node(node);
857ee2c7f45Simarom    }
858ea0b6efcSimarom}
859ea0b6efcSimarom
8600e8c9ae6SHanoh Haim/* add per port exit */
8610e8c9ae6SHanoh Haimvoid
8620e8c9ae6SHanoh HaimTrexStatelessDpCore::add_port_duration(double duration,
8633408c030SHanoh Haim                                       uint8_t port_id,
8643408c030SHanoh Haim                                       int event_id){
8650e8c9ae6SHanoh Haim    if (duration > 0.0) {
8660e8c9ae6SHanoh Haim        CGenNodeCommand *node = (CGenNodeCommand *)m_core->create_node() ;
8670e8c9ae6SHanoh Haim
8680e8c9ae6SHanoh Haim        node->m_type = CGenNode::COMMAND;
8690e8c9ae6SHanoh Haim
8700e8c9ae6SHanoh Haim        /* make sure it will be scheduled after the current node */
8710e8c9ae6SHanoh Haim        node->m_time = m_core->m_cur_time_sec + duration ;
8720e8c9ae6SHanoh Haim
8733408c030SHanoh Haim        TrexStatelessDpStop * cmd=new TrexStatelessDpStop(port_id);
8743408c030SHanoh Haim
8753408c030SHanoh Haim
8763408c030SHanoh Haim        /* test this */
8773408c030SHanoh Haim        m_core->m_non_active_nodes++;
8783408c030SHanoh Haim        cmd->set_core_ptr(m_core);
8793408c030SHanoh Haim        cmd->set_event_id(event_id);
8803408c030SHanoh Haim        cmd->set_wait_for_event_id(true);
8813408c030SHanoh Haim
8823408c030SHanoh Haim        node->m_cmd = cmd;
8830e8c9ae6SHanoh Haim
8840e8c9ae6SHanoh Haim        m_core->m_node_gen.add_node((CGenNode *)node);
8850e8c9ae6SHanoh Haim    }
8860e8c9ae6SHanoh Haim}
8870e8c9ae6SHanoh Haim
888cc352e04SHanoh Haim
889f6901ca1SHanoh Haimvoid TrexStatelessDpCore::update_mac_addr(TrexStream * stream,
890f6901ca1SHanoh Haim                                          CGenNodeStateless *node,
891f6901ca1SHanoh Haim                                          pkt_dir_t dir,
892f6901ca1SHanoh Haim                                          char *raw_pkt){
893f6901ca1SHanoh Haim    bool              ov_src = stream->get_override_src_mac_by_pkt_data();
894f6901ca1SHanoh Haim    TrexStream::stream_dst_mac_t  ov_dst = stream->get_override_dst_mac_mode();
895f6901ca1SHanoh Haim
896f6901ca1SHanoh Haim
897f6901ca1SHanoh Haim    if ( (ov_src == true) && (ov_dst == TrexStream::stPKT) ) {
898f6901ca1SHanoh Haim        /* nothing to do, take from the packet both */
899f6901ca1SHanoh Haim        return;
900f6901ca1SHanoh Haim    }
901f6901ca1SHanoh Haim
902f6901ca1SHanoh Haim        /* take from cfg_file */
90303d70c42SIdo Barnea    if ( (ov_src == false) &&
904f6901ca1SHanoh Haim         (ov_dst == TrexStream::stCFG_FILE) ){
905f6901ca1SHanoh Haim
906f6901ca1SHanoh Haim          m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir,(uint8_t*)raw_pkt);
907f6901ca1SHanoh Haim          return;
908f6901ca1SHanoh Haim    }
909f6901ca1SHanoh Haim
910f6901ca1SHanoh Haim    /* save the pkt*/
911f6901ca1SHanoh Haim    char tmp_pkt[12];
912f6901ca1SHanoh Haim    memcpy(tmp_pkt,raw_pkt,12);
913f6901ca1SHanoh Haim
914f6901ca1SHanoh Haim    m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir,(uint8_t*)raw_pkt);
915f6901ca1SHanoh Haim
916f6901ca1SHanoh Haim    if ((ov_src == true) && (ov_dst == TrexStream::stCFG_FILE)) {
917f6901ca1SHanoh Haim        memcpy(raw_pkt+6,tmp_pkt+6,6);
918f6901ca1SHanoh Haim    }
919f6901ca1SHanoh Haim
920f6901ca1SHanoh Haim    if ((ov_src == false) && (ov_dst == TrexStream::stPKT)) {
921f6901ca1SHanoh Haim        memcpy(raw_pkt,tmp_pkt,6);
922f6901ca1SHanoh Haim    }
923f6901ca1SHanoh Haim}
924f6901ca1SHanoh Haim
925f6901ca1SHanoh Haim
9268b4df272SHanoh Haimvoid TrexStatelessDpCore::replay_vm_into_cache(TrexStream * stream,
9278b4df272SHanoh Haim                                               CGenNodeStateless *node){
9288b4df272SHanoh Haim
9298b4df272SHanoh Haim    uint16_t      cache_size = stream->m_cache_size;
9308b4df272SHanoh Haim    assert(cache_size>0);
9318b4df272SHanoh Haim    rte_mbuf_t * m=0;
9328b4df272SHanoh Haim
9338b4df272SHanoh Haim    uint32_t buf_size = CGenNodeCacheMbuf::get_object_size(cache_size);
9348b4df272SHanoh Haim    CGenNodeCacheMbuf * p = (CGenNodeCacheMbuf *)malloc(buf_size);
9358b4df272SHanoh Haim    assert(p);
9368b4df272SHanoh Haim    memset(p,0,buf_size);
9378b4df272SHanoh Haim
9388b4df272SHanoh Haim    int i;
9398b4df272SHanoh Haim    for (i=0; i<cache_size; i++) {
9408b4df272SHanoh Haim        p->m_array[i] =  node->alloc_node_with_vm();
9418b4df272SHanoh Haim    }
9428b4df272SHanoh Haim    /* save const */
9438b4df272SHanoh Haim    m=node->get_const_mbuf();
9448b4df272SHanoh Haim    if (m) {
9458b4df272SHanoh Haim        p->m_mbuf_const=m;
9468b4df272SHanoh Haim        rte_pktmbuf_refcnt_update(m,1);
9478b4df272SHanoh Haim    }
9488b4df272SHanoh Haim
9498b4df272SHanoh Haim    /* free all VM and const mbuf */
9508b4df272SHanoh Haim    node->free_stl_vm_buf();
9518b4df272SHanoh Haim
9528b4df272SHanoh Haim    /* copy to local node meory */
9538b4df272SHanoh Haim    node->cache_mbuf_array_copy(p,cache_size);
9548b4df272SHanoh Haim
9558b4df272SHanoh Haim    /* free the memory */
9568b4df272SHanoh Haim    free(p);
9578b4df272SHanoh Haim}
9588b4df272SHanoh Haim
9598b4df272SHanoh Haim
960ea0b6efcSimaromvoid
961d9a11302SimaromTrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
962d9a11302Simarom                                TrexStream * stream,
963d9a11302Simarom                                TrexStreamsCompiledObj *comp) {
9648691f401Simarom
965ea0b6efcSimarom    CGenNodeStateless *node = m_core->create_node_sl();
966ea0b6efcSimarom
967e946a09eSimarom    node->m_thread_id = m_thread_id;
9688b4df272SHanoh Haim    node->cache_mbuf_array_init();
9698b4df272SHanoh Haim    node->m_batch_size=0;
9708b4df272SHanoh Haim
971ea0b6efcSimarom    /* add periodic */
972aae09645SHanoh Haim    node->m_cache_mbuf=0;
973ea0b6efcSimarom    node->m_type = CGenNode::STATELESS_PKT;
974c0a49eefSimarom
975ecbb10f1SHanoh Haim    node->m_action_counter = stream->m_action_count;
976ecbb10f1SHanoh Haim
9770901331fSimarom    /* clone the stream from control plane memory to DP memory */
9780901331fSimarom    node->m_ref_stream_info = stream->clone();
9790bde21acSimarom    /* no need for this memory anymore on the control plane memory */
9800bde21acSimarom    stream->release_dp_object();
9810e8c9ae6SHanoh Haim
9820e8c9ae6SHanoh Haim    node->m_next_stream=0; /* will be fixed later */
9830e8c9ae6SHanoh Haim
9840e8c9ae6SHanoh Haim    if ( stream->m_self_start ){
9850e8c9ae6SHanoh Haim        /* if self start it is in active mode */
9860e8c9ae6SHanoh Haim        node->m_state =CGenNodeStateless::ss_ACTIVE;
9870e8c9ae6SHanoh Haim        lp_port->m_active_streams++;
9880e8c9ae6SHanoh Haim    }else{
9890e8c9ae6SHanoh Haim        node->m_state =CGenNodeStateless::ss_INACTIVE;
9900e8c9ae6SHanoh Haim    }
9910e8c9ae6SHanoh Haim
9927a3be366Simarom    node->m_time = m_core->m_cur_time_sec + stream->get_start_delay_sec();
993c0a49eefSimarom
994151266e3SHanoh Haim    pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(stream->m_port_id);
99503d70c42SIdo Barnea    node->m_flags = 0;
9962e51cea3SHanoh Haim    node->m_src_port =0;
9972e51cea3SHanoh Haim    node->m_original_packet_data_prefix = 0;
9982e51cea3SHanoh Haim
9998714436fSIdo Barnea    if (stream->m_rx_check.m_enabled) {
10008714436fSIdo Barnea        node->set_stat_needed();
1001fa606839SIdo Barnea        uint16_t hw_id = stream->m_rx_check.m_hw_id;
1002d3b66fddSIdo Barnea        assert (hw_id < MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD);
10038714436fSIdo Barnea        node->set_stat_hw_id(hw_id);
1004d49f3784SIdo Barnea        // no support for cache with flow stat payload rules
1005d49f3784SIdo Barnea        if ((TrexPlatformApi::driver_stat_cap_e)stream->m_rx_check.m_rule_type == TrexPlatformApi::IF_STAT_PAYLOAD) {
1006d49f3784SIdo Barnea            stream->m_cache_size = 0;
1007d49f3784SIdo Barnea        }
10088714436fSIdo Barnea    }
1009ea0b6efcSimarom
1010ea0b6efcSimarom    /* set socket id */
1011ea0b6efcSimarom    node->set_socket_id(m_core->m_node_gen.m_socket_id);
1012ea0b6efcSimarom
1013ea0b6efcSimarom    /* build a mbuf from a packet */
101403d70c42SIdo Barnea
1015151266e3SHanoh Haim    uint16_t pkt_size = stream->m_pkt.len;
1016151266e3SHanoh Haim    const uint8_t *stream_pkt = stream->m_pkt.binary;
1017151266e3SHanoh Haim
1018bd8b6400SHanoh Haim    node->m_pause =0;
1019151266e3SHanoh Haim    node->m_stream_type = stream->m_type;
10203aa3a83fSimarom    node->m_next_time_offset = 1.0 / stream->get_pps();
1021ff443a39Simarom    node->m_null_stream = (stream->m_null_stream ? 1 : 0);
1022ea0b6efcSimarom
1023c0a49eefSimarom    /* stateless specific fields */
1024151266e3SHanoh Haim    switch ( stream->m_type ) {
1025151266e3SHanoh Haim
1026151266e3SHanoh Haim    case TrexStream::stCONTINUOUS :
10270e8c9ae6SHanoh Haim        node->m_single_burst=0;
10280e8c9ae6SHanoh Haim        node->m_single_burst_refill=0;
10290e8c9ae6SHanoh Haim        node->m_multi_bursts=0;
1030151266e3SHanoh Haim        break;
1031151266e3SHanoh Haim
1032151266e3SHanoh Haim    case TrexStream::stSINGLE_BURST :
1033151266e3SHanoh Haim        node->m_stream_type             = TrexStream::stMULTI_BURST;
103445b71cffSHanoh Haim        node->m_single_burst            = stream->m_burst_total_pkts;
103545b71cffSHanoh Haim        node->m_single_burst_refill     = stream->m_burst_total_pkts;
1036151266e3SHanoh Haim        node->m_multi_bursts            = 1;  /* single burst in multi burst of 1 */
1037151266e3SHanoh Haim        break;
1038151266e3SHanoh Haim
1039151266e3SHanoh Haim    case TrexStream::stMULTI_BURST :
104045b71cffSHanoh Haim        node->m_single_burst        = stream->m_burst_total_pkts;
104145b71cffSHanoh Haim        node->m_single_burst_refill = stream->m_burst_total_pkts;
104245b71cffSHanoh Haim        node->m_multi_bursts        = stream->m_num_bursts;
1043151266e3SHanoh Haim        break;
1044151266e3SHanoh Haim    default:
1045151266e3SHanoh Haim
1046151266e3SHanoh Haim        assert(0);
1047151266e3SHanoh Haim    };
1048151266e3SHanoh Haim
1049151266e3SHanoh Haim    node->m_port_id = stream->m_port_id;
1050ea0b6efcSimarom
1051ea0b6efcSimarom    /* set dir 0 or 1 client or server */
1052ea0b6efcSimarom    node->set_mbuf_cache_dir(dir);
1053ea0b6efcSimarom
1054ea0b6efcSimarom
10550901331fSimarom    if (node->m_ref_stream_info->getDpVm() == NULL) {
1056e7ffce7bSHanoh Haim        /* no VM */
1057e7ffce7bSHanoh Haim
1058e7ffce7bSHanoh Haim        node->m_vm_flow_var =  NULL;
1059e7ffce7bSHanoh Haim        node->m_vm_program  =  NULL;
1060e7ffce7bSHanoh Haim        node->m_vm_program_size =0;
1061e7ffce7bSHanoh Haim
10622e51cea3SHanoh Haim                /* allocate const mbuf */
10632e51cea3SHanoh Haim        rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), pkt_size);
10642e51cea3SHanoh Haim        assert(m);
106503d70c42SIdo Barnea
10662e51cea3SHanoh Haim        char *p = rte_pktmbuf_append(m, pkt_size);
10672e51cea3SHanoh Haim        assert(p);
10682e51cea3SHanoh Haim        /* copy the packet */
10692e51cea3SHanoh Haim        memcpy(p,stream_pkt,pkt_size);
107003d70c42SIdo Barnea
1071f6901ca1SHanoh Haim        update_mac_addr(stream,node,dir,p);
107203d70c42SIdo Barnea
10732e51cea3SHanoh Haim        /* set the packet as a readonly */
10742e51cea3SHanoh Haim        node->set_cache_mbuf(m);
1075aae09645SHanoh Haim
1076aae09645SHanoh Haim        node->m_original_packet_data_prefix =0;
10772e51cea3SHanoh Haim    }else{
10782e51cea3SHanoh Haim
1079e7ffce7bSHanoh Haim        /* set the program */
1080e7ffce7bSHanoh Haim        TrexStream * local_mem_stream = node->m_ref_stream_info;
1081e7ffce7bSHanoh Haim
1082e7ffce7bSHanoh Haim        StreamVmDp  * lpDpVm = local_mem_stream->getDpVm();
1083e7ffce7bSHanoh Haim
10840901331fSimarom        node->m_vm_flow_var      = lpDpVm->clone_bss(); /* clone the flow var */
10850901331fSimarom        node->m_vm_program       = lpDpVm->get_program(); /* same ref to the program */
10860901331fSimarom        node->m_vm_program_size  = lpDpVm->get_program_size();
1087e7ffce7bSHanoh Haim
1088e946a09eSimarom        /* generate random seed if needed*/
1089e946a09eSimarom        if (lpDpVm->is_random_seed()) {
1090e946a09eSimarom            node->generate_random_seed();
10914ae35508SHanoh Haim        }
10924ae35508SHanoh Haim
1093e7ffce7bSHanoh Haim        /* we need to copy the object */
10940901331fSimarom        if ( pkt_size > lpDpVm->get_prefix_size() ) {
10952e51cea3SHanoh Haim            /* we need const packet */
10960901331fSimarom            uint16_t const_pkt_size  = pkt_size - lpDpVm->get_prefix_size() ;
10972e51cea3SHanoh Haim            rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), const_pkt_size );
10982e51cea3SHanoh Haim            assert(m);
10992e51cea3SHanoh Haim
11002e51cea3SHanoh Haim            char *p = rte_pktmbuf_append(m, const_pkt_size);
11012e51cea3SHanoh Haim            assert(p);
11022e51cea3SHanoh Haim
11032e51cea3SHanoh Haim            /* copy packet data */
11040901331fSimarom            memcpy(p,(stream_pkt + lpDpVm->get_prefix_size()),const_pkt_size);
11052e51cea3SHanoh Haim
11062e51cea3SHanoh Haim            node->set_const_mbuf(m);
11072e51cea3SHanoh Haim        }
11082e51cea3SHanoh Haim
11092e51cea3SHanoh Haim
1110a1364603SHanoh Haim        if ( lpDpVm->is_pkt_size_var() ) {
111103d70c42SIdo Barnea            // mark the node as varible size
1112a1364603SHanoh Haim            node->set_var_pkt_size();
1113a1364603SHanoh Haim        }
1114a1364603SHanoh Haim
1115a1364603SHanoh Haim
11160901331fSimarom        if (lpDpVm->get_prefix_size() > pkt_size ) {
11170901331fSimarom            lpDpVm->set_prefix_size(pkt_size);
11182e51cea3SHanoh Haim        }
11190901331fSimarom
11202e51cea3SHanoh Haim        /* copy the headr */
11210901331fSimarom        uint16_t header_size = lpDpVm->get_prefix_size();
11222e51cea3SHanoh Haim        assert(header_size);
11232e51cea3SHanoh Haim        node->alloc_prefix_header(header_size);
11242e51cea3SHanoh Haim        uint8_t *p=node->m_original_packet_data_prefix;
11252e51cea3SHanoh Haim        assert(p);
11262e51cea3SHanoh Haim
11272e51cea3SHanoh Haim        memcpy(p,stream_pkt , header_size);
1128f6901ca1SHanoh Haim
1129f6901ca1SHanoh Haim        update_mac_addr(stream,node,dir,(char *)p);
11308b4df272SHanoh Haim
11318b4df272SHanoh Haim        if (stream->m_cache_size > 0 ) {
11328b4df272SHanoh Haim            /* we need to create cache of objects */
11338b4df272SHanoh Haim            replay_vm_into_cache(stream, node);
11348b4df272SHanoh Haim        }
11352e51cea3SHanoh Haim    }
11362e51cea3SHanoh Haim
1137ea0b6efcSimarom
11380e8c9ae6SHanoh Haim    CDpOneStream one_stream;
11390e8c9ae6SHanoh Haim
11400e8c9ae6SHanoh Haim    one_stream.m_dp_stream = node->m_ref_stream_info;
11410e8c9ae6SHanoh Haim    one_stream.m_node =node;
11420e8c9ae6SHanoh Haim
11430e8c9ae6SHanoh Haim    lp_port->m_active_nodes.push_back(one_stream);
11443978adceSimarom
1145a2625fbfSHanoh Haim    /* schedule only if active */
1146a2625fbfSHanoh Haim    if (node->m_state == CGenNodeStateless::ss_ACTIVE) {
1147a2625fbfSHanoh Haim        m_core->m_node_gen.add_node((CGenNode *)node);
1148a2625fbfSHanoh Haim    }
1149cb8bc9bdSimarom}
1150ea0b6efcSimarom
1151cb8bc9bdSimaromvoid
115203d70c42SIdo BarneaTrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj,
11533408c030SHanoh Haim                                   double duration,
11543408c030SHanoh Haim                                   int event_id) {
11550e8c9ae6SHanoh Haim
11560e8c9ae6SHanoh Haim
11570e8c9ae6SHanoh Haim    TrexStatelessDpPerPort * lp_port=get_port_db(obj->get_port_id());
11580e8c9ae6SHanoh Haim    lp_port->m_active_streams = 0;
11593408c030SHanoh Haim    lp_port->set_event_id(event_id);
11603408c030SHanoh Haim
1161996f2451SHanoh Haim    /* update cur time */
1162996f2451SHanoh Haim    if ( CGlobalInfo::is_realtime()  ){
1163996f2451SHanoh Haim        m_core->m_cur_time_sec = now_sec() + SCHD_OFFSET_DTIME ;
1164996f2451SHanoh Haim    }
1165996f2451SHanoh Haim
11660e8c9ae6SHanoh Haim    /* no nodes in the list */
11670e8c9ae6SHanoh Haim    assert(lp_port->m_active_nodes.size()==0);
11680e8c9ae6SHanoh Haim
11690e8c9ae6SHanoh Haim    for (auto single_stream : obj->get_objects()) {
11700e8c9ae6SHanoh Haim        /* all commands should be for the same port */
11710e8c9ae6SHanoh Haim        assert(obj->get_port_id() == single_stream.m_stream->m_port_id);
1172d9a11302Simarom        add_stream(lp_port,single_stream.m_stream,obj);
11730e8c9ae6SHanoh Haim    }
11740e8c9ae6SHanoh Haim
11750e8c9ae6SHanoh Haim    uint32_t nodes = lp_port->m_active_nodes.size();
11760e8c9ae6SHanoh Haim    /* find next stream */
11770e8c9ae6SHanoh Haim    assert(nodes == obj->get_objects().size());
11780e8c9ae6SHanoh Haim
11790e8c9ae6SHanoh Haim    int cnt=0;
11800e8c9ae6SHanoh Haim
11810e8c9ae6SHanoh Haim    /* set the next_stream pointer  */
1182788ba38bSimarom    for (auto single_stream : obj->get_objects()) {
11830e8c9ae6SHanoh Haim
11840e8c9ae6SHanoh Haim        if (single_stream.m_stream->is_dp_next_stream() ) {
11850e8c9ae6SHanoh Haim            int stream_id = single_stream.m_stream->m_next_stream_id;
11860e8c9ae6SHanoh Haim            assert(stream_id<nodes);
11870e8c9ae6SHanoh Haim            /* point to the next stream , stream_id is fixed */
11880e8c9ae6SHanoh Haim            lp_port->m_active_nodes[cnt].m_node->m_next_stream = lp_port->m_active_nodes[stream_id].m_node ;
11890e8c9ae6SHanoh Haim        }
11900e8c9ae6SHanoh Haim        cnt++;
1191cb8bc9bdSimarom    }
1192cc352e04SHanoh Haim
11930e8c9ae6SHanoh Haim    lp_port->m_state =TrexStatelessDpPerPort::ppSTATE_TRANSMITTING;
11940e8c9ae6SHanoh Haim    m_state = TrexStatelessDpCore::STATE_TRANSMITTING;
11950e8c9ae6SHanoh Haim
11960e8c9ae6SHanoh Haim
119794b12389Simarom    if ( duration > 0.0 ){
11983408c030SHanoh Haim        add_port_duration( duration ,obj->get_port_id(),event_id );
11990e8c9ae6SHanoh Haim    }
1200a7317d45Simarom
12010e8c9ae6SHanoh Haim}
12020e8c9ae6SHanoh Haim
12030e8c9ae6SHanoh Haim
12040e8c9ae6SHanoh Haimbool TrexStatelessDpCore::are_all_ports_idle(){
12050e8c9ae6SHanoh Haim
12060e8c9ae6SHanoh Haim    bool res=true;
12070e8c9ae6SHanoh Haim    int i;
12080e8c9ae6SHanoh Haim    for (i=0; i<NUM_PORTS_PER_CORE; i++) {
12090e8c9ae6SHanoh Haim        if ( m_ports[i].m_state != TrexStatelessDpPerPort::ppSTATE_IDLE ){
12100e8c9ae6SHanoh Haim            res=false;
12110e8c9ae6SHanoh Haim        }
12126294136dSHanoh Haim    }
12130e8c9ae6SHanoh Haim    return (res);
1214ea0b6efcSimarom}
1215ea0b6efcSimarom
12160e8c9ae6SHanoh Haim
121703d70c42SIdo Barneavoid
1218bd8b6400SHanoh HaimTrexStatelessDpCore::resume_traffic(uint8_t port_id){
1219bd8b6400SHanoh Haim
1220bd8b6400SHanoh Haim    TrexStatelessDpPerPort * lp_port = get_port_db(port_id);
1221bd8b6400SHanoh Haim
1222bd8b6400SHanoh Haim    lp_port->resume_traffic(port_id);
1223bd8b6400SHanoh Haim}
1224bd8b6400SHanoh Haim
1225bd8b6400SHanoh Haim
122603d70c42SIdo Barneavoid
1227bd8b6400SHanoh HaimTrexStatelessDpCore::pause_traffic(uint8_t port_id){
1228bd8b6400SHanoh Haim
1229bd8b6400SHanoh Haim    TrexStatelessDpPerPort * lp_port = get_port_db(port_id);
1230bd8b6400SHanoh Haim
1231bd8b6400SHanoh Haim    lp_port->pause_traffic(port_id);
1232bd8b6400SHanoh Haim}
1233bd8b6400SHanoh Haim
12348691f401Simaromvoid
123575ce59e5SimaromTrexStatelessDpCore::push_pcap(uint8_t port_id,
123675ce59e5Simarom                               int event_id,
123775ce59e5Simarom                               const std::string &pcap_filename,
123875ce59e5Simarom                               double ipg_usec,
1239e4c8e44bSYaroslav Brustinov                               double m_min_ipg_sec,
124075ce59e5Simarom                               double speedup,
1241db9145d2Simarom                               uint32_t count,
124204eae221Simarom                               double duration,
124304eae221Simarom                               bool is_dual) {
12448691f401Simarom
12458691f401Simarom    TrexStatelessDpPerPort * lp_port = get_port_db(port_id);
12468691f401Simarom
12478691f401Simarom    lp_port->set_event_id(event_id);
12488691f401Simarom
12498691f401Simarom    /* delegate the command to the port */
1250e4c8e44bSYaroslav Brustinov    bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, m_min_ipg_sec, speedup, count, is_dual);
12518691f401Simarom    if (!rc) {
12528691f401Simarom        /* report back that we stopped */
12538691f401Simarom        CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id);
12548691f401Simarom        TrexStatelessDpToCpMsgBase *event_msg = new TrexDpPortEventMsg(m_core->m_thread_id,
12558691f401Simarom                                                                       port_id,
12568691f401Simarom                                                                       event_id,
12578691f401Simarom                                                                       false);
12588691f401Simarom        ring->Enqueue((CGenNode *)event_msg);
12598691f401Simarom        return;
12608691f401Simarom    }
12618691f401Simarom
12628691f401Simarom
1263db9145d2Simarom    if (duration > 0.0) {
12648691f401Simarom        add_port_duration(duration, port_id, event_id);
12658691f401Simarom    }
1266db9145d2Simarom
1267db9145d2Simarom     m_state = TrexStatelessDpCore::STATE_PCAP_TX;
12688691f401Simarom}
12698691f401Simarom
127003d70c42SIdo Barneavoid
127159548ae8SimaromTrexStatelessDpCore::update_traffic(uint8_t port_id, double factor) {
1272d9a11302Simarom
1273d9a11302Simarom    TrexStatelessDpPerPort * lp_port = get_port_db(port_id);
1274d9a11302Simarom
127559548ae8Simarom    lp_port->update_traffic(port_id, factor);
1276d9a11302Simarom}
1277d9a11302Simarom
1278bd8b6400SHanoh Haim
1279ea0b6efcSimaromvoid
128059a3b58dSimaromTrexStatelessDpCore::stop_traffic(uint8_t  port_id,
128103d70c42SIdo Barnea                                  bool     stop_on_id,
128259a3b58dSimarom                                  int      event_id) {
12833978adceSimarom    /* we cannot remove nodes not from the top of the queue so
12843978adceSimarom       for every active node - make sure next time
12853978adceSimarom       the scheduler invokes it, it will be free */
12863978adceSimarom
12870e8c9ae6SHanoh Haim    TrexStatelessDpPerPort * lp_port = get_port_db(port_id);
12883408c030SHanoh Haim    if ( lp_port->stop_traffic(port_id,stop_on_id,event_id) == false){
128936dc8ea5SHanoh Haim        return;
129036dc8ea5SHanoh Haim    }
129159a3b58dSimarom
12928b1d07ffSimarom    /* flush the TX queue before sending done message to the CP */
12938b1d07ffSimarom    m_core->flush_tx_queue();
12948b1d07ffSimarom
1295a7317d45Simarom    CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id);
1296a7317d45Simarom    TrexStatelessDpToCpMsgBase *event_msg = new TrexDpPortEventMsg(m_core->m_thread_id,
1297a7317d45Simarom                                                                   port_id,
1298b094110eSimarom                                                                   lp_port->get_event_id());
1299a7317d45Simarom    ring->Enqueue((CGenNode *)event_msg);
130007e6795aSimarom
1301ea0b6efcSimarom}
1302ea0b6efcSimarom
1303ea0b6efcSimarom/**
1304ea0b6efcSimarom * handle a message from CP to DP
130503d70c42SIdo Barnea *
1306ea0b6efcSimarom */
130703d70c42SIdo Barneavoid
1308ea0b6efcSimaromTrexStatelessDpCore::handle_cp_msg(TrexStatelessCpToDpMsgBase *msg) {
1309ea0b6efcSimarom    msg->handle(this);
1310ea0b6efcSimarom    delete msg;
1311ea0b6efcSimarom}
1312ea0b6efcSimarom
131359a3b58dSimaromvoid
131459a3b58dSimaromTrexStatelessDpCore::barrier(uint8_t port_id, int event_id) {
131559a3b58dSimarom
131659a3b58dSimarom    CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id);
131759a3b58dSimarom    TrexStatelessDpToCpMsgBase *event_msg = new TrexDpPortEventMsg(m_core->m_thread_id,
131859a3b58dSimarom                                                                   port_id,
131959a3b58dSimarom                                                                   event_id);
132059a3b58dSimarom    ring->Enqueue((CGenNode *)event_msg);
132159a3b58dSimarom}
13228691f401Simarom
132317d58dbaSimaromvoid
132417d58dbaSimaromTrexStatelessDpCore::set_service_mode(uint8_t port_id, bool enabled) {
132517d58dbaSimarom    /* ignore the same message */
132617d58dbaSimarom    if (enabled == m_is_service_mode) {
132717d58dbaSimarom        return;
132817d58dbaSimarom    }
132917d58dbaSimarom
133017d58dbaSimarom    if (enabled) {
133117d58dbaSimarom        /* sanity */
133217d58dbaSimarom        assert(m_core->m_node_gen.m_v_if != m_wrapper);
133317d58dbaSimarom
133417d58dbaSimarom        /* set the wrapper object and make the VIF point to it */
133517d58dbaSimarom        m_wrapper->set_wrapped_object(m_core->m_node_gen.m_v_if);
133617d58dbaSimarom        m_core->m_node_gen.m_v_if = m_wrapper;
133717d58dbaSimarom        m_is_service_mode = true;
133817d58dbaSimarom
133917d58dbaSimarom    } else {
1340