diff options
Diffstat (limited to 'src/stateless/cp')
-rw-r--r-- | src/stateless/cp/trex_stream.cpp | 65 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream.h | 29 | ||||
-rw-r--r-- | src/stateless/cp/trex_streams_compiler.cpp | 353 | ||||
-rw-r--r-- | src/stateless/cp/trex_streams_compiler.h | 36 |
4 files changed, 470 insertions, 13 deletions
diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp index 1a05257c..5203b2a2 100644 --- a/src/stateless/cp/trex_stream.cpp +++ b/src/stateless/cp/trex_stream.cpp @@ -25,6 +25,71 @@ limitations under the License. /************************************** * stream *************************************/ + + +std::string TrexStream::get_stream_type_str(stream_type_t stream_type){ + + std::string res; + + + switch (stream_type) { + + case stCONTINUOUS : + res="stCONTINUOUS "; + break; + + case stSINGLE_BURST : + res="stSINGLE_BURST "; + break; + + case stMULTI_BURST : + res="stMULTI_BURST "; + break; + default: + res="Unknow "; + }; + return(res); +} + + +void TrexStream::Dump(FILE *fd){ + + fprintf(fd,"\n"); + fprintf(fd,"==> Stream_id : %lu \n",(ulong)m_stream_id); + fprintf(fd," Enabled : %lu \n",(ulong)(m_enabled?1:0)); + fprintf(fd," Self_start : %lu \n",(ulong)(m_self_start?1:0)); + + if (m_next_stream_id>=0) { + fprintf(fd," Nex_stream_id : %lu \n",(ulong)m_next_stream_id); + }else { + fprintf(fd," Nex_stream_id : %d \n",m_next_stream_id); + } + + fprintf(fd," Port_id : %lu \n",(ulong)m_port_id); + + if (m_isg_usec>0.0) { + fprintf(fd," isg : %6.2f \n",m_isg_usec); + } + fprintf(fd," type : %s \n",get_stream_type_str(m_type).c_str()); + + if ( m_type == TrexStream::stCONTINUOUS ) { + fprintf(fd," pps : %f \n",m_pps); + } + if (m_type == TrexStream::stSINGLE_BURST) { + fprintf(fd," pps : %f \n",m_pps); + fprintf(fd," burst : %lu \n",(ulong)m_burst_total_pkts); + } + if (m_type == TrexStream::stMULTI_BURST) { + fprintf(fd," pps : %f \n",m_pps); + fprintf(fd," burst : %lu \n",(ulong)m_burst_total_pkts); + fprintf(fd," mburst : %lu \n",(ulong)m_num_bursts); + if (m_ibg_usec>0.0) { + fprintf(fd," m_ibg_usec : %f \n",m_ibg_usec); + } + } +} + + TrexStream::TrexStream(uint8_t type, uint8_t port_id, uint32_t stream_id) : m_port_id(port_id), m_stream_id(stream_id) { diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index 151723ad..0634829e 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -1,5 +1,6 @@ /* Itay Marom + Hanoch Haim Cisco Systems, Inc. */ @@ -65,6 +66,9 @@ public: stMULTI_BURST = 6 }; + typedef uint8_t stream_type_t ; + + static std::string get_stream_type_str(stream_type_t stream_type); public: TrexStream(uint8_t type,uint8_t port_id, uint32_t stream_id); @@ -80,6 +84,12 @@ public: /* access the stream json */ const Json::Value & get_stream_json(); + /* compress the stream id to be zero based */ + void fix_dp_stream_id(uint32_t my_stream_id,int next_stream_id){ + m_stream_id = my_stream_id; + m_next_stream_id = next_stream_id; + } + double get_pps() { return m_pps; } @@ -92,21 +102,29 @@ public: m_type = type; } - uint8_t get_type(void){ + uint8_t get_type(void) const { return ( m_type ); } + bool is_dp_next_stream(){ + if (m_next_stream_id<0) { + return (false); + }else{ + return (true); + } + } + void set_multi_burst(uint32_t burst_total_pkts, - uint32_t num_bursts, - double ibg_usec){ + uint32_t num_bursts, + double ibg_usec) { m_burst_total_pkts = burst_total_pkts; m_num_bursts = num_bursts; m_ibg_usec = ibg_usec; } - void set_signle_burtst(uint32_t burst_total_pkts){ + void set_single_burst(uint32_t burst_total_pkts){ set_multi_burst(burst_total_pkts,1,0.0); } @@ -132,11 +150,12 @@ public: return (dp); } + void Dump(FILE *fd); public: /* basic */ uint8_t m_type; uint8_t m_port_id; - uint32_t m_stream_id; + uint32_t m_stream_id; /* id from RPC can be anything */ /* config fields */ diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 580db51c..bdfc3c01 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -19,9 +19,118 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include <string.h> +#include <string> +#include <sstream> #include <trex_streams_compiler.h> #include <trex_stream.h> +#include <assert.h> +#include <trex_stateless.h> +#include <iostream> + +/** + * describes a graph node in the pre compile check + * + * @author imarom (16-Nov-15) + */ +class GraphNode { +public: + GraphNode(TrexStream *stream, GraphNode *next) : m_stream(stream), m_next(next) { + marked = false; + m_compressed_stream_id=-1; + } + + uint32_t get_stream_id() const { + return m_stream->m_stream_id; + } + + const TrexStream *m_stream; + GraphNode *m_next; + std::vector<const GraphNode *> m_parents; + bool marked; + int m_compressed_stream_id; +}; + +/** + * node map + * + */ +class GraphNodeMap { +public: + + GraphNodeMap() : m_dead_end(NULL, NULL) { + + } + + bool add(GraphNode *node) { + if (has(node->get_stream_id())) { + return false; + } + + m_nodes[node->get_stream_id()] = node; + + if (node->m_stream->m_self_start) { + m_roots.push_back(node); + } + + return true; + } + + bool has(uint32_t stream_id) { + + return (get(stream_id) != NULL); + } + + GraphNode * get(uint32_t stream_id) { + + if (stream_id == -1) { + return &m_dead_end; + } + + auto search = m_nodes.find(stream_id); + + if (search != m_nodes.end()) { + return search->second; + } else { + return NULL; + } + } + + void clear_marks() { + for (auto node : m_nodes) { + node.second->marked = false; + } + } + + void get_unmarked(std::vector <GraphNode *> &unmarked) { + for (auto node : m_nodes) { + if (!node.second->marked) { + unmarked.push_back(node.second); + } + } + } + + + ~GraphNodeMap() { + for (auto node : m_nodes) { + delete node.second; + } + m_nodes.clear(); + } + + std::vector <GraphNode *> & get_roots() { + return m_roots; + } + + + std::unordered_map<uint32_t, GraphNode *> get_nodes() { + return m_nodes; + } + +private: + std::unordered_map<uint32_t, GraphNode *> m_nodes; + std::vector <GraphNode *> m_roots; + GraphNode m_dead_end; +}; /************************************** * stream compiled object @@ -36,15 +145,37 @@ TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { m_objs.clear(); } + +void +TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream){ + + obj_st obj; + + obj.m_stream = stream->clone_as_dp(); + + m_objs.push_back(obj); +} + void -TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream) { +TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream, + uint32_t my_dp_id, int next_dp_id) { obj_st obj; obj.m_stream = stream->clone_as_dp(); + /* compress the id's*/ + obj.m_stream->fix_dp_stream_id(my_dp_id,next_dp_id); m_objs.push_back(obj); } +void TrexStreamsCompiledObj::Dump(FILE *fd){ + for (auto obj : m_objs) { + obj.m_stream->Dump(fd); + } +} + + + TrexStreamsCompiledObj * TrexStreamsCompiledObj::clone() { @@ -63,11 +194,213 @@ TrexStreamsCompiledObj::clone() { return new_compiled_obj; } +void +TrexStreamsCompiler::add_warning(const std::string &warning) { + m_warnings.push_back("*** warning: " + warning); +} + +void +TrexStreamsCompiler::err(const std::string &err) { + throw TrexException("*** error: " + err); +} + +void +TrexStreamsCompiler::check_stream(const TrexStream *stream) { + std::stringstream ss; + + /* cont. stream can point only on itself */ + if (stream->get_type() == TrexStream::stCONTINUOUS) { + if (stream->m_next_stream_id != -1) { + ss << "continous stream '" << stream->m_stream_id << "' cannot point on another stream"; + err(ss.str()); + } + } +} + +void +TrexStreamsCompiler::allocate_pass(const std::vector<TrexStream *> &streams, + GraphNodeMap *nodes) { + std::stringstream ss; + uint32_t compressed_stream_id=0; + + + /* first pass - allocate all nodes and check for duplicates */ + for (auto stream : streams) { + + /* skip non enabled streams */ + if (!stream->m_enabled) { + continue; + } + + /* sanity check on the stream itself */ + check_stream(stream); + + /* duplicate stream id ? */ + if (nodes->has(stream->m_stream_id)) { + ss << "duplicate instance of stream id " << stream->m_stream_id; + err(ss.str()); + } + + GraphNode *node = new GraphNode(stream, NULL); + /* allocate new compressed id */ + node->m_compressed_stream_id = compressed_stream_id; + + compressed_stream_id++; + + /* add to the map */ + assert(nodes->add(node)); + } + +} + +/** + * on this pass we direct the graph to point to the right nodes + * + */ +void +TrexStreamsCompiler::direct_pass(GraphNodeMap *nodes) { + + /* second pass - direct the graph */ + for (auto p : nodes->get_nodes()) { + + GraphNode *node = p.second; + const TrexStream *stream = node->m_stream; + + /* check the stream points on an existing stream */ + GraphNode *next_node = nodes->get(stream->m_next_stream_id); + if (!next_node) { + std::stringstream ss; + ss << "stream " << node->get_stream_id() << " is pointing on non existent stream " << stream->m_next_stream_id; + err(ss.str()); + } + + node->m_next = next_node; + + /* do we have more than one parent ? */ + next_node->m_parents.push_back(node); + } + + + /* check for multiple parents */ + for (auto p : nodes->get_nodes()) { + GraphNode *node = p.second; + + if (node->m_parents.size() > 0 ) { + std::stringstream ss; + + ss << "stream " << node->get_stream_id() << " is triggered by multiple streams: "; + for (auto x : node->m_parents) { + ss << x->get_stream_id() << " "; + } + + add_warning(ss.str()); + } + } +} + +/** + * mark sure all the streams are reachable + * + */ +void +TrexStreamsCompiler::check_for_unreachable_streams(GraphNodeMap *nodes) { + /* start with the roots */ + std::vector <GraphNode *> next_nodes = nodes->get_roots(); + + + nodes->clear_marks(); + + /* run BFS from all the roots */ + while (!next_nodes.empty()) { + + /* pull one */ + GraphNode *node = next_nodes.back(); + next_nodes.pop_back(); + if (node->marked) { + continue; + } + + node->marked = true; + + if (node->m_next != NULL) { + next_nodes.push_back(node->m_next); + } + + } + + std::vector <GraphNode *> unmarked; + nodes->get_unmarked(unmarked); + + if (!unmarked.empty()) { + std::stringstream ss; + for (auto node : unmarked) { + ss << "stream " << node->get_stream_id() << " is unreachable from any other stream\n"; + } + err(ss.str()); + } + + +} + +/** + * check validation of streams for compile + * + * @author imarom (16-Nov-15) + * + * @param streams + * @param fail_msg + * + * @return bool + */ +void +TrexStreamsCompiler::pre_compile_check(const std::vector<TrexStream *> &streams, + GraphNodeMap & nodes) { + + m_warnings.clear(); + + /* allocate nodes */ + allocate_pass(streams, &nodes); + + /* direct the graph */ + direct_pass(&nodes); + + /* check for non reachable streams inside the graph */ + check_for_unreachable_streams(&nodes); + +} + /************************************** * stream compiler *************************************/ bool -TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams, TrexStreamsCompiledObj &obj) { +TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams, + TrexStreamsCompiledObj &obj, + std::string *fail_msg) { + +#if 0 + fprintf(stdout,"------------pre compile \n"); + for (auto stream : streams) { + stream->Dump(stdout); + } + fprintf(stdout,"------------pre compile \n"); +#endif + + GraphNodeMap nodes; + + + /* compile checks */ + try { + pre_compile_check(streams,nodes); + } catch (const TrexException &ex) { + if (fail_msg) { + *fail_msg = ex.what(); + } else { + std::cout << ex.what(); + } + return false; + } + + /* for now we do something trivial, */ for (auto stream : streams) { @@ -76,13 +409,19 @@ TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams, TrexStrea continue; } - /* for now skip also non self started streams */ - if (!stream->m_self_start) { - continue; + int new_id= nodes.get(stream->m_stream_id)->m_compressed_stream_id; + assert(new_id>=0); + uint32_t my_stream_id = (uint32_t)new_id; + int my_next_stream_id=-1; + if (stream->m_next_stream_id>=0) { + my_next_stream_id=nodes.get(stream->m_next_stream_id)->m_compressed_stream_id; } /* add it */ - obj.add_compiled_stream(stream); + obj.add_compiled_stream(stream, + my_stream_id, + my_next_stream_id + ); } return true; diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 44c8a0fc..200f7ce9 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -23,9 +23,11 @@ limitations under the License. #include <stdint.h> #include <vector> +#include <string> class TrexStreamsCompiler; class TrexStream; +class GraphNodeMap; /** * compiled object for a table of streams @@ -48,6 +50,10 @@ public: return m_objs; } + uint8_t get_port_id(){ + return (m_port_id); + } + /** * clone the compiled object * @@ -58,8 +64,13 @@ public: return (m_mul); } + void Dump(FILE *fd); + private: + void add_compiled_stream(TrexStream * stream, + uint32_t my_dp_id, int next_dp_id); void add_compiled_stream(TrexStream * stream); + std::vector<obj_st> m_objs; uint8_t m_port_id; @@ -68,13 +79,36 @@ private: class TrexStreamsCompiler { public: + /** * compiles a vector of streams to an object passable to the DP * * @author imarom (28-Oct-15) * */ - bool compile(const std::vector<TrexStream *> &streams, TrexStreamsCompiledObj &obj); + bool compile(const std::vector<TrexStream *> &streams, TrexStreamsCompiledObj &obj, std::string *fail_msg = NULL); + + /** + * + * returns a reference pointer to the last compile warnings + * if no warnings were produced - the vector is empty + */ + const std::vector<std::string> & get_last_compile_warnings() { + return m_warnings; + } + +private: + + void pre_compile_check(const std::vector<TrexStream *> &streams, + GraphNodeMap & nodes); + void allocate_pass(const std::vector<TrexStream *> &streams, GraphNodeMap *nodes); + void direct_pass(GraphNodeMap *nodes); + void check_for_unreachable_streams(GraphNodeMap *nodes); + void check_stream(const TrexStream *stream); + void add_warning(const std::string &warning); + void err(const std::string &err); + + std::vector<std::string> m_warnings; }; #endif /* __TREX_STREAMS_COMPILER_H__ */ |