summaryrefslogtreecommitdiffstats
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
parentcf72305f2f5632f977d2596db4c912100b438e1f (diff)
RX features phase 2 - ARP and ICMP self response
Signed-off-by: imarom <imarom@cisco.com>
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py9
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py93
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py37
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py35
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py8
-rwxr-xr-xsrc/bp_sim.h1
-rw-r--r--src/common/Network/Packet/Arp.h43
-rwxr-xr-xsrc/common/Network/Packet/EthernetHeader.h6
-rw-r--r--src/common/Network/Packet/IcmpHeader.h5
-rwxr-xr-xsrc/common/Network/Packet/MacAddress.h5
-rw-r--r--src/main_dpdk.cpp6
-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
-rwxr-xr-xsrc/trex_port_attr.h5
16 files changed, 510 insertions, 48 deletions
diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py
index b33b0447..5ea959ac 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -488,7 +488,7 @@ class TRexConsole(TRexGeneralCmd):
############# update
@verify_connected
def do_update(self, line):
- '''update speed of port(s)currently transmitting traffic\n'''
+ '''update speed of port(s) currently transmitting traffic\n'''
self.stateless_client.update_line(line)
@@ -549,6 +549,13 @@ class TRexConsole(TRexGeneralCmd):
'''Clear cached local statistics\n'''
self.stateless_client.clear_stats_line(line)
+ @verify_connected
+ def do_service (self, line):
+ '''Sets port(s) service mode state'''
+ self.stateless_client.service_line(line)
+
+ def help_service (self, line):
+ self.do_service("-h")
def help_clear(self):
self.do_clear("-h")
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
index cc20e088..fd41491e 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
@@ -878,6 +878,15 @@ class STLClient(object):
return rc
+ def __set_service_mode (self, port_id_list, enabled):
+ port_id_list = self.__ports(port_id_list)
+ rc = RC()
+
+ for port_id in port_id_list:
+ rc.add(self.ports[port_id].set_service_mode(enabled))
+
+ return rc
+
# connect to server
def __connect(self):
@@ -1387,6 +1396,12 @@ class STLClient(object):
if port_obj.is_acquired() and port_obj.get_dst_addr()['ipv4'] is not None]
+ def get_service_enabled_ports(self):
+ return [port_id
+ for port_id, port_obj in self.ports.items()
+ if port_obj.is_acquired() and port_obj.is_service_mode_on()]
+
+
# get paused ports
def get_paused_ports (self, owned = True):
if owned:
@@ -1854,9 +1869,7 @@ class STLClient(object):
raise STLError("pkt_size should be a value between 64 and 9216: '{0}'".format(pkt_size))
validate_type('count', count, int)
-
-
-
+
self.logger.pre_cmd("Pinging {0} from port {1} with {2} bytes of data:".format(dst_ipv4,
src_port,
pkt_size))
@@ -2164,7 +2177,10 @@ class STLClient(object):
unresolved_ports = [port_id for port_id in ports if not self.ports[port_id].is_resolved()]
if unresolved_ports and not force:
raise STLError("Port(s) {0} have unresolved destination addresses - please resolve them or specify 'force'".format(unresolved_ports))
-
+
+ if self.get_service_enabled_ports() and not force:
+ raise STLError("Port(s) {0} are under service mode - please disable service mode or specify 'force'".format(self.get_service_enabled_ports()))
+
@__api_check(True)
def start (self,
@@ -2827,7 +2843,7 @@ class STLClient(object):
validate_type('led_on', led_on, (bool, type(None)))
validate_type('flow_ctrl', flow_ctrl, (int, type(None)))
validate_choice('rxf', rxf, ['hw', 'all'])
-
+
# common attributes for all ports
cmn_attr_dict = {}
@@ -2880,7 +2896,35 @@ class STLClient(object):
self.resolve(ports = resolve_ports)
+
+ @__api_check(True)
+ def set_service_mode (self, ports = None, enabled = True):
+ """
+ Set service mode for port(s)
+ In service mode ports will respond to ARP, PING and etc.
+
+ :parameters:
+ ports - for which ports to configure service mode on/off
+ enabled - True for activating service mode, False for disabling
+ :raises:
+ + :exe:'STLError'
+
+ """
+ # by default take all acquired ports
+ ports = ports if ports is not None else self.get_acquired_ports()
+ ports = self._validate_port_list(ports)
+
+ if enabled:
+ self.logger.pre_cmd('Enabling service mode on port(s) {0}:'.format(ports))
+ else:
+ self.logger.pre_cmd('Disabling service mode on port(s) {0}:'.format(ports))
+
+ rc = self.__set_service_mode(ports, enabled)
+ self.logger.post_cmd(rc)
+ if not rc:
+ raise STLError(rc)
+
@__api_check(True)
def resolve (self, ports = None, retries = 0):
@@ -3078,7 +3122,7 @@ class STLClient(object):
try:
rc = f(*args)
except STLError as e:
- client.logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold'))
+ client.logger.log("Action has failed with the following error:\n" + format_text(e.brief() + "\n", 'bold'))
return RC_ERR(e.brief())
# if got true - print time
@@ -3697,18 +3741,12 @@ class STLClient(object):
self.set_rx_sniffer_line.__doc__,
parsing_opts.PORT_LIST_WITH_ALL,
parsing_opts.OUTPUT_FILENAME,
- parsing_opts.LIMIT,
- parsing_opts.ALL_FILES)
+ parsing_opts.LIMIT)
opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True)
if not opts:
return opts
- rxf = 'all' if opts.all else None
-
- if rxf:
- self.set_port_attr(opts.ports, rxf = rxf)
-
self.set_rx_sniffer(opts.ports, opts.output_filename, opts.limit)
return RC_OK()
@@ -3840,10 +3878,37 @@ class STLClient(object):
return "{0}(read-only)>".format(prefix)
elif self.is_all_ports_acquired():
- return "{0}>".format(prefix)
+ p = prefix
+
+ if self.get_service_enabled_ports():
+ if self.get_service_enabled_ports() == self.get_acquired_ports():
+ p += '(service)'
+ else:
+ p += '(service: {0})'.format(self.get_service_enabled_ports())
+
+ return "{0}>".format(p)
else:
return "{0} {1}>".format(prefix, self.get_acquired_ports())
+ @__console
+ def service_line (self, line):
+ '''Configures port for service mode.
+ In service mode ports will reply to ARP, PING
+ and etc.
+ '''
+
+ parser = parsing_opts.gen_parser(self,
+ "service",
+ self.service_line.__doc__,
+ parsing_opts.PORT_LIST_WITH_ALL,
+ parsing_opts.SERVICE_OFF)
+
+ opts = parser.parse_args(line.split())
+ if not opts:
+ return opts
+
+ self.set_service_mode(ports = opts.ports, enabled = opts.enabled)
+
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
index 389a942b..4ac31fba 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
@@ -489,6 +489,9 @@ class Port(object):
@owned
def set_rx_sniffer (self, pcap_filename, limit):
+ if not self.is_service_mode_on():
+ return self.err('port service mode must be enabled for performing RX capturing')
+
params = {"handler": self.handler,
"port_id": self.port_id,
"type": "capture",
@@ -529,7 +532,8 @@ class Port(object):
if rc.bad():
return self.err(rc.err())
- return self.ok()
+ # instead of updating manualy - let's sync with the server
+ return self.sync()
@@ -684,6 +688,9 @@ class Port(object):
json_attr['ipv4'] = {'addr': kwargs.get('ipv4')}
if kwargs.get('dest') is not None:
+ if not self.is_service_mode_on():
+ return self.err('setting destination requires port to be in service mode')
+
json_attr['dest'] = {'addr': kwargs.get('dest')}
@@ -698,6 +705,26 @@ class Port(object):
# update the dictionary from the server explicitly
return self.sync()
+
+ @owned
+ def set_service_mode (self, enabled):
+ rc = self.set_attr(rx_filter_mode = 'all' if enabled else 'hw')
+ if not rc:
+ return rc
+
+ if not enabled:
+ rc = self.remove_rx_queue()
+ if not rc:
+ return rc
+
+ rc = self.remove_rx_sniffer()
+ if not rc:
+ return rc
+
+ return self.ok()
+
+ def is_service_mode_on (self):
+ return self.get_rx_filter_mode() == 'all'
@writeable
def push_remote (self, pcap_filename, ipg_usec, speedup, count, duration, is_dual, slave_handler):
@@ -877,6 +904,8 @@ class Port(object):
return {'mac': src_mac, 'ipv4': src_ipv4}
+ def get_rx_filter_mode (self):
+ return self.__attr['rx_filter_mode']
def get_dst_addr (self):
dest = self.__attr['dest']
@@ -904,10 +933,16 @@ class Port(object):
@writeable
def arp_resolve (self, retries):
+ if not self.is_service_mode_on():
+ return self.err('port service mode must be enabled for performing ARP resolution')
+
return ARPResolver(self).resolve(retries)
@writeable
def ping (self, ping_ipv4, pkt_size):
+ if not self.is_service_mode_on():
+ return self.err('port service mode must be enabled for performing ping')
+
return PingResolver(self, ping_ipv4, pkt_size).resolve()
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py
index 3754e608..e0fc1724 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py
@@ -46,11 +46,6 @@ class Resolver(object):
# add the stream(s)
self.port.add_streams(self.generate_request())
-
- rc = self.port.set_attr(rx_filter_mode = 'all')
- if not rc:
- return rc
-
rc = self.port.set_rx_queue(size = 100)
if not rc:
return rc
@@ -59,7 +54,6 @@ class Resolver(object):
finally:
# best effort restore
- self.port.set_attr(rx_filter_mode = 'hw')
self.port.remove_rx_queue()
self.port.remove_all_streams()
@@ -202,19 +196,13 @@ class PingResolver(Resolver):
if self.dst['mac'] is None:
return self.port.err('Ping - port has an unresolved destination, cannot determine next hop MAC address')
- if self.ping_ip == self.src['ipv4']:
- return self.port.err('Ping - cannot ping own IP')
-
return self.port.ok()
# return a list of streams for request
def generate_request (self):
- src = self.port.get_src_addr()
- dst = self.port.get_dst_addr()
-
- base_pkt = Ether(dst = dst['mac'])/IP(src = src['ipv4'], dst = self.ping_ip)/ICMP(type = 8)
+ base_pkt = Ether(dst = self.dst['mac'])/IP(src = self.src['ipv4'], dst = self.ping_ip)/ICMP(type = 8)
pad = max(0, self.pkt_size - len(base_pkt))
base_pkt = base_pkt / (pad * 'x')
@@ -222,6 +210,8 @@ class PingResolver(Resolver):
#base_pkt.show2()
s1 = STLStream( packet = STLPktBuilder(pkt = base_pkt), mode = STLTXSingleBurst(total_pkts = 1) )
+ self.base_pkt = base_pkt
+
return [s1]
# return None for more packets otherwise RC object
@@ -230,23 +220,32 @@ class PingResolver(Resolver):
if not 'ICMP' in scapy_pkt:
return None
- #scapy_pkt.show2()
ip = scapy_pkt['IP']
-
+ if ip.dst != self.src['ipv4']:
+ return None
+
icmp = scapy_pkt['ICMP']
dt = pkt['ts'] - self.start_ts
+ # echo reply
if icmp.type == 0:
- # echo reply
+ # check seq
+ if icmp.seq != self.base_pkt['ICMP'].seq:
+ return None
return self.port.ok('Reply from {0}: bytes={1}, time={2:.2f}ms, TTL={3}'.format(ip.src, len(pkt['binary']), dt * 1000, ip.ttl))
# unreachable
elif icmp.type == 3:
+ # check seq
+ if icmp.payload.seq != self.base_pkt['ICMP'].seq:
+ return None
return self.port.ok('Reply from {0}: Destination host unreachable'.format(icmp.src))
+
else:
- scapy_pkt.show2()
- return self.port.err('unknown ICMP reply')
+ # skip any other types
+ #scapy_pkt.show2()
+ return None
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
index 7ae22e89..66a17a03 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
@@ -60,6 +60,8 @@ PING_IPV4 = 40
PING_COUNT = 41
PKT_SIZE = 42
+SERVICE_OFF = 43
+
GLOBAL_STATS = 50
PORT_STATS = 51
PORT_STATUS = 52
@@ -575,6 +577,12 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'default': None,
'help': "Core mask - only cores responding to the bit mask will be active"}),
+ SERVICE_OFF: ArgumentPack(['--off'],
+ {'action': 'store_false',
+ 'dest': 'enabled',
+ 'default': True,
+ 'help': 'Deactivates services on port(s)'}),
+
# advanced options
PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST,
ALL_PORTS],
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 914a26d9..454f5f19 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -643,7 +643,6 @@ public:
CMacAddrCfg (){
memset(u.m_data,0,sizeof(u.m_data));
u.m_mac.dest[3]=1;
- u.m_mac.src[3]=1;
}
union {
mac_align_t m_mac;
diff --git a/src/common/Network/Packet/Arp.h b/src/common/Network/Packet/Arp.h
index a16605bd..e23ff139 100644
--- a/src/common/Network/Packet/Arp.h
+++ b/src/common/Network/Packet/Arp.h
@@ -20,8 +20,7 @@ limitations under the License.
#pragma pack(push, 1)
class ArpHdr {
public:
- enum arp_hdr_enum_e {
- ARP_HDR_HRD_ETHER = 1,
+ enum arp_hdr_op_e {
ARP_HDR_OP_REQUEST = 1, /* request to resolve address */
ARP_HDR_OP_REPLY = 2, /* response to previous request */
ARP_HDR_OP_REVREQUEST = 3, /* request proto addr given hardware */
@@ -30,6 +29,46 @@ class ArpHdr {
ARP_HDR_OP_INVREPLY = 6, /* response identifying peer */
};
+ enum arp_hdr_hrd_e {
+ ARP_HDR_HRD_ETHER = 1,
+ };
+
+ enum arp_hdr_proto_e {
+ ARP_HDR_PROTO_IPV4 = 0x800,
+ };
+
+ void setOp(uint16_t op) {
+ m_arp_op = PKT_HTONS(op);
+ }
+
+ uint16_t getOp() const {
+ return PKT_NTOHS(m_arp_op);
+ }
+
+ uint16_t getHrdType() const {
+ return PKT_NTOHS(m_arp_hrd);
+ }
+
+ uint16_t getProtocolType() const {
+ return PKT_NTOHS(m_arp_pro);
+ }
+
+ uint32_t getSip() const {
+ return PKT_NTOHL(m_arp_sip);
+ }
+
+ void setSip(uint32_t sip) {
+ m_arp_sip = PKT_HTONL(sip);
+ }
+
+ uint32_t getTip() const {
+ return PKT_NTOHL(m_arp_tip);
+ }
+
+ void setTip(uint32_t tip) {
+ m_arp_tip = PKT_HTONL(tip);
+ }
+
public:
uint16_t m_arp_hrd; /* format of hardware address */
uint16_t m_arp_pro; /* format of protocol address */
diff --git a/src/common/Network/Packet/EthernetHeader.h b/src/common/Network/Packet/EthernetHeader.h
index c9dcdbe2..002d6c25 100755
--- a/src/common/Network/Packet/EthernetHeader.h
+++ b/src/common/Network/Packet/EthernetHeader.h
@@ -62,8 +62,10 @@ public:
inline EthernetHeader(uint8_t* packet);
inline uint8_t* getPointer (){return (uint8_t*)this;}
- static inline uint32_t getSize (){return (uint32_t)sizeof(EthernetHeader);}
-
+ inline uint32_t getSize () {
+ return ( (getNextProtocol() == Protocol::VLAN) ? 18 : 14);
+ }
+
// Get dest MAC pointer
MacAddress *getDestMacP() { return &myDestination; }
diff --git a/src/common/Network/Packet/IcmpHeader.h b/src/common/Network/Packet/IcmpHeader.h
index 99d89329..4bc102e3 100644
--- a/src/common/Network/Packet/IcmpHeader.h
+++ b/src/common/Network/Packet/IcmpHeader.h
@@ -24,6 +24,11 @@ class ICMPHeader
{
public:
+ enum {
+ TYPE_ECHO_REPLY = 0,
+ TYPE_ECHO_REQUEST = 8,
+ };
+
ICMPHeader()
{
setCode(0);
diff --git a/src/common/Network/Packet/MacAddress.h b/src/common/Network/Packet/MacAddress.h
index 5dc4a9ea..9bd3eae1 100755
--- a/src/common/Network/Packet/MacAddress.h
+++ b/src/common/Network/Packet/MacAddress.h
@@ -137,6 +137,11 @@ public:
return true;
}
+ MacAddress& operator = (const uint8_t *rhs) {
+ memcpy(data, rhs, ETHER_ADDR_LEN);
+ return (*this);
+ }
+
uint8_t* GetBuffer()
{
return data;
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index f92d18c4..a01d57a2 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -3618,9 +3618,7 @@ int CGlobalTRex::ixgbe_start(void){
if (! get_is_stateless()) {
ixgbe_configure_mg();
- } else {
- rx_sl_configure();
- }
+ }
/* core 0 - control
@@ -3759,6 +3757,8 @@ bool CGlobalTRex::Create(){
cfg.m_publisher = &m_zmq_publisher;
m_trex_stateless = new TrexStateless(cfg);
+
+ rx_sl_configure();
}
return (true);
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;
diff --git a/src/trex_port_attr.h b/src/trex_port_attr.h
index 3cb9beff..ae397430 100755
--- a/src/trex_port_attr.h
+++ b/src/trex_port_attr.h
@@ -134,7 +134,7 @@ public:
virtual void get_description(std::string &description) { description = intf_info_st.description; }
virtual void get_supported_speeds(supp_speeds_t &supp_speeds) = 0;
- uint32_t get_src_ipv4() {return m_src_ipv4;}
+ uint32_t get_src_ipv4() const {return m_src_ipv4;}
DestAttr & get_dest() {return m_dest;}
const uint8_t *get_src_mac() const;
@@ -161,6 +161,9 @@ public:
/* dump object status to JSON */
void to_json(Json::Value &output);
+ uint8_t get_port_id() const {
+ return m_port_id;
+ }
protected: