From 02ab06b1cf8886be0a6fde5360497b4fa968d3a3 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 31 Oct 2016 11:09:56 +0200 Subject: RX software features - some new files --- src/stateless/rx/trex_stateless_rx_defs.h | 36 +++ src/stateless/rx/trex_stateless_rx_port_mngr.cpp | 83 +++++++ src/stateless/rx/trex_stateless_rx_port_mngr.h | 270 +++++++++++++++++++++++ 3 files changed, 389 insertions(+) create mode 100644 src/stateless/rx/trex_stateless_rx_defs.h create mode 100644 src/stateless/rx/trex_stateless_rx_port_mngr.cpp create mode 100644 src/stateless/rx/trex_stateless_rx_port_mngr.h diff --git a/src/stateless/rx/trex_stateless_rx_defs.h b/src/stateless/rx/trex_stateless_rx_defs.h new file mode 100644 index 00000000..9fd11c14 --- /dev/null +++ b/src/stateless/rx/trex_stateless_rx_defs.h @@ -0,0 +1,36 @@ +/* + 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_RX_DEFS_H__ +#define __TREX_STATELESS_RX_DEFS_H__ + +/** + * describes the filter type applied to the RX + * RX_FILTER_MODE_HW - only hardware filtered traffic will + * reach the RX core + * + */ +typedef enum rx_filter_mode_ { + RX_FILTER_MODE_HW, + RX_FILTER_MODE_ALL +} rx_filter_mode_e; + +#endif /* __TREX_STATELESS_RX_DEFS_H__ */ diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp new file mode 100644 index 00000000..8a0fd613 --- /dev/null +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp @@ -0,0 +1,83 @@ +/* + 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 "bp_sim.h" +#include "trex_stateless_rx_port_mngr.h" +#include "common/captureFile.h" + +RXPacketRecorder::RXPacketRecorder() { + m_writer = NULL; + m_limit = 0; + m_epoch = -1; +} + +RXPacketRecorder::~RXPacketRecorder() { + stop(); +} + +void +RXPacketRecorder::start(const std::string &pcap, uint32_t limit) { + m_writer = CCapWriterFactory::CreateWriter(LIBPCAP, (char *)pcap.c_str()); + if (m_writer == NULL) { + std::stringstream ss; + ss << "unable to create PCAP file: " << pcap; + throw TrexException(ss.str()); + } + + assert(limit > 0); + m_limit = limit; +} + +void +RXPacketRecorder::stop() { + if (m_writer) { + delete m_writer; + m_writer = NULL; + } +} + +void +RXPacketRecorder::handle_pkt(const rte_mbuf_t *m) { + if (!m_writer) { + return; + } + + dsec_t now = now_sec(); + if (m_epoch < 0) { + m_epoch = now; + } + + dsec_t dt = now - m_epoch; + + CPktNsecTimeStamp t_c(dt); + m_pkt.time_nsec = t_c.m_time_nsec; + m_pkt.time_sec = t_c.m_time_sec; + + const uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *); + m_pkt.pkt_len = m->pkt_len; + memcpy(m_pkt.raw, p, m->pkt_len); + + m_writer->write_packet(&m_pkt); + + m_limit--; + if (m_limit == 0) { + stop(); + } +} diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.h b/src/stateless/rx/trex_stateless_rx_port_mngr.h new file mode 100644 index 00000000..622dffda --- /dev/null +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h @@ -0,0 +1,270 @@ +/* + 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_RX_PORT_MNGR_H__ +#define __TREX_STATELESS_RX_PORT_MNGR_H__ + +#include +#include "common/base64.h" + +#include "common/captureFile.h" + +/** + * describes a single saved RX packet + * + */ +class RxPacket { +public: + + RxPacket(const rte_mbuf_t *m) { + /* assume single part packet */ + assert(m->nb_segs == 1); + + m_size = m->pkt_len; + const uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *); + + m_raw = (uint8_t *)malloc(m_size); + memcpy(m_raw, p, m_size); + } + + /* RVO here - no performance impact */ + const std::string to_base64_str() const { + return base64_encode(m_raw, m_size); + } + + ~RxPacket() { + if (m_raw) { + delete m_raw; + } + } + +private: + + uint8_t *m_raw; + uint16_t m_size; +}; + +/** + * a simple cyclic buffer to hold RX packets + * + */ +class RxPacketBuffer { +public: + + RxPacketBuffer(int limit) { + m_buffer = nullptr; + m_head = 0; + m_tail = 0; + m_limit = limit; + + m_buffer = new RxPacket*[limit](); // zeroed + } + + ~RxPacketBuffer() { + assert(m_buffer); + + while (!is_empty()) { + RxPacket *pkt = pop(); + delete pkt; + } + delete [] m_buffer; + } + + bool is_empty() const { + return (m_head == m_tail); + } + + bool is_full() const { + return ( next(m_head) == m_tail); + } + + int get_limit() const { + return m_limit; + } + + void push(RxPacket *pkt) { + if (is_full()) { + delete pop(); + } + m_buffer[m_head] = pkt; + m_head = next(m_head); + } + + /** + * generate a JSON output of the queue + * + */ + Json::Value to_json() { + + Json::Value output = Json::arrayValue; + + int tmp = m_tail; + while (tmp != m_head) { + RxPacket *pkt = m_buffer[tmp]; + output.append(pkt->to_base64_str()); + tmp = next(tmp); + } + + return output; + } + +private: + int next(int v) const { + return ( (v + 1) % m_limit ); + } + + /* pop in case of full queue - internal usage */ + RxPacket * pop() { + assert(!is_empty()); + RxPacket *pkt = m_buffer[m_tail]; + m_tail = next(m_tail); + return pkt; + } + + int m_head; + int m_tail; + int m_limit; + RxPacket **m_buffer; +}; + +/** + * RX packet recorder to PCAP file + * + */ +class RXPacketRecorder { +public: + RXPacketRecorder(); + ~RXPacketRecorder(); + void start(const std::string &pcap, uint32_t limit); + void stop(); + void handle_pkt(const rte_mbuf_t *m); + +private: + CFileWriterBase *m_writer; + CCapPktRaw m_pkt; + dsec_t m_epoch; + uint32_t m_limit; +}; + + +/** + * per port RX features manager + * + * @author imarom (10/30/2016) + */ +class RXPortManager { +public: + enum features_t { + LATENCY = 0x1, + RECORD = 0x2, + QUEUE = 0x4 + }; + + RXPortManager() { + m_features = 0; + m_pkt_buffer = NULL; + set_feature(LATENCY); + } + + void start_recorder(const std::string &pcap, uint32_t limit_pkts) { + m_recorder.start(pcap, limit_pkts); + set_feature(RECORD); + } + + void stop_recorder() { + m_recorder.stop(); + unset_feature(RECORD); + } + + void start_queue(uint32_t limit) { + if (m_pkt_buffer) { + delete m_pkt_buffer; + } + m_pkt_buffer = new RxPacketBuffer(limit); + set_feature(QUEUE); + } + + void stop_queue() { + if (m_pkt_buffer) { + delete m_pkt_buffer; + m_pkt_buffer = NULL; + } + unset_feature(QUEUE); + } + + RxPacketBuffer *get_pkt_buffer() { + if (!is_feature_set(QUEUE)) { + return NULL; + } + + assert(m_pkt_buffer); + + /* take the current */ + RxPacketBuffer *old_buffer = m_pkt_buffer; + + /* allocate a new buffer */ + m_pkt_buffer = new RxPacketBuffer(old_buffer->get_limit()); + + return old_buffer; + } + + void handle_pkt(const rte_mbuf_t *m) { + /* fast path */ + if (no_features_set()) { + return; + } + + if (is_feature_set(RECORD)) { + m_recorder.handle_pkt(m); + } + + if (is_feature_set(QUEUE)) { + m_pkt_buffer->push(new RxPacket(m)); + } + } + +private: + + void set_feature(features_t feature) { + m_features |= feature; + } + + void unset_feature(features_t feature) { + m_features &= (~feature); + } + + bool is_feature_set(features_t feature) { + return ( (m_features & feature) == feature ); + } + + bool no_features_set() { + return (m_features == 0); + } + + uint32_t m_features; + RXPacketRecorder m_recorder; + RxPacketBuffer *m_pkt_buffer; +}; + + + +#endif /* __TREX_STATELESS_RX_PORT_MNGR_H__ */ + -- cgit 1.2.3-korg