diff options
author | imarom <imarom@cisco.com> | 2016-09-18 14:40:13 +0300 |
---|---|---|
committer | imarom <imarom@cisco.com> | 2016-09-25 15:04:21 +0300 |
commit | 0b520a31268bea0492795a56c4a65d93cdb21676 (patch) | |
tree | b3f76881d52c39b62cf4dac5d9bab86c7c13dce9 | |
parent | 0f1d226c5fc94d4d28665b9c1f3ffc2bac11cdfc (diff) |
client var support split now
-rw-r--r-- | scripts/stl/tests/multi_core_test.py | 99 | ||||
-rw-r--r-- | src/gtest/trex_stateless_gtest.cpp | 4 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 10 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream_vm.cpp | 52 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream_vm.h | 241 | ||||
-rw-r--r-- | src/stateless/cp/trex_vm_splitter.cpp | 5 |
6 files changed, 264 insertions, 147 deletions
diff --git a/scripts/stl/tests/multi_core_test.py b/scripts/stl/tests/multi_core_test.py index a0ec3b2d..17896b5e 100644 --- a/scripts/stl/tests/multi_core_test.py +++ b/scripts/stl/tests/multi_core_test.py @@ -13,8 +13,8 @@ class STLMultiCore(object): def create_stream (self, size, pps, isg, vm ): # Create base packet and pad it to size - base_pkt = Ether()/IP()/UDP() - pad = max(0, size - len(base_pkt)) * 'x' + base_pkt = Ether()/IP()/UDP(sport = 1500, dport = 1500) + pad = max(0, size - len(base_pkt)) * b'\xff' pkt = STLPktBuilder(pkt = base_pkt/pad, vm = vm) @@ -24,46 +24,89 @@ class STLMultiCore(object): mode = STLTXCont(pps = pps)) - def generate_var (self, rng, i): + def generate_var (self, rng, i, vm, pkt_offset): - d = {'name': str(i)} + name = "var-{0}".format(i) - d['size'] = rng.choice([1, 2, 4]) - max_val = (1 << d['size'] * 8) + size = rng.choice([1, 2, 4]) + bound = (1 << (size * 8)) - 1 - d['start'] = rng.randint(0, max_val - 1) - d['end'] = rng.randint(d['start'], max_val) - d['step'] = rng.randint(1, 1000) - d['op'] = rng.choice(['inc', 'dec']) + min_value = rng.randint(0, bound - 1) + max_value = rng.randint(min_value, bound) + step = rng.randint(1, 1000) + op = rng.choice(['inc', 'dec']) + + vm += [STLVmFlowVar(name = str(i), + min_value = min_value, + max_value = max_value, + size = size, + op = op), + STLVmWrFlowVar(fv_name = name, pkt_offset = pkt_offset), + ] + + print('name: {:}, start: {:}, end: {:}, size: {:}, op: {:}, step {:}'.format(name, + min_value, + max_value, + size, + op, + step)) + + return size + + + def generate_tuple_var (self, rng, i, vm, pkt_offset): + name = "tuple-{0}".format(i) + + # ip + ip_bound = (1 << (4 * 8)) - 1 + ip_min = rng.randint(0, ip_bound - 1) + ip_max = rng.randint(ip_min, ip_bound) + + # port + port_bound = (1 << (2 * 8)) - 1 + port_min = rng.randint(0, port_bound - 1) + port_max = rng.randint(port_min, port_bound - 1) + + vm += [STLVmTupleGen(ip_min = ip_min, ip_max = ip_max, + port_min = port_min, port_max = port_max, + name = name), + STLVmWrFlowVar (fv_name = name + ".ip", pkt_offset = pkt_offset ), # write ip to packet IP.src] + STLVmWrFlowVar (fv_name = name + ".port", pkt_offset = (pkt_offset + 4) ), + ] + + print('name: {:}, ip_start: {:}, ip_end: {:}, port_start: {:}, port_end: {:}'.format(name, + ip_min, + ip_max, + port_min, + port_max)) + + return 8 - return d - def dump_var (self, var): - return 'name: {:}, start: {:}, end: {:}, size: {:}, op: {:}, step {:}'.format(var['name'], var['start'], var['end'], var['size'], var['op'], var['step']) def get_streams (self, direction = 0, **kwargs): rng = random.Random(kwargs.get('seed', 1)) + var_type = kwargs.get('var_type', 'plain') + + + var_type = 'tuple' + vm = [] # base offset pkt_offset = 42 - vm = [] print("\nusing the following vars:\n") - for i in range(10): - var = self.generate_var(rng, i) - print("at offset {:} - var: {:}".format(pkt_offset, self.dump_var(var))) - vm += [STLVmFlowVar(name = var['name'], - min_value = var['start'], - max_value = var['end'], - size = var['size'], - op = var['op']), - STLVmWrFlowVar(fv_name = var['name'], pkt_offset = pkt_offset), - ] - pkt_offset += var['size'] - - - + + if var_type == 'plain': + for i in range(20): + pkt_offset += self.generate_var(rng, i, vm, pkt_offset) + else: + for i in range(5): + pkt_offset += self.generate_tuple_var(rng, i, vm, pkt_offset) + + + print("\n") # create imix streams diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index a6bbc6fe..96a6d255 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -4189,8 +4189,6 @@ public: vm.add_instruction(new StreamVmInstructionFixChecksumIpv4(14)); - vm.set_split_instruction(split_instr); - } void set_client_var_as_split(uint32_t client_min_value, @@ -4220,8 +4218,6 @@ public: /* src port */ vm.add_instruction(new StreamVmInstructionWriteToPkt("var1.port",34, 0,true)); - - vm.set_split_instruction(split_instr); } void run(uint8_t dp_core_count, uint8_t dp_core_to_check) { diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index f3addfd3..e5072b9e 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -430,16 +430,6 @@ TrexRpcCmdAddStream::parse_vm(const Json::Value &vm, std::unique_ptr<TrexStream> } } - const std::string &var_name = parse_string(vm, "split_by_var", result); - if (var_name != "") { - StreamVmInstructionVar *instr = stream->m_vm.lookup_var_by_name(var_name); - if (!instr) { - std::stringstream ss; - ss << "VM: request to split by variable '" << var_name << "' but does not exists"; - generate_parse_err(result, ss.str()); - } - stream->m_vm.set_split_instruction(instr); - } stream->m_cache_size = parse_uint16(vm, "cache", result,0); /* default is zero */ } diff --git a/src/stateless/cp/trex_stream_vm.cpp b/src/stateless/cp/trex_stream_vm.cpp index 4bfd7d0d..594e9cf2 100644 --- a/src/stateless/cp/trex_stream_vm.cpp +++ b/src/stateless/cp/trex_stream_vm.cpp @@ -301,7 +301,7 @@ void StreamVmInstructionFlowClient::Dump(FILE *fd){ fprintf(fd," client_var ,%s , ",m_var_name.c_str()); - fprintf(fd," ip:(%x-%x) port:(%x-%x) flow_limit:%lu flags: %x\n",m_client_min,m_client_max, m_port_min,m_port_max,(ulong)m_limit_num_flows,m_flags); + //fprintf(fd," ip:(%x-%x) port:(%x-%x) flow_limit:%lu flags: %x\n",m_client_min,m_client_max, m_port_min,m_port_max,(ulong)m_limit_num_flows,m_flags); } @@ -345,7 +345,7 @@ StreamVmInstruction::~StreamVmInstruction() { * **************************/ void StreamVm::add_instruction(StreamVmInstruction *inst) { - + if (inst->get_instruction_type() == StreamVmInstruction::itFLOW_MAN) { StreamVmInstructionFlowMan * ins_man=(StreamVmInstructionFlowMan *)inst; if (ins_man->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM) { @@ -357,6 +357,10 @@ void StreamVm::add_instruction(StreamVmInstruction *inst) { m_is_change_pkt_size = true; } + if (inst->need_split()) { + m_is_split_needed = true; + } + m_inst_list.push_back(inst); } @@ -1047,8 +1051,8 @@ void StreamVm::build_program(){ client_cmd.m_flow_offset = get_var_offset(lpMan->m_var_name+".ip"); /* start offset */ client_cmd.m_flags = 0; /* not used */ client_cmd.m_pad = 0; - client_cmd.m_min_ip = lpMan->m_client_min; - client_cmd.m_max_ip = lpMan->m_client_max; + client_cmd.m_min_ip = lpMan->m_ip.m_min_value; + client_cmd.m_max_ip = lpMan->m_ip.m_max_value; m_instructions.add_command(&client_cmd,sizeof(client_cmd)); }else{ @@ -1058,10 +1062,15 @@ void StreamVm::build_program(){ client_cmd.m_flow_offset = get_var_offset(lpMan->m_var_name+".ip"); /* start offset */ client_cmd.m_flags = 0; /* not used */ client_cmd.m_pad = 0; - client_cmd.m_min_port = lpMan->m_port_min; - client_cmd.m_max_port = lpMan->m_port_max; - client_cmd.m_min_ip = lpMan->m_client_min; - client_cmd.m_max_ip = lpMan->m_client_max; + + client_cmd.m_min_port = lpMan->m_port.m_min_value; + client_cmd.m_max_port = lpMan->m_port.m_max_value; + client_cmd.m_port_step = lpMan->m_port.m_step; + + client_cmd.m_min_ip = lpMan->m_ip.m_min_value; + client_cmd.m_max_ip = lpMan->m_ip.m_max_value; + client_cmd.m_ip_step = lpMan->m_ip.m_step; + client_cmd.m_limit_flows = lpMan->m_limit_num_flows; m_instructions.add_command(&client_cmd,sizeof(client_cmd)); } @@ -1119,16 +1128,6 @@ void StreamVm::build_bss() { } } -/** - * set the VM split instruction - * instr is a pointer to an instruction inside - * the VM program - * - */ -void -StreamVm::set_split_instruction(StreamVmInstructionVar *instr) { - m_split_instr = instr; -} /** * clone VM from this VM to 'other' @@ -1144,22 +1143,17 @@ StreamVm::clone(StreamVm &other) const { delete instr; } + other.m_is_random_var = false; + other.m_is_change_pkt_size = false; + other.m_is_split_needed = false; + other.m_is_compiled = false; + other.m_inst_list.clear(); for (auto instr : m_inst_list) { StreamVmInstruction *new_instr = instr->clone(); - - other.m_inst_list.push_back(new_instr); - - /* for the split instruction - find the right one */ - if (instr == m_split_instr) { - /* dynamic cast must succeed here */ - other.m_split_instr = dynamic_cast<StreamVmInstructionVar *>(new_instr); - assert(other.m_split_instr); - } + other.add_instruction(new_instr); } - - other.m_is_random_var = m_is_random_var; } /** diff --git a/src/stateless/cp/trex_stream_vm.h b/src/stateless/cp/trex_stream_vm.h index ab2a4fa8..0556eaff 100644 --- a/src/stateless/cp/trex_stream_vm.h +++ b/src/stateless/cp/trex_stream_vm.h @@ -30,6 +30,17 @@ limitations under the License. #include "pal_utl.h" #include "mbuf.h" +class StreamVmInstructionFlowClient; + +/** + * two functions ahead are used by both control plane and + * dataplane to allow fast inc/dec and handle overflow + * + * a - low bound + * b - high bound + * c - current value + * step - how many to advance / go back + */ static inline uint64_t inc_mod(uint64_t a, uint64_t b, uint64_t c, uint64_t step) { /* check if we have enough left for simple inc */ @@ -52,6 +63,36 @@ uint64_t dec_mod(uint64_t a, uint64_t b, uint64_t c, uint64_t step) { } } +/** + * a slower set of functions that indicate an overflow + * + */ +static inline +uint64_t inc_mod_of(uint64_t a, uint64_t b, uint64_t c, uint64_t step, bool &of) { + /* check if we have enough left for simple inc */ + uint64_t left = b - c; + if (step <= left) { + of = false; + return (c + step); + } else { + of = true; + return (a + (step - left - 1)); // restart consumes also 1 + } +} + +static inline +uint64_t dec_mod_of(uint64_t a, uint64_t b, uint64_t c, uint64_t step, bool &of) { + /* check if we have enough left for simple dec */ + uint64_t left = c - a; + if (step <= left) { + of = false; + return (c - step); + } else { + of = true; + return (b - (step - left - 1)); // restart consumes also 1 + } +} + //https://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/ //Used to seed the generator. @@ -571,26 +612,34 @@ struct StreamDPOpClientsLimit { uint8_t m_flow_offset; /* offset into the flow var bytes */ uint8_t m_flags; uint8_t m_pad; + uint16_t m_min_port; uint16_t m_max_port; + uint16_t m_port_step; uint32_t m_min_ip; uint32_t m_max_ip; + uint32_t m_ip_step; + uint32_t m_limit_flows; /* limit the number of flows */ public: void dump(FILE *fd,std::string opt); inline void run(uint8_t * flow_var_base) { - StreamDPFlowClient * lp= (StreamDPFlowClient *)(flow_var_base+m_flow_offset); - lp->cur_ip++; - if (lp->cur_ip > m_max_ip ) { - lp->cur_ip= m_min_ip; - lp->cur_port++; - if (lp->cur_port > m_max_port) { - lp->cur_port = m_min_port; - } + bool of; + + StreamDPFlowClient *lp = (StreamDPFlowClient *)(flow_var_base + m_flow_offset); + + /* first advance the outer var (IP) */ + lp->cur_ip = inc_mod_of(m_min_ip, m_max_ip, lp->cur_ip, m_ip_step, of); + + /* if we had an overflow - advance the port */ + if (of) { + lp->cur_port = inc_mod(m_min_port, m_max_port, lp->cur_port, m_port_step); } + /* TODO: handle limit */ + #if 0 if (m_limit_flows) { lp->cur_flow_id++; if ( lp->cur_flow_id > m_limit_flows ){ @@ -600,6 +649,7 @@ public: lp->cur_port = m_min_port; } } + #endif } @@ -937,6 +987,11 @@ public: virtual StreamVmInstruction * clone() = 0; + /* by default a regular instruction is not splitable for multicore */ + virtual bool need_split() const { + return false; + } + bool is_var_instruction() const { instruction_type_t type = get_instruction_type(); return ( (type == itFLOW_MAN) || (type == itFLOW_CLIENT) ); @@ -968,37 +1023,19 @@ public: return m_var_name; } - virtual bool need_split() const = 0; - /** * what is the split range for this var * */ - virtual uint64_t get_range() const = 0; + //virtual uint64_t get_range() const = 0; /** * allows a var instruction to be updated * for multicore (split) * */ - virtual void update(uint64_t phase, uint64_t step_multiplier) = 0; - - uint64_t peek_next(uint64_t skip = 1) const { - return peek(skip, true); - } - - uint64_t peek_prev(uint64_t skip = 1) const { - return peek(skip, false); - } - + virtual void update(uint64_t phase, uint64_t step_mul) = 0; -protected: - /** - * a var instruction should be able to peek back/forward with - * any number of steps in the series - * - */ - virtual uint64_t peek(int skip = 1, bool forward = true) const = 0; public: @@ -1037,6 +1074,8 @@ public: */ class StreamVmInstructionFlowMan : public StreamVmInstructionVar { + friend class StreamVmInstructionFlowClient; + public: virtual instruction_type_t get_instruction_type() const { @@ -1095,16 +1134,30 @@ public: assert(m_init_value <= m_max_value); } - virtual void update(uint64_t phase, uint64_t step_multiplier) { + virtual void update(uint64_t phase, uint64_t step_mul) { + /* update the init value to be with a phase */ m_init_value = peek_next(phase); - m_step = (m_step * step_multiplier) % get_range(); + + /* multiply the step */ + m_step = (m_step * step_mul) % get_range(); assert(m_init_value >= m_min_value); assert(m_init_value <= m_max_value); } - + + uint64_t peek_next(uint64_t skip = 1) const { + bool dummy; + return peek(skip, true, dummy); + } + + uint64_t peek_prev(uint64_t skip = 1) const { + bool dummy; + return peek(skip, false, dummy); + } + + virtual void Dump(FILE *fd); void sanity_check(uint32_t ins_id,StreamVm *lp); @@ -1123,7 +1176,7 @@ public: protected: /* fetch the next value in the variable (used for core phase and etc.) */ - virtual uint64_t peek(int skip = 1, bool forward = true) const { + uint64_t peek(int skip, bool forward, bool &of) const { if (m_op == FLOW_VAR_OP_RANDOM) { return m_init_value; @@ -1135,9 +1188,9 @@ protected: uint64_t next_step = (m_step * skip) % get_range(); if (add) { - return inc_mod(m_min_value, m_max_value, m_init_value, next_step); + return inc_mod_of(m_min_value, m_max_value, m_init_value, next_step, of); } else { - return dec_mod(m_min_value, m_max_value, m_init_value, next_step); + return dec_mod_of(m_min_value, m_max_value, m_init_value, next_step, of); } } @@ -1320,22 +1373,26 @@ public: } StreamVmInstructionFlowClient(const std::string &var_name, - uint32_t client_min_value, - uint32_t client_max_value, - uint16_t port_min, - uint16_t port_max, - uint32_t limit_num_flows, /* zero means don't limit */ - uint16_t flags - ) : StreamVmInstructionVar(var_name) { - - m_client_min = client_min_value; - m_client_max = client_max_value; - - m_port_min = port_min; - m_port_max = port_max; + uint32_t client_min_value, + uint32_t client_max_value, + uint16_t port_min, + uint16_t port_max, + uint32_t limit_num_flows, /* zero means don't limit */ + uint16_t flags + ) : StreamVmInstructionVar(var_name), + m_ip("ip", 4, StreamVmInstructionFlowMan::FLOW_VAR_OP_INC, client_min_value, client_min_value, client_max_value, 1), + m_port("port", 2, StreamVmInstructionFlowMan::FLOW_VAR_OP_INC, port_min, port_min, port_max, 1) { m_limit_num_flows = limit_num_flows; m_flags = flags; + + } + + StreamVmInstructionFlowClient(const StreamVmInstructionFlowClient &other) :StreamVmInstructionVar(other.m_var_name), + m_ip(other.m_ip), + m_port(other.m_port) { + m_limit_num_flows = other.m_limit_num_flows; + m_flags = other.m_flags; } virtual void Dump(FILE *fd); @@ -1345,11 +1402,11 @@ public: } uint32_t get_ip_range() const { - return (m_client_max - m_client_min + 1); + return m_ip.get_range(); } uint16_t get_port_range() const { - return (m_port_max - m_port_min + 1); + return m_port.get_range(); } virtual uint64_t get_range() const { @@ -1365,33 +1422,64 @@ public: StreamVmInstructionFlowClient::CLIENT_F_UNLIMITED_FLOWS ); } + void get_bss_init_value(uint32_t &ip, uint16_t &port) { + /* fetch the previous values by 1 */ + peek_prev(ip, port, 1); + } + virtual StreamVmInstruction * clone() { - return new StreamVmInstructionFlowClient(m_var_name, - m_client_min, - m_client_max, - m_port_min, - m_port_max, - m_limit_num_flows, - m_flags); + return new StreamVmInstructionFlowClient(*this); } - virtual void update(uint64_t phase, uint64_t step_multiplier) { + virtual void update(uint64_t phase, uint64_t step_mul) { + + /* update outer var */ + m_ip.update(phase, step_mul); + + /* inner var should advance as the whole wrap arounds */ + uint16_t port_phase = phase / m_ip.get_range(); + uint16_t port_step_mul = 1 + (step_mul / m_ip.get_range()); + + m_port.update(port_phase, port_step_mul); + } protected: - virtual uint64_t peek(int skip = 1, bool forward = true) const { - return (0); + + void peek_prev(uint32_t &next_ip, uint16_t &next_port, int skip = 1) { + peek(next_ip, next_port, skip, false); + } + + void peek_next(uint32_t &next_ip, uint16_t &next_port, int skip = 1) { + peek(next_ip, next_port, skip, true); + } + + /** + * defines a froward/backward method + * + */ + void peek(uint32_t &next_ip, uint16_t &next_port, int skip = 1, bool forward = true) const { + bool of = false; + + next_ip = m_ip.peek(skip, forward, of); + + int port_skip = skip / m_ip.get_range(); + if (of) { + port_skip++; + } + + next_port = m_port.peek(port_skip, forward, of); + } public: - uint32_t m_client_min; // min ip - uint32_t m_client_max; // max ip - uint16_t m_port_min; // start port - uint16_t m_port_max; // start port - uint32_t m_limit_num_flows; // number of flows - uint16_t m_flags; + StreamVmInstructionFlowMan m_ip; + StreamVmInstructionFlowMan m_port; + + uint32_t m_limit_num_flows; // number of flows + uint16_t m_flags; }; @@ -1648,10 +1736,10 @@ public: m_expected_pkt_size=0.0; m_cur_var_offset=0; - m_is_random_var=false; - m_is_change_pkt_size=false; + m_is_random_var = false; + m_is_change_pkt_size = false; + m_is_split_needed = false; - m_split_instr=NULL; m_is_compiled = false; m_pkt=0; } @@ -1666,13 +1754,6 @@ public: double calc_expected_pkt_size(uint16_t regular_pkt_size) const; - - void set_split_instruction(StreamVmInstructionVar *instr); - - StreamVmInstructionVar * get_split_instruction() { - return m_split_instr; - } - StreamVmDp * generate_dp_object(){ if (!m_is_compiled) { @@ -1705,6 +1786,14 @@ public: } /** + * return true if the VM is splitable + * for multicore + */ + bool need_split() const { + return m_is_split_needed; + } + + /** * add new instruction to the VM * */ @@ -1800,6 +1889,7 @@ private: private: bool m_is_random_var; bool m_is_change_pkt_size; + bool m_is_split_needed; bool m_is_compiled; uint16_t m_prefix_size; @@ -1815,7 +1905,6 @@ private: StreamDPVmInstructions m_instructions; - StreamVmInstructionVar *m_split_instr; uint8_t *m_pkt; diff --git a/src/stateless/cp/trex_vm_splitter.cpp b/src/stateless/cp/trex_vm_splitter.cpp index 1ff43829..0c2edd88 100644 --- a/src/stateless/cp/trex_vm_splitter.cpp +++ b/src/stateless/cp/trex_vm_splitter.cpp @@ -89,6 +89,11 @@ TrexVmSplitter::split(TrexStream *stream, std::vector<TrexStream *> core_streams bool TrexVmSplitter::split_internal() { + /* no split needed ? fall back */ + if (!m_stream->m_vm.need_split()) { + return false; + } + duplicate_vm(); /* search for splitable instructions */ |