summaryrefslogtreecommitdiffstats
path: root/src/stateless
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2016-12-06 15:29:55 +0200
committerimarom <imarom@cisco.com>2016-12-06 15:31:28 +0200
commit0074ceeed2aa9ecafbbd8a71dc42d4bee1b34ffb (patch)
tree005a24d1465b0fc18825770367e39ea94ede15b9 /src/stateless
parentcf72305f2f5632f977d2596db4c912100b438e1f (diff)
RX features phase 2 - ARP and ICMP self response
Signed-off-by: imarom <imarom@cisco.com>
Diffstat (limited to 'src/stateless')
-rw-r--r--src/stateless/cp/trex_exception.h5
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.cpp4
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.cpp266
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.h30
4 files changed, 300 insertions, 5 deletions
diff --git a/src/stateless/cp/trex_exception.h b/src/stateless/cp/trex_exception.h
index c12732ef..ffc2f734 100644
--- a/src/stateless/cp/trex_exception.h
+++ b/src/stateless/cp/trex_exception.h
@@ -55,7 +55,10 @@ class TrexException : public std::runtime_error
T_FLOW_STAT_NO_FREE_HW_ID,
T_FLOW_STAT_RX_CORE_START_FAIL,
T_FLOW_STAT_BAD_HW_ID,
- T_INVALID
+
+ T_RX_PKT_PARSE_ERR,
+
+ T_INVALID,
};
TrexException() : std::runtime_error(""), m_type(T_INVALID) {
diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp
index f2061bf7..9898e8b9 100644
--- a/src/stateless/rx/trex_stateless_rx_core.cpp
+++ b/src/stateless/rx/trex_stateless_rx_core.cpp
@@ -84,11 +84,13 @@ void CRxCoreStateless::create(const CRxSlCfg &cfg) {
/* create per port manager */
for (int i = 0; i < m_max_ports; i++) {
+ const TRexPortAttr *port_attr = get_stateless_obj()->get_platform_api()->getPortAttrObj(i);
m_rx_port_mngr[i].create(cfg.m_ports[i],
m_rfc2544,
&m_err_cntrs,
&m_cpu_dp_u,
- cfg.m_num_crc_fix_bytes);
+ cfg.m_num_crc_fix_bytes,
+ port_attr);
}
}
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
index afc6827c..af312700 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
@@ -22,6 +22,7 @@
#include "trex_stateless_rx_port_mngr.h"
#include "common/captureFile.h"
#include "trex_stateless_rx_core.h"
+#include "common/Network/Packet/Arp.h"
/**************************************
* latency RX feature
@@ -400,6 +401,259 @@ RXPacketRecorder::to_json() const {
return output;
}
+
+/**************************************
+ * RX feature server (ARP, ICMP) and etc.
+ *
+ *************************************/
+
+class RXPktParser {
+public:
+ RXPktParser(const rte_mbuf_t *m) {
+
+ m_mbuf = m;
+
+ /* start point */
+ m_current = rte_pktmbuf_mtod(m, uint8_t *);;
+ m_size_left = rte_pktmbuf_pkt_len(m);
+
+ m_ether = NULL;
+ m_arp = NULL;
+ m_ipv4 = NULL;
+ m_icmp = NULL;
+ m_vlan_tag = 0;
+
+ /* ethernet */
+ m_ether = (EthernetHeader *)parse_bytes(14);
+
+ uint16_t next_proto;
+ if (m_ether->getNextProtocol() == EthernetHeader::Protocol::VLAN) {
+ parse_bytes(4);
+ m_vlan_tag = m_ether->getVlanTag();
+ next_proto = m_ether->getVlanProtocol();
+ } else {
+ next_proto = m_ether->getNextProtocol();
+ }
+
+ /**
+ * support only for ARP or IPv4 based protocols
+ */
+ switch (next_proto) {
+ case EthernetHeader::Protocol::ARP:
+ parse_arp();
+ return;
+
+ case EthernetHeader::Protocol::IP:
+ parse_ipv4();
+ return;
+
+ default:
+ return;
+ }
+
+ }
+
+ const rte_mbuf_t *m_mbuf;
+ EthernetHeader *m_ether;
+ ArpHdr *m_arp;
+ IPHeader *m_ipv4;
+ ICMPHeader *m_icmp;
+ uint16_t m_vlan_tag;
+
+protected:
+
+ const uint8_t *parse_bytes(uint32_t size) {
+ if (m_size_left < size) {
+ parse_err();
+ }
+
+ const uint8_t *p = m_current;
+ m_current += size;
+ m_size_left -= size;
+
+ return p;
+ }
+
+ void parse_arp() {
+ m_arp = (ArpHdr *)parse_bytes(sizeof(ArpHdr));
+ }
+
+ void parse_ipv4() {
+ m_ipv4 = (IPHeader *)parse_bytes(IPHeader::DefaultSize);
+
+ /* advance over IP options if exists */
+ parse_bytes(m_ipv4->getOptionLen());
+
+ switch (m_ipv4->getNextProtocol()) {
+ case IPHeader::Protocol::ICMP:
+ parse_icmp();
+ return;
+
+ default:
+ return;
+ }
+ }
+
+ void parse_icmp() {
+ m_icmp = (ICMPHeader *)parse_bytes(sizeof(ICMPHeader));
+ }
+
+ void parse_err() {
+ throw TrexException(TrexException::T_RX_PKT_PARSE_ERR);
+ }
+
+ const uint8_t *m_current;
+ uint16_t m_size_left;
+};
+
+RXServer::RXServer() {
+ m_port_attr = NULL;
+ m_io = NULL;
+ m_port_id = 255;
+}
+
+void
+RXServer::create(const TRexPortAttr *port_attr, CPortLatencyHWBase *io) {
+ m_port_attr = port_attr;
+ m_io = io;
+ m_port_id = port_attr->get_port_id();
+}
+
+
+void
+RXServer::handle_pkt(const rte_mbuf_t *m) {
+
+ RXPktParser parser(m);
+
+ if (parser.m_icmp) {
+ handle_icmp(parser);
+ } else if (parser.m_arp) {
+ handle_arp(parser);
+ } else {
+ return;
+ }
+
+}
+void
+RXServer::handle_icmp(RXPktParser &parser) {
+
+ /* maybe not for us... */
+ if (parser.m_ipv4->getDestIp() != m_port_attr->get_src_ipv4()) {
+ return;
+ }
+
+ /* we handle only echo request */
+ if (parser.m_icmp->getType() != ICMPHeader::TYPE_ECHO_REQUEST) {
+ return;
+ }
+
+ /* duplicate the MBUF */
+ rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf);
+ if (!response) {
+ return;
+ }
+
+ /* reparse the cloned packet */
+ RXPktParser response_parser(response);
+
+ /* swap MAC */
+ MacAddress tmp = response_parser.m_ether->mySource;
+ response_parser.m_ether->mySource = response_parser.m_ether->myDestination;
+ response_parser.m_ether->myDestination = tmp;
+
+ /* swap IP */
+ std::swap(response_parser.m_ipv4->mySource, response_parser.m_ipv4->myDestination);
+
+ /* new packet - new TTL */
+ response_parser.m_ipv4->setTimeToLive(128);
+ response_parser.m_ipv4->updateCheckSum();
+
+ /* update type and fix checksum */
+ response_parser.m_icmp->setType(ICMPHeader::TYPE_ECHO_REPLY);
+ response_parser.m_icmp->updateCheckSum(response_parser.m_ipv4->getTotalLength() - response_parser.m_ipv4->getHeaderLength());
+
+ /* send */
+ m_io->tx(response);
+}
+
+void
+RXServer::handle_arp(RXPktParser &parser) {
+
+ /* only ethernet format supported */
+ if (parser.m_arp->getHrdType() != ArpHdr::ARP_HDR_HRD_ETHER) {
+ return;
+ }
+
+ /* IPV4 only */
+ if (parser.m_arp->getProtocolType() != ArpHdr::ARP_HDR_PROTO_IPV4) {
+ return;
+ }
+
+ /* support only for ARP request */
+ if (parser.m_arp->getOp() != ArpHdr::ARP_HDR_OP_REQUEST) {
+ return;
+ }
+
+ /* are we the target ? if not - go home */
+ if (parser.m_arp->getTip() != m_port_attr->get_src_ipv4()) {
+ return;
+ }
+
+ /* duplicate the MBUF */
+ rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf);
+ if (!response) {
+ return;
+ }
+
+ /* reparse the cloned packet */
+ RXPktParser response_parser(response);
+
+ /* reply */
+ response_parser.m_arp->setOp(ArpHdr::ARP_HDR_OP_REPLY);
+
+ /* fix the MAC addresses */
+ response_parser.m_ether->mySource = m_port_attr->get_src_mac();
+ response_parser.m_ether->myDestination = parser.m_ether->mySource;
+
+ /* fill up the fields */
+
+ /* src */
+ response_parser.m_arp->m_arp_sha = m_port_attr->get_src_mac();
+ response_parser.m_arp->setSip(m_port_attr->get_src_ipv4());
+
+ /* dst */
+ response_parser.m_arp->m_arp_tha = parser.m_arp->m_arp_sha;
+ response_parser.m_arp->m_arp_tip = parser.m_arp->m_arp_sip;
+
+ /* send */
+ m_io->tx(response);
+
+}
+
+rte_mbuf_t *
+RXServer::duplicate_mbuf(const rte_mbuf_t *m) {
+ /* RX packets should always be one segment */
+ assert(m->nb_segs == 1);
+
+ /* allocate */
+ rte_mbuf_t *clone_mbuf = CGlobalInfo::pktmbuf_alloc_by_port(m_port_id, rte_pktmbuf_pkt_len(m));
+ if (!clone_mbuf) {
+ return NULL;
+ }
+
+ /* append data */
+ uint8_t *dest = (uint8_t *)rte_pktmbuf_append(clone_mbuf, rte_pktmbuf_pkt_len(m));
+ if (!dest) {
+ return NULL;
+ }
+
+ /* copy data */
+ const uint8_t *src = rte_pktmbuf_mtod(m, const uint8_t *);
+ memcpy(dest, src, rte_pktmbuf_pkt_len(m));
+
+ return clone_mbuf;
+}
+
/**************************************
* Port manager
*
@@ -417,13 +671,18 @@ RXPortManager::create(CPortLatencyHWBase *io,
CRFC2544Info *rfc2544,
CRxCoreErrCntrs *err_cntrs,
CCpuUtlDp *cpu_util,
- uint8_t crc_bytes_num) {
+ uint8_t crc_bytes_num,
+ const TRexPortAttr *port_attr) {
m_io = io;
m_cpu_dp_u = cpu_util;
m_num_crc_fix_bytes = crc_bytes_num;
/* init features */
m_latency.create(rfc2544, err_cntrs);
+ m_server.create(port_attr, io);
+
+ /* by default, server feature is always on */
+ set_feature(SERVER);
}
void RXPortManager::handle_pkt(const rte_mbuf_t *m) {
@@ -441,6 +700,10 @@ void RXPortManager::handle_pkt(const rte_mbuf_t *m) {
if (is_feature_set(QUEUE)) {
m_queue.handle_pkt(m);
}
+
+ if (is_feature_set(SERVER)) {
+ m_server.handle_pkt(m);
+ }
}
@@ -513,3 +776,4 @@ RXPortManager::to_json() const {
return output;
}
+
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.h b/src/stateless/rx/trex_stateless_rx_port_mngr.h
index c049cb56..12b601ea 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.h
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h
@@ -255,6 +255,28 @@ private:
};
+/**************************************
+ * RX server (ping, ARP and etc.)
+ *
+ *************************************/
+class RXPktParser;
+class RXServer {
+public:
+
+ RXServer();
+ void create(const TRexPortAttr *port_attr, CPortLatencyHWBase *io);
+ void handle_pkt(const rte_mbuf_t *m);
+
+private:
+ void handle_icmp(RXPktParser &parser);
+ void handle_arp(RXPktParser &parser);
+ rte_mbuf_t *duplicate_mbuf(const rte_mbuf_t *m);
+
+ const TRexPortAttr *m_port_attr;
+ CPortLatencyHWBase *m_io;
+ uint8_t m_port_id;
+};
+
/************************ manager ***************************/
/**
@@ -268,7 +290,8 @@ public:
NO_FEATURES = 0x0,
LATENCY = 0x1,
RECORDER = 0x2,
- QUEUE = 0x4
+ QUEUE = 0x4,
+ SERVER = 0x8
};
RXPortManager();
@@ -277,7 +300,8 @@ public:
CRFC2544Info *rfc2544,
CRxCoreErrCntrs *err_cntrs,
CCpuUtlDp *cpu_util,
- uint8_t crc_bytes_num);
+ uint8_t crc_bytes_num,
+ const TRexPortAttr *port_attr);
void clear_stats() {
m_latency.reset_stats();
@@ -403,6 +427,8 @@ private:
RXLatency m_latency;
RXPacketRecorder m_recorder;
RXQueue m_queue;
+ RXServer m_server;
+
// compensate for the fact that hardware send us packets without Ethernet CRC, and we report with it
uint8_t m_num_crc_fix_bytes;