1/*
2 Itay Marom
3 Hanoch Haim
4 Cisco Systems, Inc.
5*/
6
7/*
8Copyright (c) 2015-2015 Cisco Systems, Inc.
9
10Licensed under the Apache License, Version 2.0 (the "License");
11you may not use this file except in compliance with the License.
12You may obtain a copy of the License at
13
14    http://www.apache.org/licenses/LICENSE-2.0
15
16Unless required by applicable law or agreed to in writing, software
17distributed under the License is distributed on an "AS IS" BASIS,
18WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19See the License for the specific language governing permissions and
20limitations under the License.
21*/
22#ifndef __TREX_STREAM_H__
23#define __TREX_STREAM_H__
24
25#include <stdio.h>
26#include <string.h>
27
28#include <unordered_map>
29#include <vector>
30#include <stdint.h>
31#include <string>
32
33#include <json/json.h>
34
35#include "os_time.h"
36#include "trex_stream_vm.h"
37#include <common/captureFile.h>
38#include <common/bitMan.h>
39#include "internal_api/trex_platform_api.h"
40
41
42class TrexRpcCmdAddStream;
43
44
45static inline uint16_t get_log2_size(uint16_t size){
46
47    uint16_t _sizes[]={64,128,256,512,1024,2048};
48    int i;
49    for (i=0; i<sizeof(_sizes)/sizeof(_sizes[0]); i++) {
50        if (size<=_sizes[i]) {
51            return (_sizes[i]);
52        }
53    }
54    assert(0);
55    return (0);
56}
57
58/**
59 *  calculate the size of writable mbuf in bytes. maximum size if packet size
60 *
61 * @param max_offset_writable
62 *                 the last byte that we don't write too. for example when 63 it means that bytes [62] in the array is written (zero base)
63 * @param pkt_size packet size in bytes
64 *
65 * @return the writable size of the first mbuf . the idea is to give at least 64 bytes const mbuf else all packet will be writeable
66 *
67 * examples:
68 *       max_offset_writable =63
69 *       pkt_size =62
70 *        ==>62
71 *
72 */
73
74static inline uint16_t calc_writable_mbuf_size(uint16_t max_offset_writable,
75                                               uint16_t pkt_size){
76
77    if (pkt_size<=128) {
78        return (pkt_size);
79    }
80
81    //pkt_size> 128
82    // if reside is less than 64 keep it as a single packet
83    uint16_t non_writable = pkt_size - (max_offset_writable +1) ;
84    if ( non_writable<64 ) {
85        return (pkt_size);
86    }
87
88    // keep the r/w at least 60 byte
89    if ((max_offset_writable+1)<=60) {
90        return 60;
91    }
92    return max_offset_writable+1;
93}
94
95
96
97struct CStreamPktData {
98        uint8_t      *binary;
99        uint16_t      len;
100
101        std::string   meta;
102
103public:
104        inline void clone(uint8_t  * in_binary,
105                          uint32_t in_pkt_size){
106            binary = new uint8_t[in_pkt_size];
107            len    = in_pkt_size;
108            memcpy(binary,in_binary,in_pkt_size);
109        }
110};
111
112class TrexStream;
113
114/**
115 * describes a stream rate
116 *
117 * @author imarom (18-Feb-16)
118 */
119class TrexStreamRate {
120
121
122public:
123
124    enum rate_type_e {
125        RATE_INVALID,
126        RATE_PPS,
127        RATE_BPS_L1,
128        RATE_BPS_L2,
129        RATE_PERCENTAGE
130    };
131
132    TrexStreamRate(TrexStream &stream) : m_stream(stream) {
133        m_pps        = 0;
134        m_bps_L1     = 0;
135        m_bps_L2     = 0;
136        m_percentage = 0;
137    }
138
139
140    TrexStreamRate& operator=(const TrexStreamRate& other) {
141        m_pps        = other.m_pps;
142        m_bps_L1     = other.m_bps_L1;
143        m_bps_L2     = other.m_bps_L2;
144        m_percentage = other.m_percentage;
145
146        return (*this);
147    }
148
149    /**
150     * set the base rate
151     * other values will be dervied from this value
152     *
153     */
154    void set_base_rate(rate_type_e type, double value) {
155        m_pps        = 0;
156        m_bps_L1     = 0;
157        m_bps_L2     = 0;
158        m_percentage = 0;
159
160        assert(value > 0);
161
162        switch (type) {
163        case RATE_PPS:
164            m_pps = value;
165            break;
166        case RATE_BPS_L1:
167            m_bps_L1 = value;
168            break;
169        case RATE_BPS_L2:
170            m_bps_L2 = value;
171            break;
172        case RATE_PERCENTAGE:
173            m_percentage = value;
174            break;
175
176        default:
177            assert(0);
178
179        }
180    }
181
182    double get_pps() {
183        if (m_pps == 0) {
184            calculate();
185        }
186        return (m_pps);
187    }
188
189    double get_bps_L1() {
190        if (m_bps_L1 == 0) {
191            calculate();
192        }
193        return (m_bps_L1);
194    }
195
196    double get_bps_L2() {
197        if (m_bps_L2 == 0) {
198            calculate();
199        }
200        return m_bps_L2;
201    }
202
203    double get_percentage() {
204        if (m_percentage == 0) {
205            calculate();
206        }
207        return m_percentage;
208    }
209
210
211
212    /* update the rate by a factor */
213    void update_factor(double factor) {
214        /* if all are non zero - it works, if only one (base) is also works */
215        m_pps        *= factor;
216        m_bps_L1     *= factor;
217        m_bps_L2     *= factor;
218        m_percentage *= factor;
219    }
220
221
222
223private:
224
225    /**
226     * calculates all the rates from the base rate
227     *
228     */
229    void calculate() {
230
231        if (m_pps != 0) {
232            calculate_from_pps();
233        } else if (m_bps_L1 != 0) {
234            calculate_from_bps_L1();
235        } else if (m_bps_L2 != 0) {
236            calculate_from_bps_L2();
237        } else if (m_percentage != 0) {
238            calculate_from_percentage();
239        } else {
240            assert(0);
241        }
242    }
243
244
245    uint64_t get_line_speed_bps();
246    double get_pkt_size();
247
248    void calculate_from_pps() {
249        m_bps_L1     = m_pps * (get_pkt_size() + 20) * 8;
250        m_bps_L2     = m_pps * get_pkt_size() * 8;
251        m_percentage = (m_bps_L1 / get_line_speed_bps()) * 100.0;
252    }
253
254
255    void calculate_from_bps_L1() {
256        m_bps_L2     = m_bps_L1 * ( get_pkt_size() / (get_pkt_size() + 20.0) );
257        m_pps        = m_bps_L2 / (8 * get_pkt_size());
258        m_percentage = (m_bps_L1 / get_line_speed_bps()) * 100.0;
259    }
260
261
262    void calculate_from_bps_L2() {
263        m_bps_L1     = m_bps_L2 * ( (get_pkt_size() + 20.0) / get_pkt_size());
264        m_pps        = m_bps_L2 / (8 * get_pkt_size());
265        m_percentage = (m_bps_L1 / get_line_speed_bps()) * 100.0;
266    }
267
268    void calculate_from_percentage() {
269        m_bps_L1     = (m_percentage / 100.0) * get_line_speed_bps();
270        m_bps_L2     = m_bps_L1 * ( get_pkt_size() / (get_pkt_size() + 20.0) );
271        m_pps        = m_bps_L2 / (8 * get_pkt_size());
272
273    }
274
275    double       m_pps;
276    double       m_bps_L1;
277    double       m_bps_L2;
278    double       m_percentage;
279
280    /* reference to the owner class */
281    TrexStream  &m_stream;
282};
283
284/**
285 * Stateless Stream
286 *
287 */
288class TrexStream {
289friend class TrexStreamRate;
290
291public:
292    enum STREAM_TYPE {
293        stNONE         = 0,
294        stCONTINUOUS   = 4,
295        stSINGLE_BURST = 5,
296        stMULTI_BURST  = 6
297    };
298
299    typedef uint8_t stream_type_t ;
300
301    enum DST_MAC_TYPE {
302        stCFG_FILE     = 0,
303        stPKT          = 1,
304        stARP          = 2
305    };
306
307    typedef uint8_t stream_dst_mac_t ;
308
309
310    static std::string get_stream_type_str(stream_type_t stream_type);
311
312public:
313    TrexStream(uint8_t type,uint8_t port_id, uint32_t stream_id);
314    virtual ~TrexStream();
315
316    /* defines the min max per packet supported */
317    static const uint32_t MIN_PKT_SIZE_BYTES = 14;
318    static const uint32_t MAX_PKT_SIZE_BYTES = MAX_PKT_SIZE;
319
320    /* provides storage for the stream json*/
321    void store_stream_json(const Json::Value &stream_json);
322
323    /* access the stream json */
324    const Json::Value & get_stream_json();
325
326    /* compress the stream id to be zero based */
327    void fix_dp_stream_id(uint32_t my_stream_id,int next_stream_id){
328        m_stream_id      = my_stream_id;
329        m_next_stream_id = next_stream_id;
330    }
331
332
333    double get_pps() {
334        return m_rate.get_pps();
335    }
336
337    double get_bps_L1() {
338        return m_rate.get_bps_L1();
339    }
340
341    double get_bps_L2() {
342        return m_rate.get_bps_L2();
343    }
344
345    double get_bw_percentage() {
346        return m_rate.get_percentage();
347    }
348
349    void set_rate(TrexStreamRate::rate_type_e type, double value) {
350        m_rate.set_base_rate(type, value);
351    }
352
353    void update_rate_factor(double factor) {
354        /* fixed rate streams cannot be updated in rate */
355        if (!is_fixed_rate_stream()) {
356            m_rate.update_factor(factor);
357        }
358    }
359
360    void set_type(uint8_t type){
361        m_type = type;
362    }
363
364    void set_null_stream(bool enable) {
365        m_null_stream = enable;
366    }
367
368    uint8_t get_type(void) const {
369        return ( m_type );
370    }
371
372    bool is_dp_next_stream() {
373        if (m_next_stream_id<0) {
374            return (false);
375        }else{
376            return (true);
377        }
378    }
379
380    bool is_latency_stream() const {
381        return (m_rx_check.m_enabled && (m_rx_check.m_rule_type == TrexPlatformApi::IF_STAT_PAYLOAD));
382    }
383
384    bool is_fixed_rate_stream() const {
385        return is_latency_stream();
386    }
387
388    /* can this stream be split ? */
389    bool is_splitable(uint8_t dp_core_count) const {
390
391        if (is_latency_stream()) {
392            // because of sequence number, can't split streams with payload rule to different cores
393            return false;
394        }
395
396        /* cont stream is always splitable */
397        if (m_type == stCONTINUOUS) {
398            return true;
399        }
400
401        int per_core_burst_total_pkts = (m_burst_total_pkts / dp_core_count);
402
403        return (per_core_burst_total_pkts > 0);
404
405    }
406
407    void set_multi_burst(uint32_t   burst_total_pkts,
408                         uint32_t   num_bursts,
409                         double     ibg_usec) {
410        m_burst_total_pkts = burst_total_pkts;
411        m_num_bursts       = num_bursts;
412        m_ibg_usec         = ibg_usec;
413    }
414
415    void set_single_burst(uint32_t   burst_total_pkts){
416        set_multi_burst(burst_total_pkts,1,0.0);
417    }
418
419
420    /* create new stream */
421    TrexStream * clone(bool full = false) const {
422
423        /* not all fields will be cloned */
424
425        TrexStream *dp = new TrexStream(m_type,m_port_id,m_stream_id);
426
427        /* on full clone we copy also VM */
428        if (full) {
429            m_vm.clone(dp->m_vm);
430
431        }
432
433        /* copy VM DP product */
434        if (m_vm_dp) {
435            dp->m_vm_dp = m_vm_dp->clone();
436        } else {
437            dp->m_vm_dp = NULL;
438        }
439
440        dp->m_isg_usec                = m_isg_usec;
441
442        /* multi core phase paramters */
443        dp->m_mc_phase_pre_sec            = m_mc_phase_pre_sec;
444        dp->m_mc_phase_post_sec           = m_mc_phase_post_sec;
445
446        dp->m_next_stream_id          = m_next_stream_id;
447
448        dp->m_enabled    = m_enabled;
449        dp->m_self_start = m_self_start;
450
451        /* deep copy */
452        dp->m_pkt.clone(m_pkt.binary,m_pkt.len);
453
454        dp->m_expected_pkt_len      =   m_expected_pkt_len;
455        dp->m_rx_check              =   m_rx_check;
456        dp->m_burst_total_pkts      =   m_burst_total_pkts;
457        dp->m_num_bursts            =   m_num_bursts;
458        dp->m_ibg_usec              =   m_ibg_usec;
459        dp->m_flags                 =   m_flags;
460        dp->m_cache_size            =   m_cache_size;
461        dp->m_action_count          =   m_action_count;
462        dp->m_random_seed           =   m_random_seed;
463
464        dp->m_rate                  =   m_rate;
465
466        return(dp);
467    }
468
469    /* release the DP object */
470    void release_dp_object() {
471        if (m_vm_dp) {
472            delete m_vm_dp;
473            m_vm_dp = NULL;
474        }
475    }
476
477    double get_burst_length_usec()  {
478        return ( (m_burst_total_pkts / get_pps()) * 1000 * 1000);
479    }
480
481    double get_ipg_sec() {
482        return (1.0 / get_pps());
483    }
484
485    /* return the delay before starting a stream */
486    inline double get_start_delay_sec() {
487        return usec_to_sec(m_isg_usec) + m_mc_phase_pre_sec;
488    }
489
490    /* return the delay before starting the next stream */
491    inline double get_next_stream_delay_sec() {
492        return m_mc_phase_post_sec;
493    }
494
495    /* return the delay between scheduling a new burst in a multi burst stream */
496    inline double get_next_burst_delay_sec() {
497        return usec_to_sec(m_ibg_usec) + m_mc_phase_post_sec + m_mc_phase_pre_sec;
498    }
499
500    void Dump(FILE *fd);
501
502    StreamVmDp * getDpVm(){
503        return (m_vm_dp);
504    }
505
506    /**
507     * internal compilation of stream (for DP)
508     *
509     */
510    void vm_compile();
511
512public:
513
514    void set_override_src_mac_by_pkt_data(bool enable){
515        btSetMaskBit16(m_flags,0,0,enable?1:0);
516    }
517
518    bool get_override_src_mac_by_pkt_data(){
519        return (btGetMaskBit16(m_flags,0,0) ?true:false);
520    }
521
522    void set_override_dst_mac_mode(stream_dst_mac_t  val){
523        btSetMaskBit16(m_flags,2,1,val&0x3);
524    }
525
526    stream_dst_mac_t get_override_dst_mac_mode(){
527        return ((stream_dst_mac_t)btGetMaskBit16(m_flags,2,1));
528    }
529
530public:
531    /* basic */
532    uint8_t       m_type;
533    uint8_t       m_port_id;
534    uint16_t      m_flags;
535
536    uint32_t      m_stream_id;              /* id from RPC can be anything */
537    uint16_t      m_action_count;
538    uint16_t      m_cache_size;
539    uint32_t      m_random_seed;
540
541
542    /* config fields */
543    double        m_mc_phase_pre_sec;
544    double        m_mc_phase_post_sec;
545
546    double        m_isg_usec;
547    int           m_next_stream_id;
548
549    /* indicators */
550    bool          m_enabled;
551    bool          m_self_start;
552
553    /* null stream (a dummy stream) */
554    bool          m_null_stream;
555
556    /* VM CP and DP */
557    StreamVm      m_vm;
558    StreamVmDp   *m_vm_dp;
559
560    CStreamPktData   m_pkt;
561    double           m_expected_pkt_len;
562
563    /* pkt */
564
565
566    /* RX check */
567    struct {
568        bool      m_enabled;
569        bool      m_seq_enabled;
570        bool      m_latency;
571        uint16_t  m_rule_type;
572        uint32_t  m_pg_id;
573        uint16_t  m_hw_id;
574    } m_rx_check;
575
576    uint32_t   m_burst_total_pkts; /* valid in case of burst stSINGLE_BURST,stMULTI_BURST*/
577
578    uint32_t   m_num_bursts; /* valid in case of stMULTI_BURST */
579
580    double     m_ibg_usec;  /* valid in case of stMULTI_BURST */
581
582    /* original template provided by requester */
583    Json::Value m_stream_json;
584
585private:
586
587    double get_pkt_size() {
588        /* lazy calculate the expected packet length */
589        if (m_expected_pkt_len == 0) {
590            /* if we have a VM - it might have changed the packet (even random) */
591            if (m_vm.is_vm_empty()) {
592                m_expected_pkt_len = m_pkt.len;
593            } else {
594                m_expected_pkt_len = m_vm.calc_expected_pkt_size(m_pkt.len);
595            }
596        }
597
598        return m_expected_pkt_len;
599    }
600
601
602    /* no access to this without a lazy build method */
603    TrexStreamRate m_rate;
604};
605
606
607/**
608 * holds all the streams
609 *
610 */
611class TrexStreamTable {
612public:
613
614    TrexStreamTable();
615    ~TrexStreamTable();
616
617    /**
618     * add a stream
619     * if a previous one exists, the old one  will be deleted
620     */
621    void add_stream(TrexStream *stream);
622
623    /**
624     * remove a stream
625     */
626    void remove_stream(TrexStream *stream);
627
628
629    /**
630     * fetch a stream if exists
631     * o.w NULL
632     *
633     */
634    TrexStream * get_stream_by_id(uint32_t stream_id);
635
636    /**
637     * get max stream ID assigned
638     *
639     *
640     * @return int
641     */
642    int get_max_stream_id() const;
643
644    /**
645     * populate a list with all the stream IDs
646     *
647     * @author imarom (06-Sep-15)
648     *
649     * @param stream_list
650     */
651    void get_id_list(std::vector<uint32_t> &id_list);
652
653    /**
654     * populate a list with all the stream objects
655     *
656     */
657    void get_object_list(std::vector<TrexStream *> &object_list);
658
659    /**
660     * get the table size
661     *
662     */
663    int size();
664
665    std::unordered_map<int, TrexStream *>::iterator begin() {return m_stream_table.begin();}
666    std::unordered_map<int, TrexStream *>::iterator end() {return m_stream_table.end();}
667
668private:
669    /**
670     * holds all the stream in a hash table by stream id
671     *
672     */
673    std::unordered_map<int, TrexStream *> m_stream_table;
674};
675
676#endif /* __TREX_STREAM_H__ */
677
678