aboutsummaryrefslogtreecommitdiffstats
path: root/GPL
diff options
context:
space:
mode:
authorpmikus <peter.mikus@protonmail.ch>2023-10-13 12:34:04 +0000
committerPeter Mikus <peter.mikus@protonmail.ch>2023-10-25 14:30:07 +0000
commit039a8a325bc24cd8d7c5770d88a20ce517197fe9 (patch)
treeac3a958d9493e89781ee61266b3d3e7de41e0c5f /GPL
parent8993ddb4f38f2754ae3af1c61e69a2e747f32a67 (diff)
feat(core): Multilink TRex Sync mode II
Signed-off-by: Peter Mikus <peter.mikus@protonmail.ch> Change-Id: Idf4df372520d4a72c0738a89290d16710485f140
Diffstat (limited to 'GPL')
-rw-r--r--GPL/tools/trex/trex_stl_profile.py55
-rw-r--r--GPL/traffic_profiles/trex/profile_trex_stateless_scale_class.py196
-rw-r--r--GPL/traffic_profiles/trex/trex-stl-ethip4-ip4dst10000p3.py135
3 files changed, 359 insertions, 27 deletions
diff --git a/GPL/tools/trex/trex_stl_profile.py b/GPL/tools/trex/trex_stl_profile.py
index c318674899..ac53e90571 100644
--- a/GPL/tools/trex/trex_stl_profile.py
+++ b/GPL/tools/trex/trex_stl_profile.py
@@ -74,8 +74,7 @@ def simple_burst(
duration,
framesize,
rate,
- port_0,
- port_1,
+ ports,
latency,
async_start=False,
traffic_directions=2,
@@ -103,8 +102,7 @@ def simple_burst(
:param framesize: Frame size.
:param duration: Duration of traffic run in seconds (-1=infinite).
:param rate: Traffic rate [percentage, pps, bps].
- :param port_0: Port 0 on the traffic generator.
- :param port_1: Port 1 on the traffic generator.
+ :param ports: Port list on the traffic generator.
:param latency: With latency stats.
:param async_start: Start the traffic and exit.
:param traffic_directions: Bidirectional (2) or unidirectional (1) traffic.
@@ -114,8 +112,7 @@ def simple_burst(
:type framesize: int or str
:type duration: float
:type rate: str
- :type port_0: int
- :type port_1: int
+ :type ports: list
:type latency: bool
:type async_start: bool
:type traffic_directions: int
@@ -153,38 +150,47 @@ def simple_burst(
if "macsrc" in profile_file:
client.set_port_attr(promiscuous=True)
if isinstance(framesize, int):
- last_stream_a = int((len(streams) - 2) / 2)
- last_stream_b = (last_stream_a * 2)
- client.add_streams(streams[0:last_stream_a], ports=[port_0])
+ mark_a = len(streams) // 4
+ mark_b = len(streams) // 2
+ for i,j in zip(streams[:mark_a], ports[::2]):
+ client.add_streams(streams=[i], ports=[j])
if traffic_directions > 1:
- client.add_streams(
- streams[last_stream_a:last_stream_b], ports=[port_1])
+ for i,j in zip(streams[mark_a:mark_b], ports[1::2]):
+ print(i, j)
+ client.add_streams(streams=[i], ports=[j])
elif isinstance(framesize, str):
- client.add_streams(streams[0:3], ports=[port_0])
+ mark = 0
+ for i in ports[::2]:
+ client.add_streams(streams=streams[mark:mark+3], ports=[i])
+ mark = mark + 3
if traffic_directions > 1:
- client.add_streams(streams[3:6], ports=[port_1])
+ mark = len(streams) // 2
+ for i in ports[1::2]:
+ client.add_streams(streams=streams[mark:mark+3], ports=[i])
+ mark = mark + 3
if latency:
try:
if isinstance(framesize, int):
- client.add_streams(streams[last_stream_b], ports=[port_0])
+ mark_c = len(streams) // 2
+ mark_d = len(streams) // 2 + len(streams) // 4
+ for i,j in zip(streams[mark_c:mark_d], ports[::2]):
+ client.add_streams(streams=[i], ports=[j])
if traffic_directions > 1:
- client.add_streams(
- streams[last_stream_b + 1], ports=[port_1])
+ for i,j in zip(streams[mark_d:], ports[1::2]):
+ client.add_streams(streams=[i], ports=[j])
elif isinstance(framesize, str):
latency = False
except STLError:
# Disable latency if NIC does not support requested stream type
print("##### FAILED to add latency streams #####")
latency = False
- # Even for unidir, both ports are needed to see both rx and tx.
- ports = [port_0, port_1]
# Clear the stats before injecting:
client.clear_stats()
# Choose rate and start traffic:
client.start(
- ports=ports[:traffic_directions],
+ ports=ports[::] if traffic_directions == 2 else ports[::2],
mult=rate,
duration=duration,
force=force,
@@ -286,12 +292,8 @@ def main():
help="Traffic rate with included units (pps)."
)
parser.add_argument(
- "--port_0", required=True, type=int,
- help="Port 0 on the traffic generator."
- )
- parser.add_argument(
- "--port_1", required=True, type=int,
- help="Port 1 on the traffic generator."
+ "--ports", required=True, type=int, nargs="+",
+ help="Port list on the traffic generator."
)
parser.add_argument(
"--async_start", action="store_true", default=False,
@@ -326,8 +328,7 @@ def main():
duration=args.duration,
framesize=framesize,
rate=args.rate,
- port_0=args.port_0,
- port_1=args.port_1,
+ ports=args.ports,
latency=args.latency,
async_start=args.async_start,
traffic_directions=args.traffic_directions,
diff --git a/GPL/traffic_profiles/trex/profile_trex_stateless_scale_class.py b/GPL/traffic_profiles/trex/profile_trex_stateless_scale_class.py
new file mode 100644
index 0000000000..33cf090da2
--- /dev/null
+++ b/GPL/traffic_profiles/trex/profile_trex_stateless_scale_class.py
@@ -0,0 +1,196 @@
+# Copyright (c) 2023 Cisco and/or its affiliates.
+#
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# Licensed under the Apache License 2.0 or
+# GNU General Public License v2.0 or later; you may not use this file
+# except in compliance with one of these Licenses. You
+# may obtain a copy of the Licenses at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
+#
+# Note: If this file is linked with Scapy, which is GPLv2+, your use of it
+# must be under GPLv2+. If at any point in the future it is no longer linked
+# with Scapy (or other GPLv2+ licensed software), you are free to choose
+# Apache 2.
+#
+# 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.
+
+"""Base class for stream profiles for T-rex traffic generator.
+"""
+
+import socket
+import struct
+
+from random import choice
+from string import ascii_letters
+
+from trex.stl.api import *
+
+
+class TrafficStreamsScaleClass:
+ """Base class for stream profiles for T-rex traffic generator."""
+
+ STREAM_TABLE = {
+ "IMIX_v4": [
+ {"size": 60, "pps": 28, "isg": 0},
+ {"size": 590, "pps": 20, "isg": 0.1},
+ {"size": 1514, "pps": 4, "isg": 0.2}
+ ],
+ "IMIX_v4_1": [
+ {"size": 64, "pps": 28, "isg": 0},
+ {"size": 570, "pps": 16, "isg": 0.1},
+ {"size": 1518, "pps": 4, "isg": 0.2}
+ ]
+ }
+
+ def __init__(self):
+ # Default value of frame size, it will be overwritten by the value of
+ # "framesize" parameter of "get_streams" method.
+ self.framesize = 64
+
+ # If needed, add your own parameters.
+
+ def _gen_payload(self, length):
+ """Generate payload.
+
+ If needed, implement your own algorithm.
+
+ :param length: Length of generated payload.
+ :type length: int
+ :returns: The generated payload.
+ :rtype: str
+ """
+ payload = ""
+ for _ in range(length):
+ payload += choice(ascii_letters)
+
+ return payload
+
+ def _get_start_end_ipv6(self, start_ip, end_ip):
+ """Get start host and number of hosts from IPv6 as integer.
+
+ :param start_ip: Start IPv6.
+ :param end_ip: End IPv6.
+ :type start_ip: string
+ :type end_ip: string
+ :return: Start host, number of hosts.
+ :rtype tuple of int
+ :raises: ValueError if start_ip is greater then end_ip.
+ :raises: socket.error if the IP addresses are not valid IPv6 addresses.
+ """
+ try:
+ ip1 = socket.inet_pton(socket.AF_INET6, start_ip)
+ ip2 = socket.inet_pton(socket.AF_INET6, end_ip)
+
+ hi1, lo1 = struct.unpack("!QQ", ip1)
+ hi2, lo2 = struct.unpack("!QQ", ip2)
+
+ if ((hi1 << 64) | lo1) > ((hi2 << 64) | lo2):
+ raise ValueError("IPv6: start_ip is greater then end_ip")
+
+ return lo1, abs(int(lo1) - int(lo2))
+
+ except socket.error as err:
+ print(err)
+ raise
+
+ def define_packets(self):
+ """Define the packets to be sent from the traffic generator.
+
+ This method MUST return:
+
+ return base_pkt_a, base_pkt_b, vm1, vm2
+
+ vm1 and vm2 CAN be None.
+
+ :returns: Packets to be sent from the traffic generator.
+ :rtype: tuple
+ """
+ raise NotImplementedError
+
+ def create_streams(self):
+ """Create traffic streams.
+
+ Implement your own traffic streams.
+
+ :returns: Traffic streams.
+ :rtype: list
+ """
+ pkts, vms = self.define_packets()
+
+ # Frame size is defined as an integer, e.g. 64, 1518:
+ if isinstance(self.framesize, int):
+ pkt_streams = list()
+ lat_streams = list()
+ for i in range(len(pkts)):
+ payload_len = max(0, self.framesize - len(pkts[i]) - 4)
+
+ pkt = STLPktBuilder(
+ pkt=pkts[i] / self._gen_payload(payload_len),
+ vm=vms[i]
+ )
+ pkt_lat = STLPktBuilder(
+ pkt=pkts[i] / self._gen_payload(payload_len),
+ vm=vms[i]
+ )
+ pkt_streams.append(
+ STLStream(
+ packet=pkt,
+ isg=10.0 * (i // (len(pkts) // 2)),
+ mode=STLTXCont(pps=9000)
+ )
+ )
+ lat_streams.append(
+ STLStream(
+ packet=pkt_lat,
+ isg=10.0 * (i // (len(pkts) // 2)),
+ flow_stats=STLFlowLatencyStats(pg_id=i),
+ mode=STLTXCont(pps=9000)
+ )
+ )
+
+ streams = list()
+ streams.extend(pkt_streams)
+ streams.extend(lat_streams)
+ return streams
+
+ # Frame size is defined as a string, e.g.IMIX_v4_1:
+ elif isinstance(self.framesize, str):
+ pkt_streams = list()
+ for i in range(len(pkts)):
+ for stream in self.STREAM_TABLE[self.framesize]:
+ payload_len = max(0, stream["size"] - len(pkts[i]) - 4)
+
+ pkt = STLPktBuilder(
+ pkt=pkts[i] / self._gen_payload(payload_len),
+ vm=vms[i]
+ )
+ pkt_streams.append(
+ STLStream(
+ packet=pkt,
+ isg=stream["isg"],
+ mode=STLTXCont(pps=stream["pps"])
+ )
+ )
+ return pkt_streams
+
+ def get_streams(self, **kwargs):
+ """Get traffic streams created by "create_streams" method.
+
+ If needed, add your own parameters.
+
+ :param kwargs: Key-value pairs used by "create_streams" method while
+ creating streams.
+ :returns: Traffic streams.
+ :rtype: list
+ """
+ self.framesize = kwargs["framesize"]
+ self.rate = kwargs["rate"]
+
+ return self.create_streams()
diff --git a/GPL/traffic_profiles/trex/trex-stl-ethip4-ip4dst10000p3.py b/GPL/traffic_profiles/trex/trex-stl-ethip4-ip4dst10000p3.py
new file mode 100644
index 0000000000..01b6e3c55e
--- /dev/null
+++ b/GPL/traffic_profiles/trex/trex-stl-ethip4-ip4dst10000p3.py
@@ -0,0 +1,135 @@
+# Copyright (c) 2023 Cisco and/or its affiliates.
+#
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# Licensed under the Apache License 2.0 or
+# GNU General Public License v2.0 or later; you may not use this file
+# except in compliance with one of these Licenses. You
+# may obtain a copy of the Licenses at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
+#
+# Note: If this file is linked with Scapy, which is GPLv2+, your use of it
+# must be under GPLv2+. If at any point in the future it is no longer linked
+# with Scapy (or other GPLv2+ licensed software), you are free to choose
+# Apache 2.
+#
+# 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.
+
+"""Stream profile for T-rex traffic generator.
+
+Stream profile:
+ - Three parallel bi-directional streams sent as W --> E and E --> W
+ at the same time.
+ - Packet: ETH / IP /
+"""
+
+from trex.stl.api import *
+from profile_trex_stateless_scale_class import TrafficStreamsScaleClass
+
+
+class TrafficStreams(TrafficStreamsScaleClass):
+ """Stream profile."""
+
+ def __init__(self):
+ """Initialization and setting of streams' parameters."""
+
+ super(TrafficStreamsScaleClass, self).__init__()
+
+ self.pkt_data = [
+ # Direction W --> E:
+ {
+ "src_start_ip": "10.0.0.1",
+ "dst_start_ip": "20.0.0.0",
+ "dst_end_ip": "20.0.39.15"
+ },
+ # Direction W --> E:
+ {
+ "src_start_ip": "30.0.0.1",
+ "dst_start_ip": "40.0.0.0",
+ "dst_end_ip": "40.0.39.15"
+ },
+ # Direction W --> E:
+ {
+ "src_start_ip": "50.0.0.1",
+ "dst_start_ip": "60.0.0.0",
+ "dst_end_ip": "60.0.39.15"
+ },
+ # Direction E --> W:
+ {
+ "src_start_ip": "20.0.0.1",
+ "dst_start_ip": "10.0.0.0",
+ "dst_end_ip": "10.0.39.15"
+ },
+ # Direction E --> W:
+ {
+ "src_start_ip": "40.0.0.1",
+ "dst_start_ip": "30.0.0.0",
+ "dst_end_ip": "30.0.39.15"
+ },
+ # Direction E --> W:
+ {
+ "src_start_ip": "60.0.0.1",
+ "dst_start_ip": "50.0.0.0",
+ "dst_end_ip": "50.0.39.15"
+ }
+
+ ]
+ self.pkt_base = []
+ self.pkt_vm = []
+
+ def define_packets(self):
+ """Defines the packets to be sent from the traffic generator.
+
+ Packet definition: | ETH | IP |
+
+ :returns: Base packets to be sent and transformation function.
+ :rtype: tuple
+ """
+ for i in range(len(self.pkt_data)):
+ self.pkt_base.append(
+ Ether() /
+ IP(
+ src=self.pkt_data[i]["src_start_ip"],
+ dst=self.pkt_data[i]["dst_start_ip"],
+ proto=61
+ )
+ )
+ self.pkt_vm.append(
+ STLScVmRaw(
+ [
+ STLVmFlowVar(
+ name="dst",
+ min_value=self.pkt_data[i]["dst_start_ip"],
+ max_value=self.pkt_data[i]["dst_end_ip"],
+ size=4,
+ op="inc"
+ ),
+ STLVmWrFlowVar(
+ fv_name="dst",
+ pkt_offset="IP.dst"
+ ),
+ STLVmFixIpv4(
+ offset="IP"
+ )
+ ]
+ )
+ )
+
+ return self.pkt_base, self.pkt_vm
+
+
+def register():
+ """Register this traffic profile to T-Rex.
+
+ Do not change this function.
+
+ :return: Traffic streams.
+ :rtype: Object
+ """
+ return TrafficStreams()