From d2f1c8451e2e8ffc47b208f68f9b16697d706d60 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 22 Jan 2017 16:09:46 +0200 Subject: Trex packet capture ds Signed-off-by: imarom --- src/stateless/common/trex_stateless_pkt.cpp | 182 +++++++++++++++++++++++++ src/stateless/common/trex_stateless_pkt.h | 201 ++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+) create mode 100644 src/stateless/common/trex_stateless_pkt.cpp create mode 100644 src/stateless/common/trex_stateless_pkt.h diff --git a/src/stateless/common/trex_stateless_pkt.cpp b/src/stateless/common/trex_stateless_pkt.cpp new file mode 100644 index 00000000..f7d47ec0 --- /dev/null +++ b/src/stateless/common/trex_stateless_pkt.cpp @@ -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 + + +/** + * 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 index 00000000..1b6bd2f8 --- /dev/null +++ b/src/stateless/common/trex_stateless_pkt.h @@ -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 +#include +#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__*/ -- cgit 1.2.3-korg