trex_stateless_dp_core.cpp revision ee2c7f45
1/*
2 Itay Marom
3 Cisco Systems, Inc.
4*/
5
6/*
7Copyright (c) 2015-2015 Cisco Systems, Inc.
8
9Licensed under the Apache License, Version 2.0 (the "License");
10you may not use this file except in compliance with the License.
11You may obtain a copy of the License at
12
13    http://www.apache.org/licenses/LICENSE-2.0
14
15Unless required by applicable law or agreed to in writing, software
16distributed under the License is distributed on an "AS IS" BASIS,
17WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18See the License for the specific language governing permissions and
19limitations under the License.
20*/
21#include <trex_stateless_dp_core.h>
22#include <trex_stateless_messaging.h>
23#include <trex_streams_compiler.h>
24#include <trex_stream_node.h>
25
26#include <bp_sim.h>
27
28TrexStatelessDpCore::TrexStatelessDpCore(uint8_t thread_id, CFlowGenListPerThread *core) {
29    m_thread_id = thread_id;
30    m_core = core;
31
32    CMessagingManager * cp_dp = CMsgIns::Ins()->getCpDp();
33
34    m_ring_from_cp = cp_dp->getRingCpToDp(thread_id);
35    m_ring_to_cp   = cp_dp->getRingDpToCp(thread_id);
36
37    m_state = STATE_IDLE;
38}
39
40/**
41 * in idle state loop, the processor most of the time sleeps
42 * and periodically checks for messages
43 *
44 * @author imarom (01-Nov-15)
45 */
46void
47TrexStatelessDpCore::idle_state_loop() {
48
49    while (m_state == STATE_IDLE) {
50        periodic_check_for_cp_messages();
51        delay(200);
52    }
53}
54
55/**
56 * scehduler runs when traffic exists
57 * it will return when no more transmitting is done on this
58 * core
59 *
60 * @author imarom (01-Nov-15)
61 */
62void
63TrexStatelessDpCore::start_scheduler() {
64    /* creates a maintenace job using the scheduler */
65    CGenNode * node_sync = m_core->create_node() ;
66    node_sync->m_type = CGenNode::FLOW_SYNC;
67    node_sync->m_time = m_core->m_cur_time_sec + SYNC_TIME_OUT;
68    m_core->m_node_gen.add_node(node_sync);
69
70    double old_offset = 0.0;
71    m_core->m_node_gen.flush_file(100000000, 0.0, false, m_core, old_offset);
72}
73
74void
75TrexStatelessDpCore::start() {
76
77    while (true) {
78        idle_state_loop();
79
80        start_scheduler();
81    }
82}
83
84void
85TrexStatelessDpCore::add_cont_stream(double pps, const uint8_t *pkt, uint16_t pkt_len) {
86    CGenNodeStateless *node = m_core->create_node_sl();
87
88    /* add periodic */
89    node->m_type = CGenNode::STATELESS_PKT;
90    node->m_time = m_core->m_cur_time_sec + 0.0 /* STREAM ISG */;
91    node->m_flags = 0;
92
93    /* set socket id */
94    node->set_socket_id(m_core->m_node_gen.m_socket_id);
95
96    /* build a mbuf from a packet */
97    uint16_t pkt_size = pkt_len;
98    const uint8_t *stream_pkt = pkt;
99
100    node->m_next_time_offset = 1.0 / pps;
101    node->m_is_stream_active = 1;
102
103    /* allocate const mbuf */
104    rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), pkt_size);
105    assert(m);
106
107    char *p = rte_pktmbuf_append(m, pkt_size);
108    assert(p);
109    /* copy the packet */
110    memcpy(p,stream_pkt,pkt_size);
111
112    /* set dir 0 or 1 client or server */
113    pkt_dir_t dir = 0;
114    node->set_mbuf_cache_dir(dir);
115
116    /* TBD repace the mac if req we should add flag  */
117    m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir, m);
118
119    /* set the packet as a readonly */
120    node->set_cache_mbuf(m);
121
122    /* keep track */
123    m_active_nodes.push_back(node);
124
125    /* schedule */
126    m_core->m_node_gen.add_node((CGenNode *)node);
127
128    m_state = TrexStatelessDpCore::STATE_TRANSMITTING;
129
130}
131
132void
133TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) {
134    for (auto single_stream : obj->get_objects()) {
135        add_cont_stream(single_stream.m_pps, single_stream.m_pkt, single_stream.m_pkt_len);
136    }
137}
138
139void
140TrexStatelessDpCore::stop_traffic(uint8_t port_id) {
141    /* we cannot remove nodes not from the top of the queue so
142       for every active node - make sure next time
143       the scheduler invokes it, it will be free */
144    for (auto node : m_active_nodes) {
145        if (node->m_port_id == port_id) {
146            node->m_is_stream_active = 0;
147        }
148    }
149
150    /* remove all the non active nodes */
151    auto pred = std::remove_if(m_active_nodes.begin(),
152                               m_active_nodes.end(),
153                               [](CGenNodeStateless *node) { return (!node->m_is_stream_active); });
154
155    m_active_nodes.erase(pred, m_active_nodes.end());
156
157    if (m_active_nodes.size() == 0) {
158        m_state = STATE_IDLE;
159        /* stop the scheduler */
160
161         CGenNode *node = m_core->create_node() ;
162
163         node->m_type = CGenNode::EXIT_SCHED;
164
165         /* make sure it will be scheduled after the current node */
166         node->m_time = m_core->m_node_gen.m_p_queue.top()->m_time;
167
168         m_core->m_node_gen.add_node(node);
169    }
170
171}
172
173/**
174 * handle a message from CP to DP
175 *
176 */
177void
178TrexStatelessDpCore::handle_cp_msg(TrexStatelessCpToDpMsgBase *msg) {
179    msg->handle(this);
180    delete msg;
181}
182
183