aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Mikus <peter.mikus@protonmail.ch>2024-11-18 09:32:32 +0100
committerPeter Mikus <peter.mikus@protonmail.ch>2024-11-18 12:04:21 +0000
commit309ceb0d58739b910d5474d1462cde2a6791e6fa (patch)
tree01ab824399d4708a479d2b618af192529d3fb766
parent33e60e62e1c42dfcb3d80a9941d75b24126fa1e5 (diff)
feat(core): IMIX stream dynamic
Signed-off-by: Peter Mikus <peter.mikus@protonmail.ch> Change-Id: Ib1f68a853012ee08688115e1c021756a18f5cb04
-rw-r--r--GPL/tools/trex/trex_stl_profile.py13
-rw-r--r--GPL/traffic_profiles/trex/TrafficStreamsJsonClass.py106
-rw-r--r--GPL/traffic_profiles/trex/trex-stl-json-geneve.py179
3 files changed, 294 insertions, 4 deletions
diff --git a/GPL/tools/trex/trex_stl_profile.py b/GPL/tools/trex/trex_stl_profile.py
index e3a3c8c0f9..772c656a07 100644
--- a/GPL/tools/trex/trex_stl_profile.py
+++ b/GPL/tools/trex/trex_stl_profile.py
@@ -160,14 +160,19 @@ def simple_burst(
client.add_streams(streams=[i], ports=[j])
elif isinstance(framesize, str):
mark = 0
+ strp = len(streams) // len(ports)
for i in ports[::2]:
- client.add_streams(streams=streams[mark:mark+3], ports=[i])
- mark = mark + 3
+ client.add_streams(
+ streams=streams[mark:mark+strp], ports=[i]
+ )
+ mark = mark + strp
if traffic_directions > 1:
mark = len(streams) // 2
for i in ports[1::2]:
- client.add_streams(streams=streams[mark:mark+3], ports=[i])
- mark = mark + 3
+ client.add_streams(
+ streams=streams[mark:mark+strp], ports=[i]
+ )
+ mark = mark + strp
if latency:
try:
if isinstance(framesize, int):
diff --git a/GPL/traffic_profiles/trex/TrafficStreamsJsonClass.py b/GPL/traffic_profiles/trex/TrafficStreamsJsonClass.py
new file mode 100644
index 0000000000..9ba3c31658
--- /dev/null
+++ b/GPL/traffic_profiles/trex/TrafficStreamsJsonClass.py
@@ -0,0 +1,106 @@
+# Copyright (c) 2024 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 json
+import os
+
+from trex.stl.api import *
+
+CP = os.path.join(os.path.abspath(os.sep), "etc")
+
+
+class TrafficStreamsJsonClass:
+ """Base class for stream profiles for T-rex traffic generator."""
+
+ 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
+
+ def define_packets(self):
+ """Define the packets to be sent from the traffic generator.
+
+ This method MUST return:
+
+ return pkt, vm
+
+ :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
+ """
+ pkt_streams = []
+ lat_streams = []
+
+ with open(os.path.join(CP, "packet-profile.json")) as packets_json:
+ packets_data = json.load(packets_json)
+
+ for profile in packets_data["profiles"]:
+ for i, stream in enumerate(profile["streams"]):
+ self.stream_data = stream
+ pkt, vm = self.define_packets()
+ packet = STLPktBuilder(pkt=pkt, vm=vm)
+ pkt_streams.append(
+ STLStream(
+ packet=packet,
+ mode=STLTXCont(pps=9000)
+ )
+ )
+ lat_streams.append(
+ STLStream(
+ packet=packet,
+ flow_stats=STLFlowLatencyStats(pg_id=i),
+ mode=STLTXCont(pps=9000)
+ )
+ )
+
+ streams = []
+ streams.extend(pkt_streams)
+ streams.extend(lat_streams)
+ return 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-json-geneve.py b/GPL/traffic_profiles/trex/trex-stl-json-geneve.py
new file mode 100644
index 0000000000..10d41d15da
--- /dev/null
+++ b/GPL/traffic_profiles/trex/trex-stl-json-geneve.py
@@ -0,0 +1,179 @@
+# Copyright (c) 2024 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:
+ - Packet: ETH / IP / UDP / GENEVE
+"""
+
+import ipaddress
+
+from scapy.all import (
+ Packet, BitField, XShortField, ThreeBytesField, XByteField, Raw
+)
+from scapy.contrib.geneve import GENEVE
+from scapy.layers.l2 import Ether
+from scapy.layers.inet import IP, UDP
+from scapy.layers.inet6 import IPv6
+
+from trex.stl.api import *
+from TrafficStreamsJsonClass import TrafficStreamsJsonClass
+
+
+class Geneve(Packet):
+ """Defines custom Geneve Class."""
+ name = "Geneve"
+ fields_desc = [
+ BitField("version", 0, 2),
+ BitField("optionlen", 0, 6),
+ BitField("oam", 0, 1),
+ BitField("critical", 0, 1),
+ BitField("reserved", 0, 6),
+ XShortField("proto", 0x6558),
+ ThreeBytesField("vni", 0),
+ XByteField("reserved2", 0x00)
+ ]
+
+
+class TrafficStreams(TrafficStreamsJsonClass):
+ """Stream profile."""
+
+ def __init__(self):
+ """Initialization and setting of streams' parameters."""
+
+ super(TrafficStreamsJsonClass, self).__init__()
+
+ def new_packet_header(self, key):
+ """Define the packet modifications.
+
+ :returns: List of VMs to be sent from the traffic generator.
+ :rtype: list
+ """
+ header_data = self.stream_data[key]
+ vm = []
+ for vm_entry in header_data:
+ value_list, size, offset = (
+ vm_entry["value-list"],
+ vm_entry["size"],
+ vm_entry["offset"]
+ )
+ # reserved mac address size is 8 bytes so fill the rest with zeros
+ if "mac" in vm_entry["name"]:
+ for i, value in enumerate(vm_entry["value-list"]):
+ value += ":00:00"
+ value_list[i] = int(value.lower().replace(':', ''), 16)
+ # replace only the second part of the IPv6 address
+ if "ip" in vm_entry["name"] and vm_entry["size"] == 16:
+ for i, value in enumerate(vm_entry["value-list"]):
+ value_list[i] = int.from_bytes(
+ ipaddress.IPv6Address(value).packed[8:],
+ byteorder="big"
+ )
+ size, offset = 8, offset + 8
+ vm.append(STLVmFlowVar(
+ name=vm_entry["name"],
+ value_list=value_list,
+ size=size,
+ op=vm_entry["op"]),
+ )
+ vm.append(STLVmWrFlowVar(
+ fv_name=vm_entry["name"],
+ pkt_offset=offset),
+ )
+ return vm
+
+ def define_packets(self):
+ """Defines the packets to be sent from the traffic generator.
+
+ :returns: Base packets to be sent and transformation function.
+ :rtype: tuple
+ """
+ base_pkt_data = self.stream_data["base-packet"]
+ base_pkt = (
+ Ether(
+ src=base_pkt_data["outer-eth"]["src"],
+ dst=base_pkt_data["outer-eth"]["dst"],
+ ) /
+ IP(
+ src=base_pkt_data["outer-ip"]["src"],
+ dst=base_pkt_data["outer-ip"]["dst"],
+ ) /
+ UDP(
+ sport=int(base_pkt_data["outer-udp"]["src"]),
+ dport=int(base_pkt_data["outer-udp"]["dst"]),
+ ) /
+ GENEVE(
+ # proto = 0x86dd,
+ vni=base_pkt_data["encap-vni"],
+ )
+ )
+ if "inner-eth" in base_pkt_data:
+ base_pkt = base_pkt / (
+ Ether(
+ src=base_pkt_data["inner-eth"]["src"],
+ dst=base_pkt_data["inner-eth"]["dst"],
+ )
+ )
+
+ if ipaddress.ip_address(base_pkt_data["inner-ip"]["src"]).version == 6:
+ base_pkt = base_pkt / (
+ IPv6(
+ src=base_pkt_data["inner-ip"]["src"],
+ dst=base_pkt_data["inner-ip"]["dst"],
+ )
+ )
+ else:
+ base_pkt = base_pkt / (
+ IP(
+ src=base_pkt_data["inner-ip"]["src"],
+ dst=base_pkt_data["inner-ip"]["dst"],
+ )
+ )
+ base_pkt = base_pkt / (
+ UDP(
+ sport=int(base_pkt_data["inner-udp"]["src"]),
+ dport=int(base_pkt_data["inner-udp"]["dst"]),
+ )
+ )
+ length = self.stream_data["base-packet"]["length"]
+ pkt = base_pkt / Raw(load="X" * (length - len(base_pkt)))
+
+ outer_header_data = self.new_packet_header("outer-header")
+ if "inner-l2-header" in self.stream_data:
+ inner_header_data = self.new_packet_header("inner-l2-header")
+ else:
+ inner_header_data = self.new_packet_header("inner-l3-header")
+ vm = STLScVmRaw(outer_header_data + inner_header_data)
+ return pkt, vm
+
+
+def register():
+ """Register this traffic profile to T-Rex.
+
+ Do not change this function.
+
+ :return: Traffic streams.
+ :rtype: Object
+ """
+ return TrafficStreams()