aboutsummaryrefslogtreecommitdiffstats
path: root/resources
diff options
context:
space:
mode:
authorPeter Mikus <pmikus@cisco.com>2018-01-02 14:37:24 +0100
committerPeter Mikus <pmikus@cisco.com>2018-01-04 06:30:18 +0000
commit92cbb44a89ca808df32e4a4cb137bed076a68a94 (patch)
tree904bb62e9bdb933ca57033b0efb56abb20142a7b /resources
parentc293eae53515f7b94ac5a71b329a9a9655bd8c09 (diff)
TRex ASTF onboarding Part I
- Preparing initialization of TRex in L7 mode - Updating Topology files - Adding sample ASTF profiles Change-Id: If71f7f8f3db66425a1b543f1d29069a7543f4090 Signed-off-by: Peter Mikus <pmikus@cisco.com>
Diffstat (limited to 'resources')
-rw-r--r--resources/libraries/python/TrafficGenerator.py150
-rw-r--r--resources/libraries/python/constants.py3
-rw-r--r--resources/libraries/python/topology.py15
-rw-r--r--resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-nginx-cps.py109
-rw-r--r--resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-vpp-cps.py105
5 files changed, 319 insertions, 63 deletions
diff --git a/resources/libraries/python/TrafficGenerator.py b/resources/libraries/python/TrafficGenerator.py
index 88adcc4542..a8083381d1 100644
--- a/resources/libraries/python/TrafficGenerator.py
+++ b/resources/libraries/python/TrafficGenerator.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2016 Cisco and/or its affiliates.
+# Copyright (c) 2018 Cisco and/or its affiliates.
# 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:
@@ -160,7 +160,7 @@ class TrafficGenerator(object):
:param tg_if1_adj_if: TG if1 adjecent interface.
:param tg_if2_adj_node: TG if2 adjecent node.
:param tg_if2_adj_if: TG if2 adjecent interface.
- :param test_type: 'L2' or 'L3' - src/dst MAC address.
+ :param test_type: 'L2', 'L3' or 'L7' - OSI Layer testing type.
:param tg_if1_dst_mac: Interface 1 destination MAC address.
:param tg_if2_dst_mac: Interface 2 destination MAC address.
:type tg_node: dict
@@ -176,16 +176,11 @@ class TrafficGenerator(object):
:returns: nothing
:raises: RuntimeError in case of issue during initialization.
"""
-
- topo = Topology()
-
if tg_node['type'] != NodeType.TG:
raise RuntimeError('Node type is not a TG')
self._node = tg_node
if tg_node['subtype'] == NodeSubTypeTG.TREX:
- trex_path = "/opt/trex-core-2.34"
-
ssh = SSH()
ssh.connect(tg_node)
@@ -196,89 +191,118 @@ class TrafficGenerator(object):
if int(ret) != 0:
raise RuntimeError('TRex installation failed.')
- if1_pci = topo.get_interface_pci_addr(tg_node, tg_if1)
- if2_pci = topo.get_interface_pci_addr(tg_node, tg_if2)
- if1_mac = topo.get_interface_mac(tg_node, tg_if1)
- if2_mac = topo.get_interface_mac(tg_node, tg_if2)
+ if1_pci = Topology().get_interface_pci_addr(tg_node, tg_if1)
+ if2_pci = Topology().get_interface_pci_addr(tg_node, tg_if2)
+ if1_addr = Topology().get_interface_mac(tg_node, tg_if1)
+ if2_addr = Topology().get_interface_mac(tg_node, tg_if2)
if test_type == 'L2':
- if1_adj_mac = if2_mac
- if2_adj_mac = if1_mac
+ if1_adj_addr = if2_addr
+ if2_adj_addr = if1_addr
elif test_type == 'L3':
- if1_adj_mac = topo.get_interface_mac(tg_if1_adj_node,
- tg_if1_adj_if)
- if2_adj_mac = topo.get_interface_mac(tg_if2_adj_node,
- tg_if2_adj_if)
+ if1_adj_addr = Topology().get_interface_mac(tg_if1_adj_node,
+ tg_if1_adj_if)
+ if2_adj_addr = Topology().get_interface_mac(tg_if2_adj_node,
+ tg_if2_adj_if)
+ elif test_type == 'L7':
+ if1_addr = Topology().get_interface_ip4(tg_node, tg_if1)
+ if2_addr = Topology().get_interface_ip4(tg_node, tg_if2)
+ if1_adj_addr = Topology().get_interface_ip4(tg_if1_adj_node,
+ tg_if1_adj_if)
+ if2_adj_addr = Topology().get_interface_ip4(tg_if2_adj_node,
+ tg_if2_adj_if)
else:
- raise ValueError("test_type unknown")
+ raise ValueError("Unknown Test Type")
+ # in case of switched environment we can override MAC addresses
if tg_if1_dst_mac is not None and tg_if2_dst_mac is not None:
- if1_adj_mac = tg_if1_dst_mac
- if2_adj_mac = tg_if2_dst_mac
+ if1_adj_addr = tg_if1_dst_mac
+ if2_adj_addr = tg_if2_dst_mac
if min(if1_pci, if2_pci) != if1_pci:
- if1_mac, if2_mac = if2_mac, if1_mac
if1_pci, if2_pci = if2_pci, if1_pci
- if1_adj_mac, if2_adj_mac = if2_adj_mac, if1_adj_mac
+ if1_addr, if2_addr = if2_addr, if1_addr
+ if1_adj_addr, if2_adj_addr = if2_adj_addr, if1_adj_addr
self._ifaces_reordered = True
- if1_mac_hex = "0x"+if1_mac.replace(":", ",0x")
- if2_mac_hex = "0x"+if2_mac.replace(":", ",0x")
- if1_adj_mac_hex = "0x"+if1_adj_mac.replace(":", ",0x")
- if2_adj_mac_hex = "0x"+if2_adj_mac.replace(":", ",0x")
-
- (ret, _, _) = ssh.exec_command(
- "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
- "- port_limit : 2\n"
- " version : 2\n"
- " interfaces : [\"{}\",\"{}\"]\n"
- " port_info :\n"
- " - dest_mac : [{}]\n"
- " src_mac : [{}]\n"
- " - dest_mac : [{}]\n"
- " src_mac : [{}]\n"
- "EOF'"\
- .format(if1_pci, if2_pci,
- if1_adj_mac_hex, if1_mac_hex,
- if2_adj_mac_hex, if2_mac_hex))
+ if test_type == 'L2' or test_type == 'L3':
+ (ret, _, _) = ssh.exec_command(
+ "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
+ "- port_limit: 2\n"
+ " version: 2\n"
+ " interfaces: [\"{0}\",\"{1}\"]\n"
+ " port_info:\n"
+ " - dest_mac: [{2}]\n"
+ " src_mac: [{3}]\n"
+ " - dest_mac: [{4}]\n"
+ " src_mac: [{5}]\n"
+ "EOF'"\
+ .format(if1_pci, if2_pci,
+ "0x"+if1_adj_addr.replace(":", ",0x"),
+ "0x"+if1_addr.replace(":", ",0x"),
+ "0x"+if2_adj_addr.replace(":", ",0x"),
+ "0x"+if2_addr.replace(":", ",0x")))
+ elif test_type == 'L7':
+ (ret, _, _) = ssh.exec_command(
+ "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
+ "- port_limit: 2\n"
+ " version: 2\n"
+ " interfaces: [\"{0}\",\"{1}\"]\n"
+ " port_info:\n"
+ " - ip: [{2}]\n"
+ " default_gw: [{3}]\n"
+ " - ip: [{4}]\n"
+ " default_gw: [{5}]\n"
+ "EOF'"\
+ .format(if1_pci, if2_pci,
+ if1_addr, if1_adj_addr,
+ if2_addr, if2_adj_addr))
+ else:
+ raise ValueError("Unknown Test Type")
if int(ret) != 0:
- raise RuntimeError('trex config generation error')
+ raise RuntimeError('TRex config generation error')
- max_startup_retries = 3
- while max_startup_retries > 0:
- # kill T-rex only if it is already running
- (ret, _, _) = ssh.exec_command(
+ for _ in range(0, 3):
+ # kill TRex only if it is already running
+ ssh.exec_command(
"sh -c 'pgrep t-rex && sudo pkill t-rex && sleep 3'")
- # configure T-rex
+ # configure TRex
(ret, _, _) = ssh.exec_command(
"sh -c 'cd {0}/scripts/ && sudo ./trex-cfg'"\
- .format(trex_path))
+ .format(Constants.TREX_INSTALL_DIR))
if int(ret) != 0:
raise RuntimeError('trex-cfg failed')
- # start T-rex
- (ret, _, _) = ssh.exec_command(
- "sh -c 'cd {0}/scripts/ && "
- "sudo nohup ./t-rex-64 -i -c 7 --iom 0 > /tmp/trex.log "
- "2>&1 &' > /dev/null"\
- .format(trex_path))
+ # start TRex
+ if test_type == 'L2' or test_type == 'L3':
+ (ret, _, _) = ssh.exec_command(
+ "sh -c 'cd {0}/scripts/ && "
+ "sudo nohup ./t-rex-64 -i -c 7 --iom 0 > /tmp/trex.log "
+ "2>&1 &' > /dev/null"\
+ .format(Constants.TREX_INSTALL_DIR))
+ elif test_type == 'L7':
+ (ret, _, _) = ssh.exec_command(
+ "sh -c 'cd {0}/scripts/ && "
+ "sudo nohup ./t-rex-64 --astf -i -c 7 --iom 0 > "
+ "/tmp/trex.log 2>&1 &' > /dev/null"\
+ .format(Constants.TREX_INSTALL_DIR))
+ else:
+ raise ValueError("Unknown Test Type")
if int(ret) != 0:
ssh.exec_command("sh -c 'cat /tmp/trex.log'")
raise RuntimeError('t-rex-64 startup failed')
- # get T-rex server info
+ # get TRex server info
(ret, _, _) = ssh.exec_command(
"sh -c 'sleep 3; "
"{0}/resources/tools/trex/trex_server_info.py'"\
.format(Constants.REMOTE_FW_DIR),
timeout=120)
if int(ret) == 0:
- # If we get info T-rex is running
+ # If we get info TRex is running
return
- # try again
- max_startup_retries -= 1
- # after max retries T-rex is still not responding to API
+ # after max retries TRex is still not responding to API
# critical error occurred
raise RuntimeError('t-rex-64 startup failed')
@@ -289,7 +313,7 @@ class TrafficGenerator(object):
:param node: Traffic generator node.
:type node: dict
:returns: nothing
- :raises: RuntimeError if T-rex teardown failed.
+ :raises: RuntimeError if TRex teardown failed.
:raises: RuntimeError if node type is not a TG.
"""
if node['type'] != NodeType.TG:
@@ -306,7 +330,7 @@ class TrafficGenerator(object):
def trex_stl_stop_remote_exec(node):
"""Execute script on remote node over ssh to stop running traffic.
- :param node: T-REX generator node.
+ :param node: TRex generator node.
:type node: dict
:returns: Nothing
:raises: RuntimeError if stop traffic script fails.
@@ -319,7 +343,7 @@ class TrafficGenerator(object):
"trex_stateless_stop.py'".format(Constants.REMOTE_FW_DIR))
if int(ret) != 0:
- raise RuntimeError('T-rex stateless runtime error')
+ raise RuntimeError('TRex stateless runtime error')
def trex_stl_start_remote_exec(self, duration, rate, framesize,
traffic_type, async_call=False,
@@ -370,7 +394,7 @@ class TrafficGenerator(object):
timeout=int(duration) + 60)
if int(ret) != 0:
- raise RuntimeError('T-rex stateless runtime error')
+ raise RuntimeError('TRex stateless runtime error')
elif async_call:
#no result
self._received = None
diff --git a/resources/libraries/python/constants.py b/resources/libraries/python/constants.py
index 01a96a861b..7ae9cdd06f 100644
--- a/resources/libraries/python/constants.py
+++ b/resources/libraries/python/constants.py
@@ -35,6 +35,9 @@ class Constants(object):
# QEMU install directory
QEMU_INSTALL_DIR = '/opt/qemu-2.5.0'
+ # TRex install directory
+ TREX_INSTALL_DIR = '/opt/trex-core-2.34'
+
# Kubernetes templates location
RESOURCES_TPL_K8S = 'resources/templates/kubernetes'
diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py
index 4ff68ec43d..a5a446008b 100644
--- a/resources/libraries/python/topology.py
+++ b/resources/libraries/python/topology.py
@@ -600,6 +600,21 @@ class Topology(object):
return None
@staticmethod
+ def get_interface_ip4(node, iface_key):
+ """Get IP4 address for the interface.
+
+ :param node: Node to get interface mac on.
+ :param iface_key: Interface key from topology file.
+ :type node: dict
+ :type iface_key: str
+ :returns: Return IP4 or None if not found.
+ """
+ try:
+ return node['interfaces'][iface_key].get('ip4_address', None)
+ except KeyError:
+ return None
+
+ @staticmethod
def get_adjacent_node_and_interface(nodes_info, node, iface_key):
"""Get node and interface adjacent to specified interface
on local network.
diff --git a/resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-nginx-cps.py b/resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-nginx-cps.py
new file mode 100644
index 0000000000..4e838e0088
--- /dev/null
+++ b/resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-nginx-cps.py
@@ -0,0 +1,109 @@
+# Copyright (c) 2018 Cisco and/or its affiliates.
+# 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.
+
+"""ASTF profile for TRex traffic generator.
+
+ASTF profile:
+ - Client side traffic in directions 0 --> 1.
+ - Server side traffic disabled.
+ - Packet: ETH / IP / TCP / HTTP1.1
+ - Direction 0 --> 1:
+ - Source IP address range: 172.16.130.2 - 172.16.130.2
+ - Destination IP address range: 192.168.0.1
+"""
+
+from trex_astf_lib.api import *
+
+
+class Prof1():
+ def __init__(self):
+ """Initialization and setting of streams' parameters."""
+
+ # Response content length.
+ self.content_len = 0
+ # Number of requests per HTTP transaction.
+ self.requests = 1
+ # Number of transactions per HTTP connection.
+ self.transaction_per_conn = 1
+ # Use TCP RST instead of FIN+ACK.
+ self.tcp_reset = False
+
+ # IP used in packet headers.
+ self.p1_src_start_ip = '172.16.130.2'
+ self.p1_src_end_ip = '172.16.130.2'
+ self.p1_dst_start_ip = '192.168.0.1'
+ self.p1_dst_end_ip = '192.168.0.1'
+
+ self.http_req = (b'GET /0KB.bin HTTP/1.1\r\n'
+ 'Host: {host}\r\n'
+ 'User-Agent: trex/astf\r\n'
+ 'Accept: */*\r\n'
+ 'Connection: keep-alive\r\n\r\n'
+ .format(host=self.p1_dst_start_ip))
+ self.http_res = (b'HTTP/1.1 200 OK\r\n'
+ 'Server: nginx/1.13.7\r\n'
+ 'Date: Mon, 01 Jan 2018 00:00:00 GMT\r\n'
+ 'Content-Type: application/octet-stream\r\n'
+ 'Content-Length: {length}\r\n'
+ 'Last-Modified: Mon, 01 Jan 2018 00:00:00 GMT\r\n'
+ 'Connection: keep-alive\r\n'
+ 'ETag: "5a027c14-0"\r\n'
+ 'Accept-Ranges: bytes\r\n\r\n'
+ .format(length=self.content_len))
+
+ def create_profile(self):
+ # client operations
+ prog_c = ASTFProgram()
+ prog_c.connect()
+ for i in range(self.transaction_per_conn):
+ prog_c.send(self.http_req * self.requests)
+ prog_c.recv((len(self.http_res) + self.content_len) * self.requests)
+ if self.tcp_reset:
+ prog_c.reset()
+
+ # ip generator
+ ip_gen_c = ASTFIPGenDist(ip_range=[self.p1_src_start_ip,
+ self.p1_src_end_ip],
+ distribution="seq")
+ ip_gen_s = ASTFIPGenDist(ip_range=[self.p1_dst_start_ip,
+ self.p1_dst_end_ip],
+ distribution="seq")
+ ip_gen = ASTFIPGen(glob=ASTFIPGenGlobal(ip_offset="0.0.0.1"),
+ dist_client=ip_gen_c,
+ dist_server=ip_gen_s)
+
+ # TCP parameters
+ tcp_params = ASTFTCPInfo(window=32768)
+ # client tunables
+ c_glob_info = ASTFGlobalInfo()
+
+ # template
+ client_template = ASTFTCPClientTemplate(program=prog_c,
+ tcp_info=tcp_params,
+ ip_gen=ip_gen)
+ server_template = ASTFTCPServerTemplate(program=ASTFProgram(),
+ tcp_info=tcp_params)
+ template = ASTFTemplate(client_template=client_template,
+ server_template=server_template)
+
+ # profile
+ return ASTFProfile(default_ip_gen=ip_gen, templates=template,
+ default_c_glob_info=c_glob_info)
+
+ def get_profile(self):
+ return self.create_profile()
+
+
+def register():
+ return Prof1()
+
diff --git a/resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-vpp-cps.py b/resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-vpp-cps.py
new file mode 100644
index 0000000000..0533978830
--- /dev/null
+++ b/resources/traffic_profiles/trex/trex-sf-2n-ethip4tcphttp-1u1s-vpp-cps.py
@@ -0,0 +1,105 @@
+# Copyright (c) 2018 Cisco and/or its affiliates.
+# 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.
+
+"""ASTF profile for TRex traffic generator.
+
+ASTF profile:
+ - Client side traffic in directions 0 --> 1.
+ - Server side traffic disabled.
+ - Packet: ETH / IP / TCP / HTTP1.1
+ - Direction 0 --> 1:
+ - Source IP address range: 172.16.130.2 - 172.16.130.2
+ - Destination IP address range: 192.168.0.1
+"""
+
+from trex_astf_lib.api import *
+
+
+class Prof1():
+ def __init__(self):
+ """Initialization and setting of streams' parameters."""
+
+ # Response content length.
+ self.content_len = 115
+ # Number of requests per HTTP transaction.
+ self.requests = 1
+ # Number of transactions per HTTP connection.
+ self.transaction_per_conn = 1
+ # Use TCP RST instead of FIN+ACK.
+ self.tcp_reset = False
+
+ # IP used in packet headers.
+ self.p1_src_start_ip = '172.16.130.2'
+ self.p1_src_end_ip = '172.16.130.2'
+ self.p1_dst_start_ip = '172.16.130.1'
+ self.p1_dst_end_ip = '172.16.130.1'
+
+ self.http_req = (b'GET / HTTP/1.1\r\n'
+ 'Host: {host}\r\n'
+ 'User-Agent: trex/astf\r\n'
+ 'Accept: */*\r\n\r\n'
+ .format(host=self.p1_dst_start_ip))
+ self.http_res = (b'HTTP/1.1 200 OK\r\n'
+ 'Content-Type: text/html\r\n'
+ 'Expires: Mon, 11 Jan 1970 10:10:10 GMT\r\n'
+ 'Connection: close\r\n'
+ 'Pragma: no-cache\r\n'
+ 'Content-Length: {length}\r\n\r\n'
+ .format(length=self.content_len))
+
+ def create_profile(self):
+ # client operations
+ prog_c = ASTFProgram()
+ prog_c.connect()
+ for i in range(self.transaction_per_conn):
+ prog_c.send(self.http_req * self.requests)
+ prog_c.recv((len(self.http_res) + self.content_len) * self.requests)
+ if self.tcp_reset:
+ prog_c.reset()
+
+ # ip generator
+ ip_gen_c = ASTFIPGenDist(ip_range=[self.p1_src_start_ip,
+ self.p1_src_end_ip],
+ distribution="seq")
+ ip_gen_s = ASTFIPGenDist(ip_range=[self.p1_dst_start_ip,
+ self.p1_dst_end_ip],
+ distribution="seq")
+ ip_gen = ASTFIPGen(glob=ASTFIPGenGlobal(ip_offset="0.0.0.1"),
+ dist_client=ip_gen_c,
+ dist_server=ip_gen_s)
+
+ # TCP parameters
+ tcp_params = ASTFTCPInfo(window=32768)
+ # client tunables
+ c_glob_info = ASTFGlobalInfo()
+
+ # template
+ client_template = ASTFTCPClientTemplate(program=prog_c,
+ tcp_info=tcp_params,
+ ip_gen=ip_gen)
+ server_template = ASTFTCPServerTemplate(program=ASTFProgram(),
+ tcp_info=tcp_params)
+ template = ASTFTemplate(client_template=client_template,
+ server_template=server_template)
+
+ # profile
+ return ASTFProfile(default_ip_gen=ip_gen, templates=template,
+ default_c_glob_info=c_glob_info)
+
+ def get_profile(self):
+ return self.create_profile()
+
+
+def register():
+ return Prof1()
+