trex_stateless_dp_core.cpp revision c0a49eef
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
28static inline double
29usec_to_sec(double usec) {
30    return (usec / (1000 * 1000));
31}
32
33TrexStatelessDpCore::TrexStatelessDpCore(uint8_t thread_id, CFlowGenListPerThread *core) {
34    m_thread_id = thread_id;
35    m_core = core;
36
37    CMessagingManager * cp_dp = CMsgIns::Ins()->getCpDp();
38
39    m_ring_from_cp = cp_dp->getRingCpToDp(thread_id);
40    m_ring_to_cp   = cp_dp->getRingDpToCp(thread_id);
41
42    m_state = STATE_IDLE;
43}
44
45/**
46 * in idle state loop, the processor most of the time sleeps
47 * and periodically checks for messages
48 *
49 * @author imarom (01-Nov-15)
50 */
51void
52TrexStatelessDpCore::idle_state_loop() {
53
54    while (m_state == STATE_IDLE) {
55        periodic_check_for_cp_messages();
56        delay(200);
57    }
58}
59
60/**
61 * scehduler runs when traffic exists
62 * it will return when no more transmitting is done on this
63 * core
64 *
65 * @author imarom (01-Nov-15)
66 */
67void
68TrexStatelessDpCore::start_scheduler() {
69    /* creates a maintenace job using the scheduler */
70    CGenNode * node_sync = m_core->create_node() ;
71    node_sync->m_type = CGenNode::FLOW_SYNC;
72    node_sync->m_time = m_core->m_cur_time_sec + SYNC_TIME_OUT;
73    m_core->m_node_gen.add_node(node_sync);
74
75    double old_offset = 0.0;
76    m_core->m_node_gen.flush_file(100000000, 0.0, false, m_core, old_offset);
77}
78
79void
80TrexStatelessDpCore::start() {
81
82    while (true) {
83        idle_state_loop();
84
85        start_scheduler();
86    }
87}
88
89void
90TrexStatelessDpCore::add_cont_stream(uint8_t port_id,
91                                     double isg_usec,
92                                     double pps,
93                                     const uint8_t *pkt,
94                                     uint16_t pkt_len) {
95
96    CGenNodeStateless *node = m_core->create_node_sl();
97
98    /* add periodic */
99    node->m_type = CGenNode::STATELESS_PKT;
100
101    node->m_time = m_core->m_cur_time_sec + usec_to_sec(isg_usec);
102
103    pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(port_id);
104    node->m_flags = 0;
105
106    /* set socket id */
107    node->set_socket_id(m_core->m_node_gen.m_socket_id);
108
109    /* build a mbuf from a packet */
110    uint16_t pkt_size = pkt_len;
111    const uint8_t *stream_pkt = pkt;
112
113    /* stateless specific fields */
114    node->m_next_time_offset = 1.0 / pps;
115    node->m_is_stream_active = 1;
116    node->m_port_id = port_id;
117
118    /* allocate const mbuf */
119    rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), pkt_size);
120    assert(m);
121
122    char *p = rte_pktmbuf_append(m, pkt_size);
123    assert(p);
124    /* copy the packet */
125    memcpy(p,stream_pkt,pkt_size);
126
127    /* set dir 0 or 1 client or server */
128    node->set_mbuf_cache_dir(dir);
129
130    /* TBD repace the mac if req we should add flag  */
131    m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir, m);
132
133    /* set the packet as a readonly */
134    node->set_cache_mbuf(m);
135
136    /* keep track */
137    m_active_nodes.push_back(node);
138
139    /* schedule */
140    m_core->m_node_gen.add_node((CGenNode *)node);
141
142    m_state = TrexStatelessDpCore::STATE_TRANSMITTING;
143
144}
145
146void
147TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) {
148    for (auto single_stream : obj->get_objects()) {
149        add_cont_stream(single_stream.m_port_id,
150                        single_stream.m_isg_usec,
151                        single_stream.m_pps,
152                        single_stream.m_pkt,
153                        single_stream.m_pkt_len);
154    }
155}
156
157void
158TrexStatelessDpCore::stop_traffic(uint8_t port_id) {
159    /* we cannot remove nodes not from the top of the queue so
160       for every active node - make sure next time
161       the scheduler invokes it, it will be free */
162    for (auto node : m_active_nodes) {
163        if (node->m_port_id == port_id) {
164            node->m_is_stream_active = 0;
165        }
166    }
167
168    /* remove all the non active nodes */
169    auto pred = std::remove_if(m_active_nodes.begin(),
170                               m_active_nodes.end(),
171                               [](CGenNodeStateless *node) { return (!node->m_is_stream_active); });
172
173    m_active_nodes.erase(pred, m_active_nodes.end());
174
175    if (m_active_nodes.size() == 0) {
176        m_state = STATE_IDLE;
177        /* stop the scheduler */
178
179         CGenNode *node = m_core->create_node() ;
180
181         node->m_type = CGenNode::EXIT_SCHED;
182
183         /* make sure it will be scheduled after the current node */
184         node->m_time = m_core->m_node_gen.m_p_queue.top()->m_time;
185
186         m_core->m_node_gen.add_node(node);
187    }
188
189}
190
191/**
192 * handle a message from CP to DP
193 *
194 */
195void
196TrexStatelessDpCore::handle_cp_msg(TrexStatelessCpToDpMsgBase *msg) {
197    msg->handle(this);
198    delete msg;
199}
200
201