Trex packet capture ds 66/5266/1
authorimarom <[email protected]>
Sun, 22 Jan 2017 14:09:46 +0000 (16:09 +0200)
committerimarom <[email protected]>
Sun, 22 Jan 2017 14:09:46 +0000 (16:09 +0200)
Signed-off-by: imarom <[email protected]>
src/stateless/common/trex_stateless_pkt.cpp [new file with mode: 0644]
src/stateless/common/trex_stateless_pkt.h [new file with mode: 0644]

diff --git a/src/stateless/common/trex_stateless_pkt.cpp b/src/stateless/common/trex_stateless_pkt.cpp
new file mode 100644 (file)
index 0000000..f7d47ec
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+  Itay Marom
+  Cisco Systems, Inc.
+*/
+
+/*
+  Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+#include "trex_stateless_pkt.h"
+#include <assert.h>
+
+
+/**
+ * copy MBUF to a flat buffer
+ * 
+ * @author imarom (12/20/2016)
+ * 
+ * @param dest - buffer with at least rte_pktmbuf_pkt_len(m) 
+ *               bytes
+ * @param m - MBUF to copy 
+ * 
+ * @return uint8_t* 
+ */
+void copy_mbuf(uint8_t *dest, const rte_mbuf_t *m) {
+    
+    int index = 0;
+    for (const rte_mbuf_t *it = m; it != NULL; it = it->next) {
+        const uint8_t *src = rte_pktmbuf_mtod(it, const uint8_t *);
+        memcpy(dest + index, src, it->data_len);
+        index += it->data_len;
+    }
+}
+
+/**************************************
+ * TRex packet
+ * 
+ *************************************/
+TrexPkt::TrexPkt(const rte_mbuf_t *m, int port, origin_e origin, uint64_t index) {
+
+    /* allocate buffer */
+    m_size = m->pkt_len;
+    m_raw = new uint8_t[m_size];
+
+    /* copy data */
+    copy_mbuf(m_raw, m);
+
+    /* generate a packet timestamp */
+    m_timestamp = now_sec();
+    
+    m_port   = port;
+    m_origin = origin;
+    m_index  = index;
+}
+
+TrexPkt::TrexPkt(const TrexPkt &other) {
+    m_size = other.m_size;
+    memcpy(m_raw, other.m_raw, m_size);
+    
+    m_timestamp = other.m_timestamp;
+    
+    m_port   = other.m_port;
+    m_origin = other.m_origin;
+    m_index  = other.m_index;
+}
+
+TrexPktBuffer::TrexPktBuffer(uint64_t size, mode_e mode) {
+    m_mode             = mode;
+    m_buffer           = nullptr;
+    m_head             = 0;
+    m_tail             = 0;
+    m_bytes            = 0;
+    m_size             = (size + 1); // for the empty/full difference 1 slot reserved
+    
+    /* generate queue */
+    m_buffer = new const TrexPkt*[m_size](); // zeroed
+}
+
+TrexPktBuffer::~TrexPktBuffer() {
+    assert(m_buffer);
+
+    while (!is_empty()) {
+        const TrexPkt *pkt = pop();
+        delete pkt;
+    }
+    delete [] m_buffer;
+}
+
+/**
+ * packet will be copied to an internal object
+ */
+void 
+TrexPktBuffer::push(const rte_mbuf_t *m, int port, TrexPkt::origin_e origin, uint64_t pkt_index) {
+    
+    /* if full - decide by the policy */
+    if (is_full()) {
+        if (m_mode == MODE_DROP_HEAD) {
+            delete pop();
+        } else {
+            /* drop the tail (current packet) */
+            return;
+        }
+    }
+
+    /* push packet */
+    m_buffer[m_head] = new TrexPkt(m, port, origin, pkt_index);
+    m_bytes += m_buffer[m_head]->get_size();
+        
+    m_head = next(m_head);
+    
+}
+
+/**
+ * packet will be handled internally 
+ */
+void 
+TrexPktBuffer::push(const TrexPkt *pkt) {
+    /* if full - decide by the policy */
+    if (is_full()) {
+        if (m_mode == MODE_DROP_HEAD) {
+            delete pop();
+        } else {
+            /* drop the tail (current packet) */
+            delete pkt;
+            return;
+        }
+    }
+
+    /* push packet */
+    m_buffer[m_head] = pkt;
+    m_head = next(m_head);
+}
+
+const TrexPkt *
+TrexPktBuffer::pop() {
+    assert(!is_empty());
+    
+    const TrexPkt *pkt = m_buffer[m_tail];
+    m_tail = next(m_tail);
+    
+    m_bytes -= pkt->get_size();
+    
+    return pkt;
+}
+
+uint32_t
+TrexPktBuffer::get_element_count() const {
+    if (m_head >= m_tail) {
+        return (m_head - m_tail);
+    } else {
+        return ( get_capacity() - (m_tail - m_head - 1) );
+    }
+}
+
+Json::Value
+TrexPktBuffer::to_json() const {
+
+    Json::Value output = Json::arrayValue;
+
+    int tmp = m_tail;
+    while (tmp != m_head) {
+        const TrexPkt *pkt = m_buffer[tmp];
+        output.append(pkt->to_json());
+        tmp = next(tmp);
+    }
+
+    return output;
+}
+
+
diff --git a/src/stateless/common/trex_stateless_pkt.h b/src/stateless/common/trex_stateless_pkt.h
new file mode 100644 (file)
index 0000000..1b6bd2f
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+  Itay Marom
+  Cisco Systems, Inc.
+*/
+
+/*
+  Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+#ifndef __TREX_STATELESS_PKT_H__
+#define __TREX_STATELESS_PKT_H__
+
+#include <stdint.h>
+#include <json/json.h>
+#include "mbuf.h"
+#include "common/base64.h"
+#include "os_time.h"
+
+
+/**
+ * copies MBUF to a flat buffer
+ * 
+ * @author imarom (1/1/2017)
+ * 
+ * @param dest 
+ * @param m 
+ */
+void copy_mbuf(uint8_t *dest, const rte_mbuf_t *m);
+
+/**                
+ * describes a single saved packet
+ * 
+ */
+class TrexPkt {
+public:
+
+    enum origin_e {
+        ORIGIN_NONE = 1,
+        ORIGIN_TX,
+        ORIGIN_RX
+    };
+    
+    TrexPkt(const rte_mbuf_t *m, int port = -1, origin_e origin = ORIGIN_NONE, uint64_t index = 0);
+    TrexPkt(const TrexPkt &other);
+    void set_index(uint64_t index) {
+        m_index = index;
+    }
+    
+    /* slow path and also RVO - pass by value is ok */
+    Json::Value to_json() const {
+        Json::Value output;
+        output["ts"]      = m_timestamp;
+        output["binary"]  = base64_encode(m_raw, m_size);
+        output["port"]    = m_port;
+        output["index"]   = Json::UInt64(m_index);
+        
+        switch (m_origin) {
+        case ORIGIN_TX:
+            output["origin"]  = "TX";
+            break;
+        case ORIGIN_RX:
+            output["origin"]  = "RX";
+            break;
+        default:
+            output["origin"]  = "NONE";
+            break;
+        }
+        
+        return output;
+    }
+
+    ~TrexPkt() {
+        if (m_raw) {
+            delete [] m_raw;
+        }
+    }
+
+    origin_e get_origin() const {
+        return m_origin;
+    }
+    
+    int get_port() const {
+        return m_port;
+    }
+    uint16_t get_size() const {
+        return m_size;   
+    }
+    
+    dsec_t get_ts() const {
+        return m_timestamp;
+    }
+    
+private:
+
+    uint8_t   *m_raw;
+    uint16_t   m_size;
+    dsec_t     m_timestamp;
+    origin_e   m_origin;
+    int        m_port;
+    uint64_t   m_index;
+};
+
+
+class TrexPktBuffer {
+public:
+
+    /**
+     * two modes for operations: 
+     *  
+     * MODE_DROP_HEAD - when the buffer is full, packets will be 
+     * dropped from the head (the oldest packet) 
+     *  
+     * MODE_DROP_TAIL - when the buffer is full, packets will be 
+     * dropped from the tail (the current packet) 
+     */
+    enum mode_e {
+        MODE_DROP_HEAD = 1,
+        MODE_DROP_TAIL = 2,
+    };
+    
+    TrexPktBuffer(uint64_t size, mode_e mode = MODE_DROP_TAIL);
+    ~TrexPktBuffer();
+
+    /**
+     * push a packet to the buffer
+     * 
+     */
+    void push(const rte_mbuf_t *m, int port = -1, TrexPkt::origin_e origin = TrexPkt::ORIGIN_NONE, uint64_t pkt_index = 0);
+    void push(const TrexPkt *pkt);
+    
+    /**
+     * pops a packet from the buffer
+     * usually for internal usage
+     */
+    const TrexPkt * pop();
+    
+    /**
+     * generate a JSON output of the queue
+     * 
+     */
+    Json::Value to_json() const;
+
+
+    bool is_empty() const {
+        return (m_head == m_tail);
+    }
+
+    bool is_full() const {
+        return ( next(m_head) == m_tail);
+    }
+
+    /**
+     * return the total amount of space possible
+     */
+    uint32_t get_capacity() const {
+        /* one slot is used for diff between full/empty */
+        return (m_size - 1);
+    }
+    
+    mode_e get_mode() const {
+        return m_mode;
+    }
+    
+    /**
+     * returns how many elements are in the queue
+     */
+    uint32_t get_element_count() const;
+    
+    uint32_t get_bytes() const {
+        return m_bytes; 
+    }
+    
+private:
+    int next(int v) const {
+        return ( (v + 1) % m_size );
+    }
+
+    mode_e          m_mode;
+    int             m_head;
+    int             m_tail;
+    int             m_size;
+    uint32_t        m_bytes;
+    const TrexPkt **m_buffer;
+};
+
+
+#endif /* __TREX_STATELESS_PKT_H__*/