summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2016-12-12 19:26:24 +0200
committerimarom <imarom@cisco.com>2016-12-12 19:26:24 +0200
commit0c45815234abbb79b147b8093eb19e274ee65f52 (patch)
treea604b3865f201e1fe841bca3a10e8f86e3248186
parentaf9f439b2bf768f9168cecac2488b4c718ab783f (diff)
grat ARP
Signed-off-by: imarom <imarom@cisco.com>
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py19
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py176
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py18
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py37
-rwxr-xr-xsrc/common/Network/Packet/MacAddress.h2
-rw-r--r--src/main_dpdk.cpp25
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp4
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp13
-rw-r--r--src/stateless/cp/trex_stateless_port.h6
-rw-r--r--src/stateless/messaging/trex_stateless_messaging.cpp5
-rw-r--r--src/stateless/messaging/trex_stateless_messaging.h17
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.cpp16
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.h2
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.cpp86
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.h55
-rw-r--r--src/trex_port_attr.cpp9
-rwxr-xr-xsrc/trex_port_attr.h6
-rw-r--r--src/utl_ip.cpp20
-rw-r--r--src/utl_ip.h31
19 files changed, 407 insertions, 140 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 eb8a0443..1a97ad0c 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -330,6 +330,25 @@ class TRexConsole(TRexGeneralCmd):
self.do_portattr("-h")
@verify_connected
+ def do_source (self, line):
+ '''Configure source address for port(s)\n'''
+ self.stateless_client.set_source_addr_line(line)
+
+ def help_source (self):
+ self.do_source("-h")
+
+
+ @verify_connected
+ def do_dest (self, line):
+ '''Configure destination address for port(s)\n'''
+ self.stateless_client.set_dest_addr_line(line)
+
+ def help_dest (self):
+ self.do_dest("-h")
+
+
+
+ @verify_connected
def do_set_rx_sniffer (self, line):
'''Sets a port sniffer on RX channel as PCAP recorder'''
self.stateless_client.set_rx_sniffer_line(line)
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 fe691fb0..80daadd2 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
@@ -1843,6 +1843,74 @@ class STLClient(object):
raise STLError(rc)
+
+ @__api_check(True)
+ def set_source_addr (self, port, addr):
+ """
+ Configures a port with a source address
+
+ :parameters:
+ port - the port to set the source address
+ addr - source address. currently only IPv4 is supported
+ :raises:
+ + :exc:`STLError`
+ """
+
+ validate_type('port', port, int)
+ if port not in self.get_all_ports():
+ raise STLError("port {0} is not a valid port id".format(port))
+
+ if not is_valid_ipv4(addr):
+ raise STLError("addr is not a valid IPv4 address: '{0}'".format(addr))
+
+ self.logger.pre_cmd("Setting port {0} source address as '{1}': ".format(port, addr))
+ rc = self.ports[port].set_source_addr(addr)
+ self.logger.post_cmd(rc)
+
+ if not rc:
+ raise STLError(rc)
+
+ # for MAC dest - no resolve
+ if not self.ports[port].get_dst_addr()['ipv4']:
+ return rc
+
+ # resolve the address
+ return self.resolve(ports = port, verbose = False)
+
+
+ @__api_check(True)
+ def set_dest_addr (self, port, addr):
+ """
+ Configures a port with a destination address
+
+ :parameters:
+ port - the port to set the destination address
+ addr - destination address. can be either MAC or IPv4
+ :raises:
+ + :exc:`STLError`
+ """
+
+ validate_type('port', port, int)
+ if port not in self.get_all_ports():
+ raise STLError("port {0} is not a valid port id".format(port))
+
+ if not is_valid_ipv4(addr) and not is_valid_mac(addr):
+ raise STLError("addr is not a valid IPv4 address or a MAC address: '{0}'".format(addr))
+
+ if is_valid_ipv4(addr) and not self.ports[port].get_src_addr()['ipv4']:
+ raise STLError("cannot configure destination as IPv4 address without IPv4 source address")
+
+ self.logger.pre_cmd("Setting port {0} destination address as '{1}': ".format(port, addr))
+ rc = self.ports[port].set_dest_addr(addr)
+ self.logger.post_cmd(rc)
+
+ if not rc:
+ raise STLError(rc)
+
+ # resolve the address
+ return self.resolve(ports = port, verbose = False)
+
+
@__api_check(True)
def ping_ip (self, src_port, dst_ipv4, pkt_size = 64, count = 5):
"""
@@ -2010,8 +2078,8 @@ class STLClient(object):
self.clear_stats(ports)
self.set_port_attr(ports,
promiscuous = False,
- link_up = True if restart else None,
- rxf = 'hw')
+ link_up = True if restart else None)
+ self.set_service_mode(ports, False)
self.remove_rx_sniffer(ports)
self.remove_rx_queue(ports)
@@ -2813,9 +2881,6 @@ class STLClient(object):
link_up = None,
led_on = None,
flow_ctrl = None,
- rxf = None,
- ipv4 = None,
- dest = None,
resolve = True):
"""
Set port attributes
@@ -2825,9 +2890,6 @@ class STLClient(object):
link_up - True or False
led_on - True or False
flow_ctrl - 0: disable all, 1: enable tx side, 2: enable rx side, 3: full enable
- rxf - 'hw' for hardware rules matching packets only or 'all' all packets
- ipv4 - configure IPv4 address for port(s). for multiple ports should be a list of IPv4 addresses in the same length of the ports array
- dest - configure destination address for port(s) in either IPv4 or MAC format. for multiple ports should be a list in the same length of the ports array
resolve - if true, in case a destination address is configured as IPv4 try to resolve it
:raises:
+ :exe:'STLError'
@@ -2842,7 +2904,6 @@ class STLClient(object):
validate_type('link_up', link_up, (bool, type(None)))
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 = {}
@@ -2851,34 +2912,10 @@ class STLClient(object):
cmn_attr_dict['link_status'] = link_up
cmn_attr_dict['led_status'] = led_on
cmn_attr_dict['flow_ctrl_mode'] = flow_ctrl
- cmn_attr_dict['rx_filter_mode'] = rxf
# each port starts with a set of the common attributes
attr_dict = [dict(cmn_attr_dict) for _ in ports]
- # default value for IPv4 / dest is none for all ports
- if ipv4 is None:
- ipv4 = [None] * len(ports)
- if dest is None:
- dest = [None] * len(ports)
-
- ipv4 = listify(ipv4)
- if len(ipv4) != len(ports):
- raise STLError("'ipv4' must be a list in the same length of ports - 'ports': {0}, 'ip': {1}".format(ports, ipv4))
-
- dest = listify(dest)
- if len(dest) != len(ports):
- raise STLError("'dest' must be a list in the same length of ports - 'ports': {0}, 'dest': {1}".format(ports, dest))
-
- # update each port attribute with ipv4
- for addr, port_attr in zip(ipv4, attr_dict):
- port_attr['ipv4'] = addr
-
- # update each port attribute with dest
- for addr, port_attr in zip(dest, attr_dict):
- port_attr['dest'] = addr
-
-
self.logger.pre_cmd("Applying attributes on port(s) {0}:".format(ports))
rc = self.__set_port_attr(ports, attr_dict)
self.logger.post_cmd(rc)
@@ -2886,15 +2923,7 @@ class STLClient(object):
if not rc:
raise STLError(rc)
-
- # automatic resolve
- if resolve:
- # find any port with a dest configured as IPv4
- resolve_ports = [port_id for port_id, port_dest in zip(ports, dest) if is_valid_ipv4(port_dest)]
-
- if resolve_ports:
- self.resolve(ports = resolve_ports)
-
+
@__api_check(True)
@@ -2927,13 +2956,14 @@ class STLClient(object):
@__api_check(True)
- def resolve (self, ports = None, retries = 0):
+ def resolve (self, ports = None, retries = 0, verbose = True):
"""
Resolves ports (ARP resolution)
:parameters:
ports - for which ports to apply a unique sniffer (each port gets a unique file)
retires - how many times to retry on each port (intervals of 100 milliseconds)
+ verbose - log for each request the response
:raises:
+ :exe:'STLError'
@@ -2957,8 +2987,9 @@ class STLClient(object):
raise STLError(rc)
# print the ARP transaction
- self.logger.log(rc)
- self.logger.log('')
+ if verbose:
+ self.logger.log(rc)
+ self.logger.log('')
@@ -3122,7 +3153,7 @@ class STLClient(object):
try:
rc = f(*args)
except STLError as e:
- client.logger.log("Action has failed with the following error:\n" + format_text(e.brief() + "\n", 'bold'))
+ client.logger.log("\nAction has failed with the following error:\n" + format_text(e.brief() + "\n", 'bold'))
return RC_ERR(e.brief())
# if got true - print time
@@ -3156,7 +3187,8 @@ class STLClient(object):
return opts
# IP ping
- self.ping_ip(opts.source_port, opts.ping_ipv4, opts.pkt_size, opts.count)
+ # source ports maps to ports as a single port
+ self.ping_ip(opts.ports[0], opts.ping_ipv4, opts.pkt_size, opts.count)
@__console
@@ -3691,9 +3723,6 @@ class STLClient(object):
parsing_opts.LED_STATUS,
parsing_opts.FLOW_CTRL,
parsing_opts.SUPPORTED,
- parsing_opts.RX_FILTER_MODE,
- parsing_opts.IPV4,
- parsing_opts.DEST
)
opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True)
@@ -3706,7 +3735,7 @@ class STLClient(object):
opts.flow_ctrl = parsing_opts.FLOW_CTRL_DICT.get(opts.flow_ctrl)
# if no attributes - fall back to printing the status
- if not list(filter(lambda x:x is not None, [opts.prom, opts.link, opts.led, opts.flow_ctrl, opts.supp, opts.rx_filter_mode, opts.ipv4, opts.dest])):
+ if not list(filter(lambda x:x is not None, [opts.prom, opts.link, opts.led, opts.flow_ctrl, opts.supp])):
self.show_stats_line("--ps --port {0}".format(' '.join(str(port) for port in opts.ports)))
return
@@ -3724,10 +3753,7 @@ class STLClient(object):
opts.prom,
opts.link,
opts.led,
- opts.flow_ctrl,
- opts.rx_filter_mode,
- opts.ipv4,
- opts.dest)
+ opts.flow_ctrl)
@@ -3782,6 +3808,46 @@ class STLClient(object):
@__console
+ def set_source_addr_line (self, line):
+ '''Configures source address for port(s)'''
+
+ parser = parsing_opts.gen_parser(self,
+ "source",
+ self.set_source_addr_line.__doc__,
+ parsing_opts.SOURCE_PORT,
+ parsing_opts.IPV4)
+
+ opts = parser.parse_args(line.split())
+ if not opts:
+ return opts
+
+ # source ports maps to ports as a single port
+ self.set_source_addr(opts.ports[0], opts.ipv4)
+
+ return RC_OK()
+
+
+ @__console
+ def set_dest_addr_line (self, line):
+ '''Configures destination address for port(s)'''
+
+ parser = parsing_opts.gen_parser(self,
+ "dest",
+ self.set_dest_addr_line.__doc__,
+ parsing_opts.SOURCE_PORT,
+ parsing_opts.DEST)
+
+ opts = parser.parse_args(line.split())
+ if not opts:
+ return opts
+
+ # source ports maps to ports as a single port
+ self.set_dest_addr(opts.ports[0], opts.dest)
+
+ return RC_OK()
+
+
+ @__console
def show_profile_line (self, line):
'''Shows profile information'''
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 9309ad0c..5ec1f852 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
@@ -519,7 +519,23 @@ class Port(object):
return self.ok()
-
+
+ @owned
+ def set_source_addr (self, addr):
+ if not self.is_service_mode_on():
+ return self.err('port service mode must be enabled for configuring source address. Please enable service mode')
+
+ return self.set_attr(ipv4 = addr)
+
+
+ @owned
+ def set_dest_addr (self, addr):
+ if not self.is_service_mode_on():
+ return self.err('port service mode must be enabled for configuring destination address. Please enable service mode')
+
+ return self.set_attr(dest = addr)
+
+
@owned
def set_arp_resolution (self, ipv4, mac):
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 66a17a03..c5f53d68 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
@@ -46,7 +46,6 @@ SUPPORTED = 29
FILE_PATH_NO_CHECK = 30
OUTPUT_FILENAME = 31
-ALL_FILES = 32
LIMIT = 33
PORT_RESTART = 34
@@ -54,7 +53,6 @@ IPV4 = 35
DEST = 36
RETRIES = 37
-RX_FILTER_MODE = 38
SOURCE_PORT = 39
PING_IPV4 = 40
PING_COUNT = 41
@@ -343,24 +341,17 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'dest': 'flow_ctrl',
'choices': FLOW_CTRL_DICT}),
- RX_FILTER_MODE: ArgumentPack(['--rxf'],
- {'help': 'Set RX filtering mode',
- 'dest': 'rx_filter_mode',
- 'choices': ['hw', 'all']}),
-
-
IPV4: ArgumentPack(['--ipv4'],
{'help': 'IPv4 address(s) for the port(s)',
'dest': 'ipv4',
- 'nargs': '+',
- 'default': None,
+ 'required': True,
'type': check_ipv4_addr}),
- DEST: ArgumentPack(['--dest'],
+ DEST: ArgumentPack(['--addr'],
{'help': 'Destination address(s) for the port(s) in either IPv4 or MAC format',
+ 'metavar': 'addr',
'dest': 'dest',
- 'nargs': '+',
- 'default': None,
+ 'required' : True,
'type': check_dest_addr}),
RETRIES: ArgumentPack(['-r', '--retries'],
@@ -384,14 +375,6 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'default': False,
'action': 'store_true'}),
-
- ALL_FILES: ArgumentPack(['--all'],
- {'help': 'change RX port filter to fetch all packets',
- 'dest': 'all',
- 'default': False,
- 'action': "store_true"}),
-
-
LIMIT: ArgumentPack(['-l', '--limit'],
{'help': 'Limit the packet count to be written to the file',
'dest': 'limit',
@@ -423,8 +406,9 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
SOURCE_PORT: ArgumentPack(['--port', '-p'],
- {'dest':'source_port',
+ {'dest':'ports',
'type': int,
+ 'metavar': 'PORT',
'help': 'source port for the action',
'required': True}),
@@ -652,6 +636,8 @@ class CCmdArgParser(argparse.ArgumentParser):
if not self.has_ports_cfg(opts):
return opts
+ opts.ports = listify(opts.ports)
+
# if all ports are marked or
if (getattr(opts, "all_ports", None) == True) or (getattr(opts, "ports", None) == []):
if default_ports is None:
@@ -664,7 +650,12 @@ class CCmdArgParser(argparse.ArgumentParser):
# so maybe we have ports configured
invalid_ports = list_difference(opts.ports, self.stateless_client.get_all_ports())
if invalid_ports:
- msg = "{0}: port(s) {1} are not valid port IDs".format(self.cmd_name, invalid_ports)
+
+ if len(invalid_ports) > 1:
+ msg = "{0}: port(s) {1} are not valid port IDs".format(self.cmd_name, invalid_ports)
+ else:
+ msg = "{0}: port {1} is not a valid port ID".format(self.cmd_name, invalid_ports[0])
+
self.stateless_client.logger.log(format_text(msg, 'bold'))
return RC_ERR(msg)
diff --git a/src/common/Network/Packet/MacAddress.h b/src/common/Network/Packet/MacAddress.h
index 9bd3eae1..924f774e 100755
--- a/src/common/Network/Packet/MacAddress.h
+++ b/src/common/Network/Packet/MacAddress.h
@@ -47,7 +47,7 @@ public:
a5);
};
- MacAddress(uint8_t macAddr[ETHER_ADDR_LEN])
+ MacAddress(const uint8_t macAddr[ETHER_ADDR_LEN])
{
set(macAddr[0],
macAddr[1],
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index a01d57a2..03c41431 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -3153,11 +3153,6 @@ void CGlobalTRex::pre_test() {
// If we got src MAC for port in global config, take it, otherwise use src MAC from DPDK
uint8_t port_macs[m_max_ports][ETHER_ADDR_LEN];
for (int port_id = 0; port_id < m_max_ports; port_id++) {
- uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
- if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
- rte_eth_macaddr_get(port_id,
- (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
- }
memcpy(port_macs[port_id], CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, ETHER_ADDR_LEN);
}
@@ -3200,16 +3195,9 @@ void CGlobalTRex::pre_test() {
} else {
resolve_needed = false;
}
- if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
- rte_eth_macaddr_get(port_id,
- (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
- need_grat_arp[port_id] = true;
- } else {
- // If we got src MAC from config file, do not send gratuitous ARP for it
- // (for compatibility with old behaviour)
- need_grat_arp[port_id] = false;
- }
-
+
+ need_grat_arp[port_id] = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip() != 0;
+
pretest.add_ip(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip()
, CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan()
, CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
@@ -4880,7 +4868,14 @@ bool CPhyEthIF::Create(uint8_t portid) {
m_last_tx_pps = 0.0;
m_port_attr = g_trex.m_drv->create_port_attr(portid);
+ /* set src MAC addr */
+ uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0};
+ if (! memcmp( CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) {
+ rte_eth_macaddr_get(m_port_id,
+ (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src);
+ }
+ /* set src IPv4 */
uint32_t src_ipv4 = CGlobalInfo::m_options.m_ip_cfg[m_port_id].get_ip();
if (src_ipv4) {
m_port_attr->set_src_ipv4(src_ipv4);
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
index 3d541fe5..5c397fcd 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -368,8 +368,10 @@ TrexRpcCmdSetPortAttr::parse_ipv4(const Json::Value &msg, uint8_t port_id, Json:
ss << "invalid IPv4 address: '" << ipv4_str << "'";
generate_parse_err(result, ss.str());
}
+
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+ port->set_src_ipv4(ipv4_addr);
- get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_src_ipv4(ipv4_addr);
return (0);
}
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index 7edf1a31..057f6521 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -987,6 +987,19 @@ TrexStatelessPort::get_rx_queue_pkts() {
return reply.wait_for_reply();
}
+
+void
+TrexStatelessPort::set_src_ipv4(uint32_t ipv4) {
+
+ getPortAttrObj()->set_src_ipv4(ipv4);
+
+ CManyIPInfo src_addr;
+ src_addr.insert(COneIPv4Info(ipv4, 0, getPortAttrObj()->get_src_mac(), m_port_id));
+
+ TrexStatelessRxUpdateSrcAddr *msg = new TrexStatelessRxUpdateSrcAddr(m_port_id, src_addr);
+ send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+}
+
Json::Value
TrexStatelessPort::rx_features_to_json() {
static MsgReply<Json::Value> reply;
diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h
index 74ab17f1..3ae74f5a 100644
--- a/src/stateless/cp/trex_stateless_port.h
+++ b/src/stateless/cp/trex_stateless_port.h
@@ -400,6 +400,12 @@ public:
const RXPacketBuffer *get_rx_queue_pkts();
/**
+ * sets an IPv4 source address
+ *
+ */
+ void set_src_ipv4(uint32_t ipv4);
+
+ /**
* generate a JSON describing the status
* of the RX features
*
diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp
index 17acb21e..dc656e67 100644
--- a/src/stateless/messaging/trex_stateless_messaging.cpp
+++ b/src/stateless/messaging/trex_stateless_messaging.cpp
@@ -316,3 +316,8 @@ TrexStatelessRxFeaturesToJson::handle(CRxCoreStateless *rx_core) {
return true;
}
+bool
+TrexStatelessRxUpdateSrcAddr::handle(CRxCoreStateless *rx_core) {
+ rx_core->get_rx_port_mngr(m_port_id).update_src_addr(m_src_addr);
+ return true;
+}
diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h
index 79a6bf08..5f00c244 100644
--- a/src/stateless/messaging/trex_stateless_messaging.h
+++ b/src/stateless/messaging/trex_stateless_messaging.h
@@ -27,6 +27,7 @@ limitations under the License.
#include "trex_exception.h"
#include "trex_stateless_rx_defs.h"
#include "os_time.h"
+#include "utl_ip.h"
class TrexStatelessDpCore;
class CRxCoreStateless;
@@ -568,6 +569,22 @@ private:
};
+class TrexStatelessRxUpdateSrcAddr : public TrexStatelessCpToRxMsgBase {
+public:
+ TrexStatelessRxUpdateSrcAddr(uint8_t port_id,
+ const CManyIPInfo &src_addr) {
+
+ m_port_id = port_id;
+ m_src_addr = src_addr;
+ }
+
+ virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+ uint8_t m_port_id;
+ CManyIPInfo m_src_addr;
+};
+
/**
* a request from RX core to dump to Json the RX features
*/
diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp
index 9898e8b9..31fef68f 100644
--- a/src/stateless/rx/trex_stateless_rx_core.cpp
+++ b/src/stateless/rx/trex_stateless_rx_core.cpp
@@ -85,12 +85,12 @@ 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_rx_port_mngr[i].create(port_attr,
+ cfg.m_ports[i],
m_rfc2544,
&m_err_cntrs,
&m_cpu_dp_u,
- cfg.m_num_crc_fix_bytes,
- port_attr);
+ cfg.m_num_crc_fix_bytes);
}
}
@@ -189,6 +189,7 @@ void CRxCoreStateless::handle_work_stage() {
/* set the next sync time to */
dsec_t sync_time_sec = now_sec() + (1.0 / 1000);
+ dsec_t tick_time_sec = now_sec() + 1.0;
while (m_state == STATE_WORKING) {
process_all_pending_pkts();
@@ -197,8 +198,11 @@ void CRxCoreStateless::handle_work_stage() {
if ( (now - sync_time_sec) > 0 ) {
periodic_check_for_cp_messages();
+ }
+
+ if ( (now - tick_time_sec) > 0) {
port_manager_tick();
- sync_time_sec = now + (1.0 / 1000);
+ tick_time_sec = now + 1.0;
}
rte_pause();
@@ -211,6 +215,8 @@ void CRxCoreStateless::start() {
m_monitor.create("STL RX CORE", 1);
TrexWatchDog::getInstance().register_monitor(&m_monitor);
+ recalculate_next_state();
+
while (m_state != STATE_QUIT) {
switch (m_state) {
case STATE_IDLE:
@@ -334,7 +340,7 @@ CRxCoreStateless::disable_latency() {
recalculate_next_state();
}
-const RXPortManager &
+RXPortManager &
CRxCoreStateless::get_rx_port_mngr(uint8_t port_id) {
assert(port_id < m_max_ports);
return m_rx_port_mngr[port_id];
diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h
index cd16bb8a..96e511b4 100644
--- a/src/stateless/rx/trex_stateless_rx_core.h
+++ b/src/stateless/rx/trex_stateless_rx_core.h
@@ -151,7 +151,7 @@ class CRxCoreStateless {
void enable_latency();
void disable_latency();
- const RXPortManager &get_rx_port_mngr(uint8_t port_id);
+ RXPortManager &get_rx_port_mngr(uint8_t port_id);
private:
void handle_cp_msg(TrexStatelessCpToRxMsgBase *msg);
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
index af312700..e36f825d 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
@@ -23,6 +23,7 @@
#include "common/captureFile.h"
#include "trex_stateless_rx_core.h"
#include "common/Network/Packet/Arp.h"
+#include "pkt_gen.h"
/**************************************
* latency RX feature
@@ -507,16 +508,16 @@ protected:
};
RXServer::RXServer() {
- m_port_attr = NULL;
m_io = NULL;
+ m_src_addr = 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();
+RXServer::create(uint8_t port_id, CPortLatencyHWBase *io, const CManyIPInfo *src_addr) {
+ m_port_id = port_id;
+ m_io = io;
+ m_src_addr = src_addr;
}
@@ -538,7 +539,7 @@ void
RXServer::handle_icmp(RXPktParser &parser) {
/* maybe not for us... */
- if (parser.m_ipv4->getDestIp() != m_port_attr->get_src_ipv4()) {
+ if (!m_src_addr->exists(parser.m_ipv4->getDestIp())) {
return;
}
@@ -578,6 +579,7 @@ RXServer::handle_icmp(RXPktParser &parser) {
void
RXServer::handle_arp(RXPktParser &parser) {
+ MacAddress src_mac;
/* only ethernet format supported */
if (parser.m_arp->getHrdType() != ArpHdr::ARP_HDR_HRD_ETHER) {
@@ -595,7 +597,7 @@ RXServer::handle_arp(RXPktParser &parser) {
}
/* are we the target ? if not - go home */
- if (parser.m_arp->getTip() != m_port_attr->get_src_ipv4()) {
+ if (!m_src_addr->lookup(parser.m_arp->getTip(), 0, src_mac)) {
return;
}
@@ -612,14 +614,14 @@ RXServer::handle_arp(RXPktParser &parser) {
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->mySource = 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());
+ response_parser.m_arp->m_arp_sha = src_mac;
+ response_parser.m_arp->setSip(parser.m_arp->getTip());
/* dst */
response_parser.m_arp->m_arp_tha = parser.m_arp->m_arp_sha;
@@ -655,6 +657,44 @@ RXServer::duplicate_mbuf(const rte_mbuf_t *m) {
}
/**************************************
+ * Gratidious ARP
+ *
+ *************************************/
+void
+RXGratARP::create(uint8_t port_id, CPortLatencyHWBase *io, CManyIPInfo *src_addr) {
+ m_io = io;
+ m_port_id = port_id;
+ m_src_addr = src_addr;
+}
+
+void
+RXGratARP::send_next_grat_arp() {
+ uint8_t src_mac[ETHER_ADDR_LEN];
+
+ const COneIPInfo *ip_info = m_src_addr->get_next_loop();
+ if (!ip_info) {
+ return;
+ }
+
+ rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(m_port_id));
+ assert(m);
+
+ uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, ip_info->get_grat_arp_len());
+ ip_info->get_mac(src_mac);
+ uint16_t vlan = ip_info->get_vlan();
+
+ /* for now only IPv4 */
+ assert(ip_info->ip_ver() == COneIPInfo::IP4_VER);
+ uint32_t sip = ((COneIPv4Info *)ip_info)->get_ip();
+
+ CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, m_port_id);
+
+ m_io->tx(m);
+
+
+}
+
+/**************************************
* Port manager
*
*************************************/
@@ -663,26 +703,37 @@ RXPortManager::RXPortManager() {
clear_all_features();
m_io = NULL;
m_cpu_dp_u = NULL;
+ m_port_id = UINT8_MAX;
}
void
-RXPortManager::create(CPortLatencyHWBase *io,
+RXPortManager::create(const TRexPortAttr *port_attr,
+ CPortLatencyHWBase *io,
CRFC2544Info *rfc2544,
CRxCoreErrCntrs *err_cntrs,
CCpuUtlDp *cpu_util,
- uint8_t crc_bytes_num,
- const TRexPortAttr *port_attr) {
+ uint8_t crc_bytes_num) {
+
+ m_port_id = port_attr->get_port_id();
m_io = io;
m_cpu_dp_u = cpu_util;
m_num_crc_fix_bytes = crc_bytes_num;
+ /* if IPv4 is configured - add it to the grat service */
+ uint32_t src_ipv4 = port_attr->get_src_ipv4();
+ if (src_ipv4) {
+ m_src_addr.insert(COneIPv4Info(src_ipv4, 0, port_attr->get_src_mac(), m_port_id));
+ }
+
/* init features */
m_latency.create(rfc2544, err_cntrs);
- m_server.create(port_attr, io);
+ m_server.create(m_port_id, io, &m_src_addr);
+ m_grat_arp.create(m_port_id, io, &m_src_addr);
/* by default, server feature is always on */
set_feature(SERVER);
+ set_feature(GRAT_ARP);
}
void RXPortManager::handle_pkt(const rte_mbuf_t *m) {
@@ -706,7 +757,6 @@ void RXPortManager::handle_pkt(const rte_mbuf_t *m) {
}
}
-
int RXPortManager::process_all_pending_pkts(bool flush_rx) {
rte_mbuf_t *rx_pkts[64];
@@ -747,8 +797,13 @@ RXPortManager::tick() {
if (is_feature_set(RECORDER)) {
m_recorder.flush_to_disk();
}
+
+ if (is_feature_set(GRAT_ARP)) {
+ m_grat_arp.send_next_grat_arp();
+ }
}
+
Json::Value
RXPortManager::to_json() const {
Json::Value output = Json::objectValue;
@@ -777,3 +832,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 12b601ea..e72b0ff0 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.h
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h
@@ -264,7 +264,7 @@ class RXServer {
public:
RXServer();
- void create(const TRexPortAttr *port_attr, CPortLatencyHWBase *io);
+ void create(uint8_t port_id, CPortLatencyHWBase *io, const CManyIPInfo *src_addr);
void handle_pkt(const rte_mbuf_t *m);
private:
@@ -272,9 +272,36 @@ private:
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;
+ const CManyIPInfo *m_src_addr;
+};
+
+/**************************************
+ * Gratidious ARP
+ *
+ *************************************/
+class RXGratARP {
+public:
+ RXGratARP() {
+ m_io = NULL;
+ m_port_id = UINT8_MAX;
+ m_src_addr = NULL;
+ }
+
+ void create(uint8_t port_id, CPortLatencyHWBase *io, CManyIPInfo *src_addr);
+
+
+ /**
+ * the main 'tick' of the service
+ *
+ */
+ void send_next_grat_arp();
+
+private:
+ CPortLatencyHWBase *m_io;
+ CManyIPInfo *m_src_addr;
+ uint8_t m_port_id;
};
/************************ manager ***************************/
@@ -291,22 +318,25 @@ public:
LATENCY = 0x1,
RECORDER = 0x2,
QUEUE = 0x4,
- SERVER = 0x8
+ SERVER = 0x8,
+ GRAT_ARP = 0x10,
};
RXPortManager();
- void create(CPortLatencyHWBase *io,
+ void create(const TRexPortAttr *port_attr,
+ CPortLatencyHWBase *io,
CRFC2544Info *rfc2544,
CRxCoreErrCntrs *err_cntrs,
CCpuUtlDp *cpu_util,
- uint8_t crc_bytes_num,
- const TRexPortAttr *port_attr);
+ uint8_t crc_bytes_num);
+
void clear_stats() {
m_latency.reset_stats();
}
+
void get_latency_stats(rx_per_flow_t *rx_stats,
int min,
int max,
@@ -390,6 +420,15 @@ public:
*/
void tick();
+ /**
+ * updates the source addresses registered with the port
+ *
+ */
+ void update_src_addr(const CManyIPInfo &new_src_addr) {
+ /* deep copy */
+ m_src_addr = new_src_addr;
+ }
+
bool has_features_set() {
return (m_features != NO_FEATURES);
}
@@ -423,17 +462,19 @@ private:
}
uint32_t m_features;
-
+ uint8_t m_port_id;
RXLatency m_latency;
RXPacketRecorder m_recorder;
RXQueue m_queue;
RXServer m_server;
+ RXGratARP m_grat_arp;
// compensate for the fact that hardware send us packets without Ethernet CRC, and we report with it
uint8_t m_num_crc_fix_bytes;
CCpuUtlDp *m_cpu_dp_u;
CPortLatencyHWBase *m_io;
+ CManyIPInfo m_src_addr;
};
diff --git a/src/trex_port_attr.cpp b/src/trex_port_attr.cpp
index 0ecbc2c4..2a68fcb9 100644
--- a/src/trex_port_attr.cpp
+++ b/src/trex_port_attr.cpp
@@ -99,7 +99,14 @@ TRexPortAttr::get_src_mac() const {
return CGlobalInfo::m_options.get_src_mac_addr(m_port_id);
}
-
+void
+TRexPortAttr::set_src_ipv4(uint32_t addr) {
+ m_src_ipv4 = addr;
+
+ /* when IP source changes - consider this as link down */
+ m_dest.on_link_down();
+}
+
std::string
TRexPortAttr::get_rx_filter_mode() const {
switch (m_rx_filter_mode) {
diff --git a/src/trex_port_attr.h b/src/trex_port_attr.h
index c69314fc..437fa8c7 100755
--- a/src/trex_port_attr.h
+++ b/src/trex_port_attr.h
@@ -151,11 +151,7 @@ public:
virtual int set_led(bool on) = 0;
virtual int set_rx_filter_mode(rx_filter_mode_e mode) = 0;
- void set_src_ipv4(uint32_t addr) {
- m_src_ipv4 = addr;
- /* when IP source changes - consider this as link down */
- m_dest.on_link_down();
- }
+ void set_src_ipv4(uint32_t addr);
/* DUMPS */
virtual void dump_link(FILE *fd) = 0;
diff --git a/src/utl_ip.cpp b/src/utl_ip.cpp
index e7bb6fab..d29ab60a 100644
--- a/src/utl_ip.cpp
+++ b/src/utl_ip.cpp
@@ -71,13 +71,14 @@ void COneIPv6Info::fill_grat_arp_buf(uint8_t *p) {
}
const COneIPInfo *CManyIPInfo::get_next() {
- COneIPInfo *ret;
-
+ const COneIPInfo *ret;
+
if (!m_iter_initiated) {
m_ipv4_iter = m_ipv4_resolve.begin();
m_iter_initiated = true;
}
+
if (m_ipv4_iter == m_ipv4_resolve.end()) {
m_ipv4_iter = m_ipv4_resolve.begin();
return NULL;
@@ -99,13 +100,13 @@ void CManyIPInfo::dump(FILE *fd) {
}
}
-void CManyIPInfo::insert(COneIPv4Info &ip_info) {
+void CManyIPInfo::insert(const COneIPv4Info &ip_info) {
CIpVlan ip_vlan(ip_info.get_ip(), ip_info.get_vlan());
m_ipv4_resolve.insert(std::make_pair(ip_vlan, ip_info));
}
-bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) {
+bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) const {
ip_vlan_to_many_ip_iter_t it = m_ipv4_resolve.find(CIpVlan(ip, vlan));
if (it != m_ipv4_resolve.end()) {
uint8_t mac[ETHER_ADDR_LEN];
@@ -117,6 +118,17 @@ bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) {
}
}
+bool CManyIPInfo::exists(uint32_t ip, uint16_t vlan) const {
+ ip_vlan_to_many_ip_iter_t it = m_ipv4_resolve.find(CIpVlan(ip, vlan));
+ return (it != m_ipv4_resolve.end());
+}
+
+void CManyIPInfo::clear() {
+ m_ipv4_resolve.clear();
+ m_ipv6_resolve.clear();
+ m_iter_initiated = false;
+}
+
const COneIPInfo *CManyIPInfo::get_first() {
if (m_ipv4_resolve.size() == 0) {
return NULL;
diff --git a/src/utl_ip.h b/src/utl_ip.h
index 27bb6c81..bab92c0f 100644
--- a/src/utl_ip.h
+++ b/src/utl_ip.h
@@ -156,7 +156,7 @@ class COneIPv4Info : public COneIPInfo {
m_ip = ip;
}
~COneIPv4Info() {};
- uint32_t get_ip() {return m_ip;}
+ uint32_t get_ip() const {return m_ip;}
virtual uint8_t ip_ver() const {return IP4_VER;}
virtual uint32_t get_arp_req_len() const {return 60;}
virtual uint32_t get_grat_arp_len() const {return 60;}
@@ -225,7 +225,7 @@ inline bool operator== (const COneIPv6Info& lhs, const COneIPv6Info& rhs) {
inline bool operator!= (const COneIPv6Info& lhs, const COneIPv6Info& rhs){ return !(lhs == rhs); }
typedef std::map<CIpVlan, COneIPv4Info> ip_vlan_to_many_ip_t;
-typedef std::map<CIpVlan, COneIPv4Info>::iterator ip_vlan_to_many_ip_iter_t;
+typedef std::map<CIpVlan, COneIPv4Info>::const_iterator ip_vlan_to_many_ip_iter_t;
typedef std::map<std::pair<uint16_t[8], uint16_t>, COneIPv6Info> ipv6_vlan_to_many_ipv6_t;
class CManyIPInfo {
@@ -233,18 +233,37 @@ class CManyIPInfo {
CManyIPInfo () {
m_iter_initiated = false;
}
- void insert(COneIPv4Info &ip_info);
- bool lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac);
+ void insert(const COneIPv4Info &ip_info);
+ bool lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) const;
+ bool exists(uint32_t ip, uint16_t vlan = 0) const;
+ void clear();
+
void dump(FILE *fd);
uint32_t size() { return m_ipv4_resolve.size() + m_ipv6_resolve.size();}
const COneIPInfo *get_first();
const COneIPInfo *get_next();
+ const COneIPInfo *get_next_loop() {
+ const COneIPInfo *ip_info = get_next();
+ return (ip_info ? ip_info : get_next());
+ }
+
+ CManyIPInfo& operator = (const CManyIPInfo &rhs) {
+ m_ipv4_resolve = rhs.m_ipv4_resolve;
+ m_ipv6_resolve = rhs.m_ipv6_resolve;
+
+ m_iter_initiated = false;
+ return (*this);
+ }
+
private:
- ip_vlan_to_many_ip_t m_ipv4_resolve;
+ ip_vlan_to_many_ip_t m_ipv4_resolve;
+ ipv6_vlan_to_many_ipv6_t m_ipv6_resolve;
+
ip_vlan_to_many_ip_iter_t m_ipv4_iter;
- ipv6_vlan_to_many_ipv6_t m_ipv6_resolve;
+
bool m_iter_initiated;
};
+
#endif