summaryrefslogtreecommitdiffstats
path: root/src/stateless/dp
diff options
context:
space:
mode:
authorHanoh Haim <hhaim@cisco.com>2016-05-10 17:49:25 +0300
committerHanoh Haim <hhaim@cisco.com>2016-05-10 17:49:25 +0300
commit2d37b9f98020a4458aaad1f3fd05ca5e408213e0 (patch)
tree3a8cd16eb748711b72df37c6f7eea4842d73290a /src/stateless/dp
parent996f2451dba01f534420418eaac2856510682757 (diff)
parent63bf6aba10075a03fe6609369c1c7008afb85ba7 (diff)
merge from master
Diffstat (limited to 'src/stateless/dp')
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp192
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.h29
-rw-r--r--src/stateless/dp/trex_stream_node.h172
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__ */
+