diff options
author | Hanoh Haim <hhaim@cisco.com> | 2016-05-10 17:49:25 +0300 |
---|---|---|
committer | Hanoh Haim <hhaim@cisco.com> | 2016-05-10 17:49:25 +0300 |
commit | 2d37b9f98020a4458aaad1f3fd05ca5e408213e0 (patch) | |
tree | 3a8cd16eb748711b72df37c6f7eea4842d73290a /src/stateless/dp | |
parent | 996f2451dba01f534420418eaac2856510682757 (diff) | |
parent | 63bf6aba10075a03fe6609369c1c7008afb85ba7 (diff) |
merge from master
Diffstat (limited to 'src/stateless/dp')
-rw-r--r-- | src/stateless/dp/trex_stateless_dp_core.cpp | 192 | ||||
-rw-r--r-- | src/stateless/dp/trex_stateless_dp_core.h | 29 | ||||
-rw-r--r-- | src/stateless/dp/trex_stream_node.h | 172 |
3 files changed, 377 insertions, 16 deletions
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 13bf5a5d..c5963625 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -358,6 +358,51 @@ bool TrexStatelessDpPerPort::pause_traffic(uint8_t port_id){ return (true); } +bool TrexStatelessDpPerPort::push_pcap(uint8_t port_id, + const std::string &pcap_filename, + double ipg_usec, + double speedup, + uint32_t count) { + + /* push pcap can only happen on an idle port from the core prespective */ + assert(m_state == TrexStatelessDpPerPort::ppSTATE_IDLE); + + CGenNodePCAP *pcap_node = m_core->allocate_pcap_node(); + if (!pcap_node) { + return (false); + } + + pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(port_id); + socket_id_t socket_id = m_core->m_node_gen.m_socket_id; + + uint8_t mac_addr[12]; + m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir, mac_addr); + + bool rc = pcap_node->create(port_id, + dir, + socket_id, + mac_addr, + pcap_filename, + ipg_usec, + speedup, + count); + if (!rc) { + m_core->free_node((CGenNode *)pcap_node); + return (false); + } + + /* schedule the node for now */ + pcap_node->m_time = m_core->m_cur_time_sec; + m_core->m_node_gen.add_node((CGenNode *)pcap_node); + + /* hold a pointer to the node */ + assert(m_active_pcap_node == NULL); + m_active_pcap_node = pcap_node; + + m_state = TrexStatelessDpPerPort::ppSTATE_PCAP_TX; + return (true); +} + bool TrexStatelessDpPerPort::stop_traffic(uint8_t port_id, bool stop_on_id, @@ -390,6 +435,19 @@ bool TrexStatelessDpPerPort::stop_traffic(uint8_t port_id, } } + /* check for active PCAP node */ + if (m_active_pcap_node) { + /* when got async stop from outside or duration */ + if (m_active_pcap_node->is_active()) { + m_active_pcap_node->mark_for_free(); + } else { + /* graceful stop - node was put out by the scheduler */ + m_core->free_node( (CGenNode *)m_active_pcap_node); + } + + m_active_pcap_node = NULL; + } + /* active stream should be zero */ assert(m_active_streams==0); m_active_nodes.clear(); @@ -401,9 +459,9 @@ bool TrexStatelessDpPerPort::stop_traffic(uint8_t port_id, void TrexStatelessDpPerPort::create(CFlowGenListPerThread * core){ m_core=core; m_state=TrexStatelessDpPerPort::ppSTATE_IDLE; - m_port_id=0; m_active_streams=0; m_active_nodes.clear(); + m_active_pcap_node = NULL; } @@ -709,6 +767,7 @@ void TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port, TrexStream * stream, TrexStreamsCompiledObj *comp) { + CGenNodeStateless *node = m_core->create_node_sl(); node->cache_mbuf_array_init(); @@ -977,6 +1036,42 @@ TrexStatelessDpCore::pause_traffic(uint8_t port_id){ lp_port->pause_traffic(port_id); } + +void +TrexStatelessDpCore::push_pcap(uint8_t port_id, + int event_id, + const std::string &pcap_filename, + double ipg_usec, + double speedup, + uint32_t count, + double duration) { + + TrexStatelessDpPerPort * lp_port = get_port_db(port_id); + + lp_port->set_event_id(event_id); + + /* delegate the command to the port */ + bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, speedup, count); + if (!rc) { + /* report back that we stopped */ + CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id); + TrexStatelessDpToCpMsgBase *event_msg = new TrexDpPortEventMsg(m_core->m_thread_id, + port_id, + event_id, + false); + ring->Enqueue((CGenNode *)event_msg); + return; + } + + + if (duration > 0.0) { + add_port_duration(duration, port_id, event_id); + } + + m_state = TrexStatelessDpCore::STATE_PCAP_TX; +} + + void TrexStatelessDpCore::update_traffic(uint8_t port_id, double factor) { @@ -995,21 +1090,10 @@ TrexStatelessDpCore::stop_traffic(uint8_t port_id, the scheduler invokes it, it will be free */ TrexStatelessDpPerPort * lp_port = get_port_db(port_id); - if ( lp_port->stop_traffic(port_id,stop_on_id,event_id) == false){ - /* nothing to do ! already stopped */ - //printf(" skip .. %f\n",m_core->m_cur_time_sec); return; } - /* inform the control plane we stopped - this might be a async stop - (streams ended) - */ - #if 0 - if ( are_all_ports_idle() ) { - /* just a place holder if we will need to do somthing in that case */ - } - #endif CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id); TrexStatelessDpToCpMsgBase *event_msg = new TrexDpPortEventMsg(m_core->m_thread_id, @@ -1038,3 +1122,87 @@ TrexStatelessDpCore::barrier(uint8_t port_id, int event_id) { event_id); ring->Enqueue((CGenNode *)event_msg); } + + +/** + * PCAP node + */ +bool CGenNodePCAP::create(uint8_t port_id, + pkt_dir_t dir, + socket_id_t socket_id, + const uint8_t *mac_addr, + const std::string &pcap_filename, + double ipg_usec, + double speedup, + uint32_t count) { + std::stringstream ss; + + m_type = CGenNode::PCAP_PKT; + m_flags = 0; + m_src_port = 0; + m_port_id = port_id; + m_count = count; + + /* mark this node as slow path */ + set_slow_path(true); + + if (ipg_usec != -1) { + /* fixed IPG */ + m_ipg_sec = usec_to_sec(ipg_usec / speedup); + m_speedup = 0; + } else { + /* packet IPG */ + m_ipg_sec = -1; + m_speedup = speedup; + } + + /* copy MAC addr info */ + memcpy(m_mac_addr, mac_addr, 12); + + /* set the dir */ + set_mbuf_dir(dir); + set_socket_id(socket_id); + + /* create the PCAP reader */ + m_reader = CCapReaderFactory::CreateReader((char *)pcap_filename.c_str(), 0, ss); + if (!m_reader) { + return false; + } + + m_raw_packet = new CCapPktRaw(); + if ( m_reader->ReadPacket(m_raw_packet) == false ){ + /* handle error */ + delete m_reader; + return (false); + } + + /* this is the reference time */ + //m_base_time = m_raw_packet->get_time(); + m_last_pkt_time = m_raw_packet->get_time(); + + /* ready */ + m_state = PCAP_ACTIVE; + + return true; +} + +/** + * cleanup for PCAP node + * + * @author imarom (08-May-16) + */ +void CGenNodePCAP::destroy() { + + if (m_raw_packet) { + delete m_raw_packet; + m_raw_packet = NULL; + } + + if (m_reader) { + delete m_reader; + m_reader = NULL; + } + + m_state = PCAP_INVALID; +} + diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index bdf84cfd..af2187ae 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -33,7 +33,7 @@ class CFlowGenListPerThread; class CGenNodeStateless; class TrexStreamsCompiledObj; class TrexStream; - +class CGenNodePCAP; class CDpOneStream { public: @@ -54,7 +54,8 @@ public: enum state_e { ppSTATE_IDLE, ppSTATE_TRANSMITTING, - ppSTATE_PAUSE + ppSTATE_PAUSE, + ppSTATE_PCAP_TX, }; @@ -70,6 +71,12 @@ public: bool update_traffic(uint8_t port_id, double factor); + bool push_pcap(uint8_t port_id, + const std::string &pcap_filename, + double ipg_usec, + double speedup, + uint32_t count); + bool stop_traffic(uint8_t port_id, bool stop_on_id, int event_id); @@ -91,11 +98,11 @@ public: public: state_e m_state; - uint8_t m_port_id; uint32_t m_active_streams; /* how many active streams on this port */ std::vector<CDpOneStream> m_active_nodes; /* holds the current active nodes */ + CGenNodePCAP *m_active_pcap_node; CFlowGenListPerThread * m_core ; int m_event_id; }; @@ -113,6 +120,7 @@ public: enum state_e { STATE_IDLE, STATE_TRANSMITTING, + STATE_PCAP_TX, STATE_TERMINATE }; @@ -151,7 +159,7 @@ public: */ void start_traffic(TrexStreamsCompiledObj *obj, double duration, - int m_event_id); + int event_id); /* pause the streams, work only if all are continues */ @@ -163,6 +171,19 @@ public: /** + * push a PCAP file on port + * + */ + void push_pcap(uint8_t port_id, + int event_id, + const std::string &pcap_filename, + double ipg_usec, + double speedup, + uint32_t count, + double duration); + + + /** * update current traffic rate * * @author imarom (25-Nov-15) diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index e9e5cf5b..b5395e78 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -26,6 +26,8 @@ limitations under the License. #include <stdio.h> class TrexStatelessDpCore; +class TrexStatelessDpPerPort; + #include <trex_stream.h> class TrexStatelessCpToDpMsgBase; @@ -448,6 +450,176 @@ private: static_assert(sizeof(CGenNodeStateless) == sizeof(CGenNode), "sizeof(CGenNodeStateless) != sizeof(CGenNode)" ); +/* this is a event for PCAP transmitting */ +struct CGenNodePCAP : public CGenNodeBase { +friend class TrexStatelessDpPerPort; + +public: + + /** + * creates a node from a PCAP file + */ + bool create(uint8_t port_id, + pkt_dir_t dir, + socket_id_t socket_id, + const uint8_t *mac_addr, + const std::string &pcap_filename, + double ipg_usec, + double speedup, + uint32_t count); + /** + * destroy the node cleaning up any data + * + */ + void destroy(); + + /** + * advance - will read the next packet + * + * @author imarom (03-May-16) + */ + void next() { + assert(is_active()); + + /* save the previous packet time */ + m_last_pkt_time = m_raw_packet->get_time(); + + /* advance */ + if ( m_reader->ReadPacket(m_raw_packet) == false ){ + m_count--; + + /* if its the end - go home... */ + if (m_count == 0) { + m_state = PCAP_INACTIVE; + return; + } + + /* rewind and load the first packet */ + m_reader->Rewind(); + if (!m_reader->ReadPacket(m_raw_packet)) { + m_state = PCAP_INACTIVE; + return; + } + } + + } + + /** + * return the time for the next scheduling for a packet + * + */ + inline double get_ipg() { + assert(m_state != PCAP_INVALID); + + /* fixed IPG */ + if (m_ipg_sec != -1) { + return m_ipg_sec; + } else { + return ((m_raw_packet->get_time() - m_last_pkt_time) / m_speedup); + } + } + + /** + * get the current packet as MBUF + * + */ + inline rte_mbuf_t *get_pkt() { + assert(m_state != PCAP_INVALID); + + rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc( get_socket_id(), m_raw_packet->getTotalLen()); + assert(m); + + char *p = rte_pktmbuf_append(m, m_raw_packet->getTotalLen()); + assert(p); + + /* copy the packet */ + memcpy(p, m_raw_packet->raw, m_raw_packet->getTotalLen()); + + /* fix the MAC */ + memcpy(p, m_mac_addr, 12); + + return (m); + } + + + inline void handle(CFlowGenListPerThread *thread) { + assert(m_state != PCAP_INVALID); + thread->m_node_gen.m_v_if->send_node( (CGenNode *)this); + + // read the next packet + next(); + + if (is_active()) { + m_time += get_ipg(); + thread->m_node_gen.m_p_queue.push((CGenNode *)this); + + } else { + thread->stop_stateless_traffic(get_port_id()); + } + } + + void set_mbuf_dir(pkt_dir_t dir) { + if (dir) { + m_flags |=NODE_FLAGS_DIR; + }else{ + m_flags &=~NODE_FLAGS_DIR; + } + } + + inline pkt_dir_t get_mbuf_dir(){ + return ((pkt_dir_t)( m_flags &1)); + } + + uint8_t get_port_id() { + return m_port_id; + } + + void mark_for_free() { + m_state = PCAP_MARKED_FOR_FREE; + } + + bool is_active() { + return (m_state == PCAP_ACTIVE); + } + + bool is_marked_for_free() { + return (m_state == PCAP_MARKED_FOR_FREE); + } + +private: + + enum { + PCAP_INVALID = 0, + PCAP_ACTIVE, + PCAP_INACTIVE, + PCAP_MARKED_FOR_FREE + }; + + /* cache line 0 */ + /* important stuff here */ + uint8_t m_mac_addr[12]; + uint8_t m_state; + + double m_last_pkt_time; + double m_speedup; + double m_ipg_sec; + uint32_t m_count; + + double m_next_time_offset; /* in sec */ + + CCapReaderBase *m_reader; + CCapPktRaw *m_raw_packet; + + uint8_t m_port_id; + + /* pad to match the size of CGenNode */ + uint8_t m_pad_end[33]; + +} __rte_cache_aligned; + + +static_assert(sizeof(CGenNodePCAP) == sizeof(CGenNode), "sizeof(CGenNodePCAP) != sizeof(CGenNode)" ); #endif /* __TREX_STREAM_NODE_H__ */ + |