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