trex_stream_vm.h revision c754842a
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#ifndef __TREX_STREAM_VM_API_H__
22#define __TREX_STREAM_VM_API_H__
23
24#include <string>
25#include <stdint.h>
26#include <vector>
27#include <unordered_map>
28#include <assert.h>
29#include <common/Network/Packet/IPHeader.h>
30#include "pal_utl.h"
31#include "mbuf.h"
32
33
34
35//https://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/
36
37//Used to seed the generator.
38inline void fast_srand(uint32_t &g_seed, int seed ){
39  g_seed = seed;
40}
41
42
43//fastrand routine returns one integer, similar output value range as C lib.
44
45inline int fastrand(uint32_t &g_seed)
46{
47  g_seed = (214013*g_seed+2531011);
48  return (g_seed>>16)&0x7FFF;
49}
50
51static inline void vm_srand(uint32_t * per_thread_seed,uint64_t seedval)
52{
53    fast_srand( *per_thread_seed,seedval );
54}
55
56static inline uint32_t vm_rand16(uint32_t * per_thread_seed)
57{
58	return ( fastrand(*per_thread_seed));
59}
60
61static inline uint32_t vm_rand32(uint32_t * per_thread_seed)
62{
63	return ( (vm_rand16(per_thread_seed)<<16)+vm_rand16(per_thread_seed));
64}
65
66static inline uint64_t vm_rand64(uint32_t * per_thread_seed)
67{
68    uint64_t res;
69
70    res=((uint64_t)vm_rand32(per_thread_seed)<<32)+vm_rand32(per_thread_seed);
71
72    return (res);
73}
74
75
76class StreamVm;
77
78/* memory struct of rand_limit instruction */
79/*******************************************************/
80
81struct RandMemBss8 {
82    uint8_t  m_val;
83    uint8_t  m_cnt;
84    uint32_t m_seed;
85} __attribute__((packed));
86
87struct RandMemBss16 {
88    uint16_t  m_val;
89    uint16_t  m_cnt;
90    uint32_t  m_seed;
91} __attribute__((packed));
92
93struct RandMemBss32 {
94    uint32_t  m_val;
95    uint32_t  m_cnt;
96    uint32_t  m_seed;
97} __attribute__((packed));
98
99struct RandMemBss64 {
100    uint64_t  m_val;
101    uint64_t  m_cnt;
102    uint32_t  m_seed;
103} __attribute__((packed));
104
105struct StreamDPOpFlowRandLimit8 {
106    uint8_t m_op;
107    uint8_t m_flow_offset;
108    uint8_t m_limit;
109    uint32_t m_seed;
110public:
111    void dump(FILE *fd,std::string opt);
112    inline void run(uint8_t * flow_var) {
113        RandMemBss8 *p = (RandMemBss8 *)(flow_var + m_flow_offset);
114        if (p->m_cnt  == m_limit){
115            p->m_seed = m_seed;
116            p->m_cnt=0;
117        }
118        uint32_t val = vm_rand16(&p->m_seed);
119        p->m_val= (uint8_t)(val);
120        p->m_cnt++;
121    }
122};
123
124struct StreamDPOpFlowRandLimit16 {
125    uint8_t m_op;
126    uint8_t m_flow_offset;
127    uint16_t m_limit;
128    uint32_t m_seed;
129public:
130    void dump(FILE *fd,std::string opt);
131    inline void run(uint8_t * flow_var) {
132        RandMemBss16 *p = (RandMemBss16 *)(flow_var + m_flow_offset);
133        if (p->m_cnt  == m_limit){
134            p->m_seed = m_seed;
135            p->m_cnt=0;
136        }
137        uint32_t val = vm_rand16(&p->m_seed);
138        p->m_val= (uint16_t)(val);
139        p->m_cnt++;
140    }
141
142};
143
144struct StreamDPOpFlowRandLimit32 {
145    uint8_t m_op;
146    uint8_t m_flow_offset;
147    uint32_t m_limit;
148    uint32_t m_seed;
149public:
150    void dump(FILE *fd,std::string opt);
151    inline void run(uint8_t * flow_var) {
152        RandMemBss32 *p = (RandMemBss32 *)(flow_var + m_flow_offset);
153        if (p->m_cnt  == m_limit){
154            p->m_seed = m_seed;
155            p->m_cnt=0;
156        }
157        uint32_t val = vm_rand32(&p->m_seed);
158        p->m_val= val;
159        p->m_cnt++;
160    }
161};
162
163struct StreamDPOpFlowRandLimit64 {
164    uint8_t m_op;
165    uint8_t m_flow_offset;
166    uint64_t m_limit;
167    uint32_t m_seed;
168public:
169    void dump(FILE *fd,std::string opt);
170    inline void run(uint8_t * flow_var) {
171        RandMemBss64 *p = (RandMemBss64 *)(flow_var + m_flow_offset);
172        if (p->m_cnt  == m_limit){
173            p->m_seed = m_seed;
174            p->m_cnt=0;
175        }
176        uint64_t val = vm_rand64(&p->m_seed);
177        p->m_val= val;
178        p->m_cnt++;
179    }
180};
181
182/*******************************************************/
183
184/* in memory program */
185
186struct StreamDPOpFlowVar8 {
187    uint8_t m_op;
188    uint8_t m_flow_offset;
189    uint8_t m_min_val;
190    uint8_t m_max_val;
191public:
192    void dump(FILE *fd,std::string opt);
193
194    inline void run_inc(uint8_t * flow_var) {
195        uint8_t *p = (flow_var + m_flow_offset);
196        if (*p == m_max_val) {
197            *p = m_min_val;
198        } else {
199            *p = *p + 1;
200        }
201    }
202
203    inline void run_dec(uint8_t * flow_var) {
204        uint8_t *p = (flow_var + m_flow_offset);
205        if (*p == m_min_val) {
206            *p = m_max_val;
207        } else {
208            *p = *p - 1;
209        }
210    }
211
212    inline void run_rand(uint8_t * flow_var,uint32_t *per_thread_random) {
213        uint8_t * p=(flow_var+m_flow_offset);
214        *p= m_min_val + (vm_rand16(per_thread_random)  % (int)(m_max_val - m_min_val + 1));
215    }
216
217
218} __attribute__((packed)) ;
219
220struct StreamDPOpFlowVar16 {
221    uint8_t m_op;
222    uint8_t m_flow_offset;
223    uint16_t m_min_val;
224    uint16_t m_max_val;
225public:
226    void dump(FILE *fd,std::string opt);
227
228    inline void run_inc(uint8_t * flow_var) {
229        uint16_t *p = (uint16_t *)(flow_var + m_flow_offset);
230        if (*p == m_max_val) {
231            *p = m_min_val;
232        } else {
233            *p = *p + 1;
234        }
235    }
236
237    inline void run_dec(uint8_t * flow_var) {
238        uint16_t *p = (uint16_t *)(flow_var + m_flow_offset);
239        if (*p == m_min_val) {
240            *p = m_max_val;
241        } else {
242            *p = *p - 1;
243        }
244    }
245
246    inline void run_rand(uint8_t * flow_var,uint32_t *per_thread_random) {
247        uint16_t * p=(uint16_t *)(flow_var+m_flow_offset);
248        *p= m_min_val + (vm_rand16(per_thread_random) % (int)(m_max_val - m_min_val + 1));
249    }
250
251
252
253} __attribute__((packed)) ;
254
255struct StreamDPOpFlowVar32 {
256    uint8_t m_op;
257    uint8_t m_flow_offset;
258    uint32_t m_min_val;
259    uint32_t m_max_val;
260public:
261    void dump(FILE *fd,std::string opt);
262
263    inline void run_inc(uint8_t * flow_var) {
264        uint32_t *p = (uint32_t *)(flow_var + m_flow_offset);
265        if (*p == m_max_val) {
266            *p = m_min_val;
267        } else {
268            *p = *p + 1;
269        }
270    }
271
272    inline void run_dec(uint8_t * flow_var) {
273        uint32_t *p = (uint32_t *)(flow_var + m_flow_offset);
274        if (*p == m_min_val) {
275            *p = m_max_val;
276        } else {
277            *p = *p - 1;
278        }
279    }
280
281    inline void run_rand(uint8_t * flow_var,uint32_t *per_thread_random) {
282        uint32_t * p=(uint32_t *)(flow_var+m_flow_offset);
283        *p = m_min_val + (vm_rand32(per_thread_random) % ((uint64_t)(m_max_val) - m_min_val + 1));
284    }
285
286} __attribute__((packed)) ;
287
288struct StreamDPOpFlowVar64 {
289    uint8_t m_op;
290    uint8_t m_flow_offset;
291    uint64_t m_min_val;
292    uint64_t m_max_val;
293public:
294    void dump(FILE *fd,std::string opt);
295
296    inline void run_inc(uint8_t * flow_var) {
297        uint64_t *p = (uint64_t *)(flow_var + m_flow_offset);
298        if (*p == m_max_val) {
299            *p = m_min_val;
300        } else {
301            *p = *p + 1;
302        }
303    }
304
305    inline void run_dec(uint8_t * flow_var) {
306        uint64_t *p = (uint64_t *)(flow_var + m_flow_offset);
307        if (*p == m_min_val) {
308            *p = m_max_val;
309        } else {
310            *p = *p - 1;
311        }
312    }
313
314    inline void run_rand(uint8_t * flow_var,uint32_t *per_thread_random) {
315        uint64_t * p=(uint64_t *)(flow_var+m_flow_offset);
316
317        if ((m_max_val - m_min_val) == UINT64_MAX) {
318            *p = vm_rand64(per_thread_random);
319        } else {
320            *p = m_min_val + ( vm_rand64(per_thread_random)  % ( (uint64_t)m_max_val - m_min_val + 1) );
321        }
322    }
323
324
325} __attribute__((packed)) ;
326
327
328
329struct StreamDPOpFlowVar8Step {
330    uint8_t m_op;
331    uint8_t m_flow_offset;
332    uint8_t m_min_val;
333    uint8_t m_max_val;
334    uint8_t m_step;
335public:
336    void dump(FILE *fd,std::string opt);
337
338    inline void run_inc(uint8_t * flow_var) {
339        uint8_t *p = (flow_var + m_flow_offset);
340        if (*p > (m_max_val-m_step)) {
341            *p = m_min_val;
342        } else {
343            *p = *p + m_step;
344        }
345    }
346
347    inline void run_dec(uint8_t * flow_var) {
348        uint8_t *p = (flow_var + m_flow_offset);
349        if (*p < (m_min_val+m_step)) {
350            *p = m_max_val;
351        } else {
352            *p = *p - m_step;
353        }
354    }
355
356} __attribute__((packed)) ;
357
358struct StreamDPOpFlowVar16Step {
359    uint8_t m_op;
360    uint8_t m_flow_offset;
361    uint16_t m_min_val;
362    uint16_t m_max_val;
363    uint16_t m_step;
364
365public:
366    void dump(FILE *fd,std::string opt);
367
368    inline void run_inc(uint8_t * flow_var) {
369        uint16_t *p = (uint16_t *)(flow_var + m_flow_offset);
370        if (*p > (m_max_val-m_step)) {
371            *p = m_min_val;
372        } else {
373            *p = *p + m_step;
374        }
375    }
376
377    inline void run_dec(uint8_t * flow_var) {
378        uint16_t *p = (uint16_t *)(flow_var + m_flow_offset);
379        if (*p < (m_min_val+m_step)) {
380            *p = m_max_val;
381        } else {
382            *p = *p - m_step;
383        }
384    }
385
386} __attribute__((packed)) ;
387
388struct StreamDPOpFlowVar32Step {
389    uint8_t m_op;
390    uint8_t m_flow_offset;
391    uint32_t m_min_val;
392    uint32_t m_max_val;
393    uint32_t m_step;
394public:
395    void dump(FILE *fd,std::string opt);
396
397    inline void run_inc(uint8_t * flow_var) {
398        uint32_t *p = (uint32_t *)(flow_var + m_flow_offset);
399        if (*p > (m_max_val-m_step)) {
400            *p = m_min_val;
401        } else {
402            *p = *p + m_step;
403        }
404    }
405
406    inline void run_dec(uint8_t * flow_var) {
407        uint32_t *p = (uint32_t *)(flow_var + m_flow_offset);
408        if (*p < (m_min_val+m_step)) {
409            *p = m_max_val;
410        } else {
411            *p = *p - m_step;
412        }
413    }
414
415} __attribute__((packed)) ;
416
417struct StreamDPOpFlowVar64Step {
418    uint8_t m_op;
419    uint8_t m_flow_offset;
420    uint64_t m_min_val;
421    uint64_t m_max_val;
422    uint64_t m_step;
423public:
424    void dump(FILE *fd,std::string opt);
425
426    inline void run_inc(uint8_t * flow_var) {
427        uint64_t *p = (uint64_t *)(flow_var + m_flow_offset);
428        if (*p > (m_max_val-m_step) ) {
429            *p = m_min_val;
430        } else {
431            *p = *p + m_step;
432        }
433    }
434
435    inline void run_dec(uint8_t * flow_var) {
436        uint64_t *p = (uint64_t *)(flow_var + m_flow_offset);
437        if (*p < m_min_val+m_step) {
438            *p = m_max_val;
439        } else {
440            *p = *p - m_step;
441        }
442    }
443
444
445} __attribute__((packed)) ;
446
447///////////////////////////////////////////////////////////////////////
448
449
450struct StreamDPOpPktWrBase {
451    enum {
452        PKT_WR_IS_BIG = 1
453    }; /* for flags */
454
455    uint8_t m_op;
456    uint8_t m_flags;
457    uint8_t  m_offset;
458
459public:
460    bool is_big(){
461        return ( (m_flags &StreamDPOpPktWrBase::PKT_WR_IS_BIG) == StreamDPOpPktWrBase::PKT_WR_IS_BIG ?true:false);
462    }
463
464} __attribute__((packed)) ;
465
466
467struct StreamDPOpPktWr8 : public StreamDPOpPktWrBase {
468    int8_t  m_val_offset;
469    uint16_t m_pkt_offset;
470
471public:
472    void dump(FILE *fd,std::string opt);
473
474    inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
475        uint8_t * p_pkt      = (pkt_base+m_pkt_offset);
476        uint8_t * p_flow_var = (flow_var_base+m_offset);
477        *p_pkt=(*p_flow_var+m_val_offset);
478
479    }
480
481
482} __attribute__((packed)) ;
483
484
485struct StreamDPOpPktWr16 : public StreamDPOpPktWrBase {
486    uint16_t m_pkt_offset;
487    int16_t  m_val_offset;
488public:
489    void dump(FILE *fd,std::string opt);
490
491    inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
492        uint16_t * p_pkt      = (uint16_t*)(pkt_base+m_pkt_offset);
493        uint16_t * p_flow_var = (uint16_t*)(flow_var_base+m_offset);
494
495        if ( likely(is_big())){
496            *p_pkt=PKT_HTONS((*p_flow_var+m_val_offset));
497        }else{
498            *p_pkt=(*p_flow_var+m_val_offset);
499        }
500
501    }
502} __attribute__((packed));
503
504struct StreamDPOpPktWr32 : public StreamDPOpPktWrBase {
505    uint16_t m_pkt_offset;
506    int32_t  m_val_offset;
507public:
508    void dump(FILE *fd,std::string opt);
509
510    inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
511        uint32_t * p_pkt      = (uint32_t*)(pkt_base+m_pkt_offset);
512        uint32_t * p_flow_var = (uint32_t*)(flow_var_base+m_offset);
513        if ( likely(is_big())){
514            *p_pkt=PKT_HTONL((*p_flow_var+m_val_offset));
515        }else{
516            *p_pkt=(*p_flow_var+m_val_offset);
517        }
518    }
519
520} __attribute__((packed));
521
522struct StreamDPOpPktWr64 : public StreamDPOpPktWrBase {
523    uint16_t m_pkt_offset;
524    int64_t  m_val_offset;
525
526public:
527    void dump(FILE *fd,std::string opt);
528
529    inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
530        uint64_t * p_pkt      = (uint64_t*)(pkt_base+m_pkt_offset);
531        uint64_t * p_flow_var = (uint64_t*)(flow_var_base+m_offset);
532        if ( likely(is_big())){
533            *p_pkt=pal_ntohl64((*p_flow_var+m_val_offset));
534        }else{
535            *p_pkt=(*p_flow_var+m_val_offset);
536        }
537    }
538
539
540} __attribute__((packed));
541
542
543struct StreamDPOpPktWrMask  {
544
545    enum {
546        MASK_PKT_WR_IS_BIG = 1
547    }; /* for flags */
548
549    uint8_t  m_op;
550    uint8_t  m_flags;
551    uint8_t  m_var_offset;
552    int8_t   m_shift;
553    uint8_t  m_pkt_cast_size;
554    uint8_t  m_flowv_cast_size; /* 1,2,4 */
555    uint16_t m_pkt_offset;
556    uint32_t m_mask;
557    int32_t  m_add_value;
558    bool is_big(){
559        return ( (m_flags &StreamDPOpPktWrMask::MASK_PKT_WR_IS_BIG) == StreamDPOpPktWrMask::MASK_PKT_WR_IS_BIG ?true:false);
560    }
561
562
563public:
564    void dump(FILE *fd,std::string opt);
565
566    void wr(uint8_t * flow_var_base,
567                   uint8_t * pkt_base) ;
568
569} __attribute__((packed));
570
571
572
573
574struct StreamDPOpIpv4Fix {
575    uint8_t m_op;
576    uint16_t  m_offset;
577public:
578    void dump(FILE *fd,std::string opt);
579    void run(uint8_t * pkt_base){
580        IPHeader *      ipv4=  (IPHeader *)(pkt_base+m_offset);
581        ipv4->updateCheckSum();
582    }
583
584} __attribute__((packed));
585
586
587/* flow varible of Client command */
588struct StreamDPFlowClient {
589    uint32_t cur_ip;
590    uint16_t cur_port;
591    uint32_t cur_flow_id;
592} __attribute__((packed));
593
594
595struct StreamDPOpClientsLimit {
596    uint8_t m_op;
597    uint8_t m_flow_offset; /* offset into the flow var  bytes */
598    uint8_t m_flags;
599    uint8_t m_pad;
600    uint16_t    m_min_port;
601    uint16_t    m_max_port;
602
603    uint32_t    m_min_ip;
604    uint32_t    m_max_ip;
605    uint32_t    m_limit_flows; /* limit the number of flows */
606
607public:
608    void dump(FILE *fd,std::string opt);
609    inline void run(uint8_t * flow_var_base) {
610        StreamDPFlowClient * lp= (StreamDPFlowClient *)(flow_var_base+m_flow_offset);
611        lp->cur_ip++;
612        if (lp->cur_ip > m_max_ip ) {
613            lp->cur_ip= m_min_ip;
614            lp->cur_port++;
615            if (lp->cur_port > m_max_port) {
616                lp->cur_port = m_min_port;
617            }
618        }
619
620        if (m_limit_flows) {
621            lp->cur_flow_id++;
622            if ( lp->cur_flow_id > m_limit_flows ){
623                /* reset to the first flow */
624                lp->cur_flow_id = 1;
625                lp->cur_ip      =  m_min_ip;
626                lp->cur_port    =  m_min_port;
627            }
628        }
629    }
630
631
632} __attribute__((packed));
633
634struct StreamDPOpClientsUnLimit {
635    enum __MIN_PORT {
636        CLIENT_UNLIMITED_MIN_PORT = 1025
637    };
638
639    uint8_t m_op;
640    uint8_t m_flow_offset; /* offset into the flow var  bytes */
641    uint8_t m_flags;
642    uint8_t m_pad;
643    uint32_t    m_min_ip;
644    uint32_t    m_max_ip;
645
646public:
647    void dump(FILE *fd,std::string opt);
648    inline void run(uint8_t * flow_var_base) {
649        StreamDPFlowClient * lp= (StreamDPFlowClient *)(flow_var_base+m_flow_offset);
650        lp->cur_ip++;
651        if (lp->cur_ip > m_max_ip ) {
652            lp->cur_ip= m_min_ip;
653            lp->cur_port++;
654            if (lp->cur_port == 0) {
655                lp->cur_port = StreamDPOpClientsUnLimit::CLIENT_UNLIMITED_MIN_PORT;
656            }
657        }
658    }
659
660} __attribute__((packed));
661
662
663struct StreamDPOpPktSizeChange  {
664    uint8_t  m_op;
665    uint8_t  m_flow_offset; /* offset to the flow var */
666
667    inline void run(uint8_t * flow_var_base,uint16_t & new_size) {
668        uint16_t * p_flow_var = (uint16_t*)(flow_var_base+m_flow_offset);
669        new_size  = (*p_flow_var);
670    }
671
672    void dump(FILE *fd,std::string opt);
673
674
675} __attribute__((packed)); ;
676
677
678/* datapath instructions */
679class StreamDPVmInstructions {
680public:
681    enum INS_TYPE {
682        ditINC8     =7 ,
683        ditINC16        ,
684        ditINC32        ,
685        ditINC64        ,
686
687        ditDEC8         ,
688        ditDEC16        ,
689        ditDEC32        ,
690        ditDEC64        ,
691
692        ditRANDOM8      ,
693        ditRANDOM16     ,
694        ditRANDOM32     ,
695        ditRANDOM64     ,
696
697        ditFIX_IPV4_CS  ,
698
699        itPKT_WR8       ,
700        itPKT_WR16       ,
701        itPKT_WR32       ,
702        itPKT_WR64       ,
703        itCLIENT_VAR       ,
704        itCLIENT_VAR_UNLIMIT ,
705        itPKT_SIZE_CHANGE ,
706
707        /* inc/dec with step*/
708        ditINC8_STEP         ,
709        ditINC16_STEP        ,
710        ditINC32_STEP        ,
711        ditINC64_STEP        ,
712
713        ditDEC8_STEP         ,
714        ditDEC16_STEP        ,
715        ditDEC32_STEP        ,
716        ditDEC64_STEP        ,
717        itPKT_WR_MASK        ,
718
719        ditRAND_LIMIT8      ,
720        ditRAND_LIMIT16     ,
721        ditRAND_LIMIT32     ,
722        ditRAND_LIMIT64     ,
723
724    };
725
726
727public:
728    void clear();
729    void add_command(void *buffer,uint16_t size);
730    uint8_t * get_program();
731    uint32_t get_program_size();
732
733
734    void Dump(FILE *fd);
735
736
737private:
738    std::vector<uint8_t> m_inst_list;
739};
740
741
742class StreamDPVmInstructionsRunner {
743public:
744    StreamDPVmInstructionsRunner(){
745        m_new_pkt_size=0;;
746
747    }
748
749    void   slow_commands(uint8_t op_code,
750                           uint8_t * flow_var, /* flow var */
751                           uint8_t * pkt,
752                           uint8_t * & p);
753
754    inline void run(uint32_t * per_thread_random,
755                    uint32_t program_size,
756                    uint8_t * program,  /* program */
757                    uint8_t * flow_var, /* flow var */
758                    uint8_t * pkt);      /* pkt */
759
760    inline uint16_t get_new_pkt_size(){
761        return (m_new_pkt_size);
762    }
763private:
764    uint16_t    m_new_pkt_size;
765};
766
767
768typedef union  ua_ {
769        StreamDPOpFlowVar8  *lpv8;
770        StreamDPOpFlowVar16 *lpv16;
771        StreamDPOpFlowVar32 *lpv32;
772        StreamDPOpFlowVar64 *lpv64;
773        StreamDPOpIpv4Fix   *lpIpv4Fix;
774        StreamDPOpPktWr8     *lpw8;
775        StreamDPOpPktWr16    *lpw16;
776        StreamDPOpPktWr32    *lpw32;
777        StreamDPOpPktWr64    *lpw64;
778        StreamDPOpPktSizeChange    *lpw_pkt_size;
779
780        StreamDPOpClientsLimit      *lpcl;
781        StreamDPOpClientsUnLimit    *lpclu;
782
783        StreamDPOpFlowVar8Step  *lpv8s;
784        StreamDPOpFlowVar16Step *lpv16s;
785        StreamDPOpFlowVar32Step *lpv32s;
786        StreamDPOpFlowVar64Step *lpv64s;
787        StreamDPOpPktWrMask     *lpwr_mask;
788
789        StreamDPOpFlowRandLimit8  *lpv_rl8;
790        StreamDPOpFlowRandLimit16 *lpv_rl16;
791        StreamDPOpFlowRandLimit32 *lpv_rl32;
792        StreamDPOpFlowRandLimit64 *lpv_rl64;
793
794} ua_t ;
795
796
797
798inline void StreamDPVmInstructionsRunner::run(uint32_t * per_thread_random,
799                                              uint32_t program_size,
800                                              uint8_t * program,  /* program */
801                                              uint8_t * flow_var, /* flow var */
802                                              uint8_t * pkt
803                                              ){
804
805    uint8_t * p=program;
806    uint8_t * p_end=p+program_size;
807
808    ua_t ua;
809
810    while ( p < p_end) {
811        uint8_t op_code=*p;
812        switch (op_code) {
813
814        case  StreamDPVmInstructions::itCLIENT_VAR :
815            ua.lpcl =(StreamDPOpClientsLimit *)p;
816            ua.lpcl->run(flow_var);
817            p+=sizeof(StreamDPOpClientsLimit);
818            break;
819
820        case  StreamDPVmInstructions::itCLIENT_VAR_UNLIMIT :
821            ua.lpclu =(StreamDPOpClientsUnLimit *)p;
822            ua.lpclu->run(flow_var);
823            p+=sizeof(StreamDPOpClientsUnLimit);
824            break;
825
826        case   StreamDPVmInstructions::ditINC8  :
827            ua.lpv8 =(StreamDPOpFlowVar8 *)p;
828            ua.lpv8->run_inc(flow_var);
829            p+=sizeof(StreamDPOpFlowVar8);
830            break;
831
832        case  StreamDPVmInstructions::ditINC16  :
833            ua.lpv16 =(StreamDPOpFlowVar16 *)p;
834            ua.lpv16->run_inc(flow_var);
835            p+=sizeof(StreamDPOpFlowVar16);
836            break;
837        case  StreamDPVmInstructions::ditINC32 :
838            ua.lpv32 =(StreamDPOpFlowVar32 *)p;
839            ua.lpv32->run_inc(flow_var);
840            p+=sizeof(StreamDPOpFlowVar32);
841             break;
842        case  StreamDPVmInstructions::ditINC64 :
843            ua.lpv64 =(StreamDPOpFlowVar64 *)p;
844            ua.lpv64->run_inc(flow_var);
845            p+=sizeof(StreamDPOpFlowVar64);
846            break;
847
848        case  StreamDPVmInstructions::ditDEC8 :
849            ua.lpv8 =(StreamDPOpFlowVar8 *)p;
850            ua.lpv8->run_dec(flow_var);
851            p+=sizeof(StreamDPOpFlowVar8);
852            break;
853        case  StreamDPVmInstructions::ditDEC16 :
854            ua.lpv16 =(StreamDPOpFlowVar16 *)p;
855            ua.lpv16->run_dec(flow_var);
856            p+=sizeof(StreamDPOpFlowVar16);
857            break;
858        case  StreamDPVmInstructions::ditDEC32 :
859            ua.lpv32 =(StreamDPOpFlowVar32 *)p;
860            ua.lpv32->run_dec(flow_var);
861            p+=sizeof(StreamDPOpFlowVar32);
862            break;
863        case  StreamDPVmInstructions::ditDEC64 :
864            ua.lpv64 =(StreamDPOpFlowVar64 *)p;
865            ua.lpv64->run_dec(flow_var);
866            p+=sizeof(StreamDPOpFlowVar64);
867            break;
868
869        case  StreamDPVmInstructions::ditRANDOM8 :
870            ua.lpv8 =(StreamDPOpFlowVar8 *)p;
871            ua.lpv8->run_rand(flow_var,per_thread_random);
872            p+=sizeof(StreamDPOpFlowVar8);
873            break;
874        case  StreamDPVmInstructions::ditRANDOM16 :
875            ua.lpv16 =(StreamDPOpFlowVar16 *)p;
876            ua.lpv16->run_rand(flow_var,per_thread_random);
877            p+=sizeof(StreamDPOpFlowVar16);
878            break;
879        case  StreamDPVmInstructions::ditRANDOM32 :
880            ua.lpv32 =(StreamDPOpFlowVar32 *)p;
881            ua.lpv32->run_rand(flow_var,per_thread_random);
882            p+=sizeof(StreamDPOpFlowVar32);
883            break;
884        case  StreamDPVmInstructions::ditRANDOM64 :
885            ua.lpv64 =(StreamDPOpFlowVar64 *)p;
886            ua.lpv64->run_rand(flow_var,per_thread_random);
887            p+=sizeof(StreamDPOpFlowVar64);
888            break;
889
890        case  StreamDPVmInstructions::ditFIX_IPV4_CS :
891            ua.lpIpv4Fix =(StreamDPOpIpv4Fix *)p;
892            ua.lpIpv4Fix->run(pkt);
893            p+=sizeof(StreamDPOpIpv4Fix);
894            break;
895
896        case  StreamDPVmInstructions::itPKT_WR8  :
897            ua.lpw8 =(StreamDPOpPktWr8 *)p;
898            ua.lpw8->wr(flow_var,pkt);
899            p+=sizeof(StreamDPOpPktWr8);
900            break;
901
902        case  StreamDPVmInstructions::itPKT_WR16 :
903            ua.lpw16 =(StreamDPOpPktWr16 *)p;
904            ua.lpw16->wr(flow_var,pkt);
905            p+=sizeof(StreamDPOpPktWr16);
906            break;
907
908        case  StreamDPVmInstructions::itPKT_WR32 :
909            ua.lpw32 =(StreamDPOpPktWr32 *)p;
910            ua.lpw32->wr(flow_var,pkt);
911            p+=sizeof(StreamDPOpPktWr32);
912            break;
913
914        case  StreamDPVmInstructions::itPKT_WR64 :
915            ua.lpw64 =(StreamDPOpPktWr64 *)p;
916            ua.lpw64->wr(flow_var,pkt);
917            p+=sizeof(StreamDPOpPktWr64);
918            break;
919
920        case  StreamDPVmInstructions::itPKT_SIZE_CHANGE :
921            ua.lpw_pkt_size =(StreamDPOpPktSizeChange *)p;
922            ua.lpw_pkt_size->run(flow_var,m_new_pkt_size);
923            p+=sizeof(StreamDPOpPktSizeChange);
924            break;
925
926        default:
927            slow_commands(op_code,flow_var,pkt,p);
928            break;
929        }
930    };
931};
932
933
934
935
936/**
937 * interface for stream VM instruction
938 *
939 */
940class StreamVmInstruction {
941public:
942
943    enum INS_TYPE {
944        itNONE         = 0,
945        itFIX_IPV4_CS  = 4,
946        itFLOW_MAN     = 5,
947        itPKT_WR       = 6,
948        itFLOW_CLIENT  = 7 ,
949        itPKT_SIZE_CHANGE = 8,
950        itPKT_WR_MASK     = 9,
951        itFLOW_RAND_LIMIT = 10 /* random with limit & seed */
952
953
954    };
955
956    typedef uint8_t instruction_type_t ;
957
958    virtual instruction_type_t get_instruction_type() const = 0;
959
960    virtual ~StreamVmInstruction();
961
962    virtual void Dump(FILE *fd)=0;
963
964    virtual StreamVmInstruction * clone() = 0;
965
966    /* by default an instruction is not splitable */
967    virtual bool is_splitable() const {
968        return false;
969    }
970    /* nothing to init */
971    virtual uint8_t bss_init_value(uint8_t *p){
972        return (0);
973    }
974
975private:
976    static const std::string m_name;
977};
978
979/**
980 * abstract class that defines a flow var
981 *
982 * @author imarom (23-Dec-15)
983 */
984class StreamVmInstructionVar : public StreamVmInstruction {
985
986public:
987
988    StreamVmInstructionVar(const std::string &var_name) : m_var_name(var_name) {
989
990    }
991
992    const std::string & get_var_name() {
993        return m_var_name;
994    }
995
996    virtual bool is_splitable() const {
997        return true;
998    }
999
1000    /**
1001     * what is the split range for this var
1002     *
1003     */
1004    virtual uint64_t get_splitable_range() const = 0;
1005
1006public:
1007
1008    /* flow var name */
1009    const std::string m_var_name;
1010};
1011
1012/**
1013 * fix checksum for ipv4
1014 *
1015 */
1016class StreamVmInstructionFixChecksumIpv4 : public StreamVmInstruction {
1017public:
1018    StreamVmInstructionFixChecksumIpv4(uint16_t offset) : m_pkt_offset(offset) {
1019
1020    }
1021
1022    virtual instruction_type_t get_instruction_type() const {
1023        return ( StreamVmInstruction::itFIX_IPV4_CS);
1024    }
1025
1026    virtual void Dump(FILE *fd);
1027
1028    virtual StreamVmInstruction * clone() {
1029        return new StreamVmInstructionFixChecksumIpv4(m_pkt_offset);
1030    }
1031
1032public:
1033    uint16_t m_pkt_offset; /* the offset of IPv4 header from the start of the packet  */
1034};
1035
1036/**
1037 * flow manipulation instruction
1038 *
1039 * @author imarom (07-Sep-15)
1040 */
1041class StreamVmInstructionFlowMan : public StreamVmInstructionVar {
1042
1043public:
1044
1045    virtual instruction_type_t get_instruction_type() const {
1046        return ( StreamVmInstruction::itFLOW_MAN);
1047    }
1048
1049    virtual bool is_valid_for_split() const {
1050        return (m_step==1?true:false);
1051    }
1052
1053
1054    virtual uint64_t get_splitable_range() const {
1055        return (m_max_value - m_min_value + 1);
1056    }
1057
1058
1059    virtual uint8_t  bss_init_value(uint8_t *p);
1060
1061
1062    /**
1063     * different types of operations on the object
1064     */
1065    enum flow_var_op_e {
1066        FLOW_VAR_OP_INC,
1067        FLOW_VAR_OP_DEC,
1068        FLOW_VAR_OP_RANDOM
1069    };
1070
1071
1072    /**
1073     * for BSS we take one previous value
1074     * because the VM will be executed before writing to pkt
1075     * so the init value is one step's advanced
1076     *
1077     */
1078    uint64_t get_bss_init_value() const {
1079        uint64_t init = m_init_value;
1080
1081        switch (m_op) {
1082        case FLOW_VAR_OP_INC:
1083            return (init == m_min_value ? m_max_value : (init - 1));
1084
1085        case FLOW_VAR_OP_DEC:
1086            return (init == m_max_value ? m_min_value : (init + 1));
1087
1088        default:
1089            return init;
1090        }
1091
1092    }
1093
1094    StreamVmInstructionFlowMan(const std::string &var_name,
1095                               uint8_t size,
1096                               flow_var_op_e op,
1097                               uint64_t init_value,
1098                               uint64_t min_value,
1099                               uint64_t max_value,
1100                               uint64_t step=1) : StreamVmInstructionVar(var_name) {
1101
1102        m_op = op;
1103        m_size_bytes = size;
1104        m_init_value = init_value;
1105        m_min_value  = min_value;
1106        m_max_value  = max_value;
1107        m_step       = step;
1108
1109    }
1110
1111    virtual void Dump(FILE *fd);
1112
1113    void sanity_check(uint32_t ins_id,StreamVm *lp);
1114
1115    virtual StreamVmInstruction * clone() {
1116        return new StreamVmInstructionFlowMan(m_var_name,
1117                                              m_size_bytes,
1118                                              m_op,
1119                                              m_init_value,
1120                                              m_min_value,
1121                                              m_max_value,
1122                                              m_step);
1123    }
1124
1125private:
1126    void sanity_check_valid_size(uint32_t ins_id,StreamVm *lp);
1127    void sanity_check_valid_opt(uint32_t ins_id,StreamVm *lp);
1128    void sanity_check_valid_range(uint32_t ins_id,StreamVm *lp);
1129
1130public:
1131
1132    /* flow var size */
1133    uint8_t       m_size_bytes;
1134
1135    /* type of op */
1136    flow_var_op_e m_op;
1137
1138    /* range */
1139    uint64_t m_init_value;
1140    uint64_t m_min_value;
1141    uint64_t m_max_value;
1142
1143    uint64_t m_step;
1144};
1145
1146
1147/**
1148 * flow var random with limit
1149 *
1150 * @author hhaim 9/2016
1151 */
1152class StreamVmInstructionFlowRandLimit : public StreamVmInstructionVar {
1153
1154public:
1155
1156    virtual instruction_type_t get_instruction_type() const {
1157        return ( StreamVmInstruction::itFLOW_RAND_LIMIT);
1158    }
1159
1160    virtual bool is_valid_for_split() const {
1161        return (false);
1162    }
1163
1164
1165    virtual uint64_t get_splitable_range() const {
1166        return (1);
1167    }
1168
1169
1170    StreamVmInstructionFlowRandLimit(const std::string &var_name,
1171                                     uint8_t  size,
1172                                     uint64_t limit,
1173                                     int       seed
1174                                     ) : StreamVmInstructionVar(var_name) {
1175
1176        m_size_bytes = size;
1177        m_seed       = seed;
1178        m_limit      = limit;
1179    }
1180
1181    virtual void Dump(FILE *fd);
1182
1183    void sanity_check(uint32_t ins_id,StreamVm *lp);
1184
1185    virtual uint8_t  bss_init_value(uint8_t *p);
1186
1187    virtual StreamVmInstruction * clone() {
1188        return new StreamVmInstructionFlowRandLimit(m_var_name,
1189                                                    m_size_bytes,
1190                                                    m_limit,
1191                                                    m_seed);
1192    }
1193
1194private:
1195    void sanity_check_valid_size(uint32_t ins_id,StreamVm *lp);
1196
1197public:
1198
1199    uint64_t       m_limit;
1200    int            m_seed;
1201    uint8_t        m_size_bytes;
1202};
1203
1204
1205/**
1206 * write flow-write-mask  to packet, hhaim
1207 *
1208 *  uint32_t var_tmp=(uint32_t )(flow_var_t size )flow_var;
1209 *  if (shift){
1210 *     var_tmp=var_tmp<<shift
1211 *  }else{
1212 *      var_tmp=var_tmp>>shift
1213 *  }
1214 *
1215 *  pkt_data=read_pkt_size()
1216 *  pkt_data =  (pkt_data & ~mask) |(var_tmp & mask)
1217 *  write_pkt(pkt_data)
1218 *
1219 */
1220class StreamVmInstructionWriteMaskToPkt : public StreamVmInstruction {
1221public:
1222
1223    StreamVmInstructionWriteMaskToPkt(const std::string &flow_var_name,
1224                                  uint16_t           pkt_offset,
1225                                  uint8_t            pkt_cast_size, /* valid 1,2,4 */
1226                                  uint32_t           mask,
1227                                  int                shift,       /* positive is shift left, negetive shift right */
1228                                  int32_t            add_value = 0,
1229                                  bool               is_big_endian = true) :
1230                                                        m_flow_var_name(flow_var_name),
1231                                                        m_pkt_offset(pkt_offset),
1232                                                        m_pkt_cast_size(pkt_cast_size),
1233                                                        m_mask(mask),
1234                                                        m_shift(shift),
1235                                                        m_add_value(add_value),
1236                                                        m_is_big_endian(is_big_endian) {}
1237
1238    virtual instruction_type_t get_instruction_type() const {
1239        return ( StreamVmInstruction::itPKT_WR_MASK);
1240    }
1241
1242    virtual void Dump(FILE *fd);
1243
1244    virtual StreamVmInstruction * clone() {
1245        return new StreamVmInstructionWriteMaskToPkt(m_flow_var_name,
1246                                                     m_pkt_offset,
1247                                                     m_pkt_cast_size,
1248                                                     m_mask,
1249                                                     m_shift,
1250                                                     m_add_value,
1251                                                     m_is_big_endian);
1252    }
1253
1254public:
1255
1256    /* flow var name to write */
1257    std::string   m_flow_var_name;
1258
1259    /* where to write */
1260    uint16_t      m_pkt_offset;
1261    uint8_t       m_pkt_cast_size; /* valid 1,2,4 */
1262
1263    uint32_t      m_mask;
1264    int           m_shift;
1265    int           m_add_value;
1266    bool          m_is_big_endian;
1267};
1268
1269
1270
1271
1272/**
1273 * flow client instruction - save state for client range and port range
1274 *
1275 * @author hhaim
1276 */
1277class StreamVmInstructionFlowClient : public StreamVmInstructionVar {
1278
1279public:
1280    enum client_flags_e {
1281        CLIENT_F_UNLIMITED_FLOWS=1, /* unlimited number of flow, don't care about ports  */
1282    };
1283
1284
1285    virtual instruction_type_t get_instruction_type() const {
1286        return ( StreamVmInstruction::itFLOW_CLIENT);
1287    }
1288
1289
1290    StreamVmInstructionFlowClient(const std::string &var_name,
1291                               uint32_t client_min_value,
1292                               uint32_t client_max_value,
1293                               uint16_t port_min,
1294                               uint16_t port_max,
1295                               uint32_t limit_num_flows, /* zero means don't limit */
1296                               uint16_t flags
1297                               ) : StreamVmInstructionVar(var_name) {
1298
1299        m_client_min = client_min_value;
1300        m_client_max = client_max_value;
1301
1302        m_port_min   = port_min;
1303        m_port_max   = port_max;
1304
1305        m_limit_num_flows = limit_num_flows;
1306        m_flags = flags;
1307    }
1308
1309    virtual void Dump(FILE *fd);
1310
1311    static uint8_t get_flow_var_size(){
1312        return  (4+2+4);
1313    }
1314
1315    uint32_t get_ip_range() const {
1316        return (m_client_max - m_client_min + 1);
1317    }
1318
1319    uint16_t get_port_range() const {
1320        return (m_port_max - m_port_min + 1);
1321    }
1322
1323    virtual uint64_t get_splitable_range() const {
1324        return get_ip_range();
1325    }
1326
1327
1328    virtual uint8_t  bss_init_value(uint8_t *p);
1329
1330
1331    bool is_unlimited_flows(){
1332        return ( (m_flags &   StreamVmInstructionFlowClient::CLIENT_F_UNLIMITED_FLOWS ) ==
1333                  StreamVmInstructionFlowClient::CLIENT_F_UNLIMITED_FLOWS );
1334    }
1335
1336    virtual StreamVmInstruction * clone() {
1337        return new StreamVmInstructionFlowClient(m_var_name,
1338                                                 m_client_min,
1339                                                 m_client_max,
1340                                                 m_port_min,
1341                                                 m_port_max,
1342                                                 m_limit_num_flows,
1343                                                 m_flags);
1344    }
1345
1346public:
1347
1348    uint32_t m_client_min;  // min ip
1349    uint32_t m_client_max;  // max ip
1350    uint16_t m_port_min;  // start port
1351    uint16_t m_port_max;  // start port
1352    uint32_t m_limit_num_flows;   // number of flows
1353    uint16_t m_flags;
1354};
1355
1356
1357
1358class VmFlowVarRec {
1359public:
1360    uint32_t    m_offset;
1361    union {
1362        StreamVmInstructionFlowMan * m_ins_flowv;
1363        StreamVmInstructionFlowClient * m_ins_flow_client;
1364        StreamVmInstructionFlowRandLimit * m_ins_flow_rand_limit;
1365    } m_ins;
1366    uint8_t    m_size_bytes;
1367};
1368
1369
1370
1371
1372/**
1373 * write flow var to packet, hhaim
1374 *
1375 */
1376class StreamVmInstructionWriteToPkt : public StreamVmInstruction {
1377public:
1378
1379      StreamVmInstructionWriteToPkt(const std::string &flow_var_name,
1380                                    uint16_t           pkt_offset,
1381                                    int32_t            add_value = 0,
1382                                    bool               is_big_endian = true) :
1383
1384                                                        m_flow_var_name(flow_var_name),
1385                                                        m_pkt_offset(pkt_offset),
1386                                                        m_add_value(add_value),
1387                                                        m_is_big_endian(is_big_endian) {}
1388
1389    virtual instruction_type_t get_instruction_type() const {
1390        return ( StreamVmInstruction::itPKT_WR);
1391    }
1392
1393    virtual void Dump(FILE *fd);
1394
1395    virtual StreamVmInstruction * clone() {
1396        return new StreamVmInstructionWriteToPkt(m_flow_var_name,
1397                                                 m_pkt_offset,
1398                                                 m_add_value,
1399                                                 m_is_big_endian);
1400    }
1401
1402public:
1403
1404    /* flow var name to write */
1405    std::string   m_flow_var_name;
1406
1407    /* where to write */
1408    uint16_t      m_pkt_offset;
1409
1410    /* add/dec value from field when writing */
1411    int32_t       m_add_value;
1412
1413    /* writing endian */
1414    bool         m_is_big_endian;
1415};
1416
1417
1418
1419/**
1420 * change packet size,
1421 *
1422 */
1423class StreamVmInstructionChangePktSize : public StreamVmInstruction {
1424public:
1425
1426    StreamVmInstructionChangePktSize(const std::string &flow_var_name) :
1427
1428                                                        m_flow_var_name(flow_var_name)
1429                                                        {}
1430
1431    virtual instruction_type_t get_instruction_type() const {
1432        return ( StreamVmInstruction::itPKT_SIZE_CHANGE );
1433    }
1434
1435    virtual void Dump(FILE *fd);
1436
1437    virtual StreamVmInstruction * clone() {
1438        return new StreamVmInstructionChangePktSize(m_flow_var_name);
1439    }
1440
1441public:
1442
1443    /* flow var name to write */
1444    std::string   m_flow_var_name;
1445};
1446
1447
1448/**
1449 * describes a VM program for DP
1450 *
1451 */
1452
1453class StreamVmDp {
1454public:
1455    StreamVmDp(){
1456        m_bss_ptr=NULL;
1457        m_program_ptr =NULL ;
1458        m_bss_size=0;
1459        m_program_size=0;
1460        m_max_pkt_offset_change=0;
1461        m_prefix_size = 0;
1462        m_is_pkt_size_var=false;
1463    }
1464
1465    StreamVmDp( uint8_t * bss,
1466                uint16_t bss_size,
1467                uint8_t * prog,
1468                uint16_t prog_size,
1469                uint16_t max_pkt_offset,
1470                uint16_t prefix_size,
1471                bool a_is_pkt_size_var,
1472                bool a_is_random_seed
1473                ){
1474
1475        if (bss) {
1476            assert(bss_size);
1477            m_bss_ptr=(uint8_t*)malloc(bss_size);
1478            assert(m_bss_ptr);
1479            memcpy(m_bss_ptr,bss,bss_size);
1480            m_bss_size=bss_size;
1481        }else{
1482            m_bss_ptr=NULL;
1483            m_bss_size=0;
1484        }
1485
1486        if (prog) {
1487            assert(prog_size);
1488            m_program_ptr=(uint8_t*)malloc(prog_size);
1489            memcpy(m_program_ptr,prog,prog_size);
1490            m_program_size = prog_size;
1491        }else{
1492            m_program_ptr = NULL;
1493            m_program_size=0;
1494        }
1495
1496        m_max_pkt_offset_change = max_pkt_offset;
1497        m_prefix_size = prefix_size;
1498        m_is_pkt_size_var=a_is_pkt_size_var;
1499        m_is_random_seed=a_is_random_seed;
1500    }
1501
1502    ~StreamVmDp(){
1503        if (m_bss_ptr) {
1504            free(m_bss_ptr);
1505            m_bss_ptr=0;
1506            m_bss_size=0;
1507        }
1508        if (m_program_ptr) {
1509            free(m_program_ptr);
1510            m_program_size=0;
1511            m_program_ptr=0;
1512        }
1513    }
1514
1515    StreamVmDp * clone() const {
1516        StreamVmDp * lp = new StreamVmDp(m_bss_ptr,
1517                                         m_bss_size,
1518                                         m_program_ptr,
1519                                         m_program_size,
1520                                         m_max_pkt_offset_change,
1521                                         m_prefix_size,
1522                                         m_is_pkt_size_var,
1523                                         m_is_random_seed
1524                                         );
1525        assert(lp);
1526        return (lp);
1527    }
1528
1529    uint8_t* clone_bss(){
1530        assert(m_bss_size>0);
1531        uint8_t *p=(uint8_t *)malloc(m_bss_size);
1532        assert(p);
1533        memcpy(p,m_bss_ptr,m_bss_size);
1534        return (p);
1535    }
1536
1537    uint16_t get_bss_size(){
1538        return(m_bss_size);
1539    }
1540
1541    uint8_t*  get_bss(){
1542        return (m_bss_ptr);
1543    }
1544
1545    uint8_t*  get_program(){
1546        return (m_program_ptr);
1547    }
1548
1549    uint16_t  get_program_size(){
1550        return (m_program_size);
1551    }
1552
1553    uint16_t get_max_packet_update_offset(){
1554        return (m_max_pkt_offset_change);
1555    }
1556
1557    uint16_t get_prefix_size() {
1558        return m_prefix_size;
1559    }
1560
1561    void set_prefix_size(uint16_t prefix_size) {
1562        m_prefix_size = prefix_size;
1563    }
1564
1565    void set_pkt_size_is_var(bool pkt_size_var){
1566        m_is_pkt_size_var=pkt_size_var;
1567    }
1568    bool is_pkt_size_var(){
1569        return (m_is_pkt_size_var);
1570    }
1571    bool is_random_seed(){
1572        return (m_is_random_seed);
1573    }
1574
1575
1576private:
1577    uint8_t *  m_bss_ptr; /* pointer to the data section */
1578    uint8_t *  m_program_ptr; /* pointer to the program */
1579    uint16_t   m_bss_size;
1580    uint16_t   m_program_size; /* program size*/
1581    uint16_t   m_max_pkt_offset_change;
1582    uint16_t   m_prefix_size;
1583    bool       m_is_pkt_size_var;
1584    bool       m_is_random_seed;
1585
1586};
1587
1588
1589/**
1590 * describes a VM program
1591 *
1592 */
1593class StreamVm {
1594
1595public:
1596    enum STREAM_VM {
1597        svMAX_FLOW_VAR   = 64, /* maximum flow varible */
1598        svMAX_PACKET_OFFSET_CHANGE = 512
1599    };
1600
1601
1602
1603    StreamVm(){
1604        m_prefix_size=0;
1605        m_bss=0;
1606        m_pkt_size=0;
1607        m_expected_pkt_size=0.0;
1608        m_cur_var_offset=0;
1609
1610        m_is_random_var=false;
1611        m_is_change_pkt_size=false;
1612
1613        m_split_instr=NULL;
1614        m_is_compiled = false;
1615        m_pkt=0;
1616    }
1617
1618
1619    /**
1620     * calculate the expected packet size
1621     * might be different from regular_pkt_size
1622     * if the VM changes the packet length (random)
1623     *
1624     */
1625    double calc_expected_pkt_size(uint16_t regular_pkt_size) const;
1626
1627
1628
1629    void set_split_instruction(StreamVmInstructionVar *instr);
1630
1631    StreamVmInstructionVar * get_split_instruction() {
1632        return m_split_instr;
1633    }
1634
1635    StreamVmDp * generate_dp_object(){
1636
1637        if (!m_is_compiled) {
1638            return NULL;
1639        }
1640
1641        StreamVmDp * lp= new StreamVmDp(get_bss_ptr(),
1642                                        get_bss_size(),
1643                                        get_dp_instruction_buffer()->get_program(),
1644                                        get_dp_instruction_buffer()->get_program_size(),
1645                                        get_max_packet_update_offset(),
1646                                        get_prefix_size(),
1647                                        is_var_pkt_size(),
1648                                        m_is_random_var
1649                                        );
1650        assert(lp);
1651        return (lp);
1652
1653    }
1654
1655    /**
1656     * clone VM instructions
1657     *
1658     */
1659    void clone(StreamVm &other) const;
1660
1661
1662    bool is_vm_empty() const {
1663        return (m_inst_list.size() == 0);
1664    }
1665
1666    /**
1667     * add new instruction to the VM
1668     *
1669     */
1670    void add_instruction(StreamVmInstruction *inst);
1671
1672    /**
1673     * get const access to the instruction list
1674     *
1675     */
1676    const std::vector<StreamVmInstruction *> & get_instruction_list();
1677
1678    StreamDPVmInstructions  *           get_dp_instruction_buffer();
1679
1680    uint16_t                                  get_bss_size(){
1681        return (m_cur_var_offset );
1682    }
1683
1684    uint8_t *                                 get_bss_ptr(){
1685        return (m_bss );
1686    }
1687
1688
1689    uint16_t                                  get_max_packet_update_offset(){
1690        return ( m_max_field_update );
1691    }
1692
1693    uint16_t get_prefix_size() {
1694        return m_prefix_size;
1695    }
1696
1697    bool is_var_pkt_size(){
1698        return (m_is_change_pkt_size);
1699    }
1700
1701
1702    bool is_compiled() const {
1703        return m_is_compiled;
1704    }
1705
1706    /**
1707     * compile the VM
1708     * return true of success, o.w false
1709     *
1710     */
1711    void compile(uint16_t pkt_len);
1712
1713    ~StreamVm();
1714
1715    void Dump(FILE *fd);
1716
1717    /* raise exception */
1718    void  err(const std::string &err);
1719
1720    void set_pkt(uint8_t *pkt){
1721        m_pkt=pkt;
1722    }
1723
1724
1725    /**
1726     * return a pointer to a flow var / client var
1727     * by name if exists, otherwise NULL
1728     *
1729     */
1730    StreamVmInstructionVar * lookup_var_by_name(const std::string &var_name);
1731
1732private:
1733
1734    /* lookup for varible offset, */
1735    bool var_lookup(const std::string &var_name,VmFlowVarRec & var);
1736
1737    void  var_clear_table();
1738
1739    bool  var_add(const std::string &var_name,VmFlowVarRec & var);
1740
1741    uint16_t get_var_offset(const std::string &var_name);
1742
1743    void build_flow_var_table() ;
1744
1745    void build_bss();
1746
1747    void build_program();
1748
1749    void alloc_bss();
1750
1751    void free_bss();
1752
1753private:
1754
1755    void clean_max_field_cnt();
1756
1757    void add_field_cnt(uint16_t new_cnt);
1758
1759private:
1760    bool                               m_is_random_var;
1761    bool                               m_is_change_pkt_size;
1762    bool                               m_is_compiled;
1763    uint16_t                           m_prefix_size;
1764
1765    uint16_t                           m_pkt_size;
1766    double                             m_expected_pkt_size;
1767
1768    uint16_t                           m_cur_var_offset;
1769    uint16_t                           m_max_field_update; /* the location of the last byte that is going to be changed in the packet */
1770
1771    std::vector<StreamVmInstruction *> m_inst_list;
1772    std::unordered_map<std::string, VmFlowVarRec> m_flow_var_offset;
1773    uint8_t *                          m_bss;
1774
1775    StreamDPVmInstructions             m_instructions;
1776
1777    StreamVmInstructionVar             *m_split_instr;
1778    uint8_t                            *m_pkt;
1779
1780
1781
1782};
1783
1784#endif /* __TREX_STREAM_VM_API_H__ */
1785