trex_stateless_rx_core.cpp revision 3e8d1108
1/*
2  Ido Barnea
3  Cisco Systems, Inc.
4*/
5
6/*
7  Copyright (c) 2016-2016 Cisco Systems, Inc.
8
9  Licensed under the Apache License, Version 2.0 (the "License");
10  you may not use this file except in compliance with the License.
11  You may obtain a copy of the License at
12
13  http://www.apache.org/licenses/LICENSE-2.0
14
15  Unless required by applicable law or agreed to in writing, software
16  distributed under the License is distributed on an "AS IS" BASIS,
17  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  See the License for the specific language governing permissions and
19  limitations under the License.
20*/
21
22#include <stdio.h>
23#include "bp_sim.h"
24#include "flow_stat_parser.h"
25#include "stateful_rx_core.h"
26#include "pal/linux/sanb_atomic.h"
27#include "trex_stateless_messaging.h"
28#include "trex_stateless_rx_core.h"
29#include "trex_stateless.h"
30
31
32void CRFC2544Info::create() {
33    m_latency.Create();
34    m_exp_flow_seq = 0;
35    m_prev_flow_seq = 0;
36    reset();
37}
38
39// after calling stop, packets still arriving will be considered error
40void CRFC2544Info::stop() {
41    if (m_exp_flow_seq != FLOW_STAT_PAYLOAD_INITIAL_FLOW_SEQ) {
42        m_prev_flow_seq = m_exp_flow_seq;
43        m_exp_flow_seq = FLOW_STAT_PAYLOAD_INITIAL_FLOW_SEQ;
44    }
45}
46
47void CRFC2544Info::reset() {
48    // This is the seq num value we expect next packet to have.
49    // Init value should match m_seq_num in CVirtualIFPerSideStats
50    m_seq = UINT32_MAX - 1;  // catch wrap around issues early
51    m_seq_err = 0;
52    m_seq_err_events_too_big = 0;
53    m_seq_err_events_too_low = 0;
54    m_ooo = 0;
55    m_dup = 0;
56    m_latency.Reset();
57    m_jitter.reset();
58}
59
60void CRFC2544Info::export_data(rfc2544_info_t_ &obj) {
61    std::string json_str;
62    Json::Reader reader;
63    Json::Value json;
64
65    obj.set_err_cntrs(m_seq_err, m_ooo, m_dup, m_seq_err_events_too_big, m_seq_err_events_too_low);
66    obj.set_jitter(m_jitter.get_jitter());
67    m_latency.dump_json(json);
68    obj.set_latency_json(json);
69};
70
71void CRxCoreStateless::create(const CRxSlCfg &cfg) {
72    m_capture = false;
73    m_max_ports = cfg.m_max_ports;
74    m_tx_cores  = cfg.m_tx_cores;
75
76    CMessagingManager * cp_rx = CMsgIns::Ins()->getCpRx();
77
78    m_ring_from_cp = cp_rx->getRingCpToDp(0);
79    m_state = STATE_IDLE;
80
81    for (int i = 0; i < MAX_FLOW_STATS_PAYLOAD; i++) {
82        m_rfc2544[i].create();
83    }
84
85    m_cpu_cp_u.Create(&m_cpu_dp_u);
86
87    /* create per port manager */
88    for (int i = 0; i < m_max_ports; i++) {
89        const TRexPortAttr *port_attr = get_stateless_obj()->get_platform_api()->getPortAttrObj(i);
90        m_rx_port_mngr[i].create(port_attr,
91                                 cfg.m_ports[i],
92                                 m_rfc2544,
93                                 &m_err_cntrs,
94                                 &m_cpu_dp_u,
95                                 cfg.m_num_crc_fix_bytes);
96    }
97}
98
99void CRxCoreStateless::handle_cp_msg(TrexStatelessCpToRxMsgBase *msg) {
100    msg->handle(this);
101    delete msg;
102}
103
104void CRxCoreStateless::tickle() {
105    m_monitor.tickle();
106}
107
108bool CRxCoreStateless::periodic_check_for_cp_messages() {
109
110    /* tickle the watchdog */
111    tickle();
112
113    /* fast path */
114    if ( likely ( m_ring_from_cp->isEmpty() ) ) {
115        return false;
116    }
117
118    while ( true ) {
119        CGenNode * node = NULL;
120
121        if (m_ring_from_cp->Dequeue(node) != 0) {
122            break;
123        }
124        assert(node);
125        TrexStatelessCpToRxMsgBase * msg = (TrexStatelessCpToRxMsgBase *)node;
126        handle_cp_msg(msg);
127    }
128
129    /* a message might result in a change of state */
130    recalculate_next_state();
131    return true;
132
133}
134
135void
136CRxCoreStateless::periodic_check_for_dp_messages() {
137
138    for (int i = 0; i < m_tx_cores; i++) {
139        periodic_check_for_dp_messages_core(i);
140    }
141
142}
143
144void
145CRxCoreStateless::periodic_check_for_dp_messages_core(uint32_t core_id) {
146
147    CNodeRing *ring = CMsgIns::Ins()->getRxDp()->getRingDpToCp(core_id);
148
149    /* fast path */
150    if ( likely ( ring->isEmpty() ) ) {
151        return;
152    }
153
154    while (true) {
155        CGenNode *node = NULL;
156
157        if (ring->Dequeue(node) != 0) {
158            break;
159        }
160
161        //assert(node);
162    }
163}
164
165void CRxCoreStateless::recalculate_next_state() {
166    if (m_state == STATE_QUIT) {
167        return;
168    }
169
170    /* next state is determine by the question are there any ports with active features ? */
171    m_state = (are_any_features_active() ? STATE_WORKING : STATE_IDLE);
172}
173
174bool CRxCoreStateless::are_any_features_active() {
175    for (int i = 0; i < m_max_ports; i++) {
176        if (m_rx_port_mngr[i].has_features_set()) {
177            return true;
178        }
179    }
180
181    return false;
182}
183
184void CRxCoreStateless::idle_state_loop() {
185    const int SHORT_DELAY_MS    = 2;
186    const int LONG_DELAY_MS     = 50;
187    const int DEEP_SLEEP_LIMIT  = 2000;
188
189    int counter = 0;
190
191    while (m_state == STATE_IDLE) {
192        bool had_msg = periodic_check_for_cp_messages();
193        if (had_msg) {
194            counter = 0;
195            continue;
196        } else {
197            flush_all_pending_pkts();
198        }
199
200        /* enter deep sleep only if enough time had passed */
201        if (counter < DEEP_SLEEP_LIMIT) {
202            delay(SHORT_DELAY_MS);
203            counter++;
204        } else {
205            delay(LONG_DELAY_MS);
206        }
207    }
208}
209
210/**
211 * for each port handle the grat ARP mechansim
212 *
213 */
214void CRxCoreStateless::handle_grat_arp() {
215    for (int i = 0; i < m_max_ports; i++) {
216        m_rx_port_mngr[i].send_next_grat_arp();
217    }
218}
219
220void CRxCoreStateless::handle_work_stage() {
221
222    /* set the next sync time to */
223    dsec_t sync_time_sec = now_sec() + (1.0 / 1000);
224    dsec_t grat_arp_sec  = now_sec() + (double)CGlobalInfo::m_options.m_arp_ref_per;
225
226    while (m_state == STATE_WORKING) {
227        process_all_pending_pkts();
228
229        dsec_t now = now_sec();
230
231        /* until a scheduler is added here - dirty IFs */
232
233        if ( (now - sync_time_sec) > 0 ) {
234            periodic_check_for_cp_messages();
235            //periodic_check_for_dp_messages();
236            sync_time_sec = now + (1.0 / 1000);
237        }
238
239        if ( (now - grat_arp_sec) > 0) {
240            handle_grat_arp();
241            grat_arp_sec = now + (double)CGlobalInfo::m_options.m_arp_ref_per;
242        }
243
244        rte_pause();
245
246    }
247}
248
249void CRxCoreStateless::start() {
250    /* register a watchdog handle on current core */
251    m_monitor.create("STL RX CORE", 1);
252    TrexWatchDog::getInstance().register_monitor(&m_monitor);
253
254    recalculate_next_state();
255
256    while (m_state != STATE_QUIT) {
257        switch (m_state) {
258        case STATE_IDLE:
259            idle_state_loop();
260            break;
261        case STATE_WORKING:
262            handle_work_stage();
263            break;
264
265        default:
266            assert(0);
267            break;
268        }
269
270    }
271
272    m_monitor.disable();
273}
274
275int CRxCoreStateless::process_all_pending_pkts(bool flush_rx) {
276
277    int total_pkts = 0;
278    for (int i = 0; i < m_max_ports; i++) {
279        total_pkts += m_rx_port_mngr[i].process_all_pending_pkts(flush_rx);
280    }
281
282    return total_pkts;
283
284}
285
286void CRxCoreStateless::reset_rx_stats(uint8_t port_id) {
287    m_rx_port_mngr[port_id].clear_stats();
288}
289
290int CRxCoreStateless::get_rx_stats(uint8_t port_id, rx_per_flow_t *rx_stats, int min, int max
291                                   , bool reset, TrexPlatformApi::driver_stat_cap_e type) {
292
293    /* for now only latency stats */
294    m_rx_port_mngr[port_id].get_latency_stats(rx_stats, min, max, reset, type);
295
296    return (0);
297
298}
299
300int CRxCoreStateless::get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, int max, bool reset) {
301    for (int hw_id = min; hw_id <= max; hw_id++) {
302        CRFC2544Info &curr_rfc2544 = m_rfc2544[hw_id];
303
304        if (reset) {
305            // need to stop first, so count will be consistent
306            curr_rfc2544.stop();
307        }
308
309        curr_rfc2544.sample_period_end();
310        curr_rfc2544.export_data(rfc2544_info[hw_id - min]);
311
312        if (reset) {
313            curr_rfc2544.reset();
314        }
315    }
316    return 0;
317}
318
319int CRxCoreStateless::get_rx_err_cntrs(CRxCoreErrCntrs *rx_err) {
320    *rx_err = m_err_cntrs;
321    return 0;
322}
323
324void CRxCoreStateless::update_cpu_util(){
325    m_cpu_cp_u.Update();
326}
327
328double CRxCoreStateless::get_cpu_util() {
329    return m_cpu_cp_u.GetVal();
330}
331
332
333void
334CRxCoreStateless::start_queue(uint8_t port_id, uint64_t size) {
335    m_rx_port_mngr[port_id].start_queue(size);
336    recalculate_next_state();
337}
338
339void
340CRxCoreStateless::stop_queue(uint8_t port_id) {
341    m_rx_port_mngr[port_id].stop_queue();
342    recalculate_next_state();
343}
344
345void
346CRxCoreStateless::enable_latency() {
347    for (int i = 0; i < m_max_ports; i++) {
348        m_rx_port_mngr[i].enable_latency();
349    }
350
351    recalculate_next_state();
352}
353
354void
355CRxCoreStateless::disable_latency() {
356    for (int i = 0; i < m_max_ports; i++) {
357        m_rx_port_mngr[i].disable_latency();
358    }
359
360    recalculate_next_state();
361}
362
363RXPortManager &
364CRxCoreStateless::get_rx_port_mngr(uint8_t port_id) {
365    assert(port_id < m_max_ports);
366    return m_rx_port_mngr[port_id];
367
368}
369
370void
371CRxCoreStateless::get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff) {
372    get_rx_port_mngr(port_id).get_ignore_stats(stat, get_diff);
373}
374