From: Nicholas Pratte <[email protected]> Rework TG class hierarchy to include performance traffic generators. As such, methods specific to capturing traffic have been moved to the CapturingTrafficGenerator subclass.
Bugzilla ID: 1697 Signed-off-by: Nicholas Pratte <[email protected]> Signed-off-by: Patrick Robb <[email protected]> Reviewed-by: Dean Marx <[email protected]> --- .../capturing_traffic_generator.py | 34 ++++++++++ .../performance_traffic_generator.py | 63 +++++++++++++++++++ .../traffic_generator/traffic_generator.py | 38 ----------- 3 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 dts/framework/testbed_model/traffic_generator/performance_traffic_generator.py diff --git a/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py index ec0993e6b7..734a66d1f3 100644 --- a/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py +++ b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generator.py @@ -65,6 +65,40 @@ def is_capturing(self) -> bool: """This traffic generator can capture traffic.""" return True + def send_packet(self, packet: Packet, port: Port) -> None: + """Send `packet` and block until it is fully sent. + + Send `packet` on `port`, then wait until `packet` is fully sent. + + Args: + packet: The packet to send. + port: The egress port on the TG node. + """ + self.send_packets([packet], port) + + def send_packets(self, packets: list[Packet], port: Port) -> None: + """Send `packets` and block until they are fully sent. + + Send `packets` on `port`, then wait until `packets` are fully sent. + + Args: + packets: The packets to send. + port: The egress port on the TG node. + """ + self._logger.info(f"Sending packet{'s' if len(packets) > 1 else ''}.") + self._logger.debug(get_packet_summaries(packets)) + self._send_packets(packets, port) + + @abstractmethod + def _send_packets(self, packets: list[Packet], port: Port) -> None: + """The implementation of :method:`send_packets`. + + The subclasses must implement this method which sends `packets` on `port`. + The method should block until all `packets` are fully sent. + + What fully sent means is defined by the traffic generator. + """ + def send_packets_and_capture( self, packets: list[Packet], diff --git a/dts/framework/testbed_model/traffic_generator/performance_traffic_generator.py b/dts/framework/testbed_model/traffic_generator/performance_traffic_generator.py new file mode 100644 index 0000000000..6b23faa1a5 --- /dev/null +++ b/dts/framework/testbed_model/traffic_generator/performance_traffic_generator.py @@ -0,0 +1,63 @@ +"""Traffic generators for performance tests which can generate a high number of packets.""" + +from abc import abstractmethod +from dataclasses import dataclass + +from scapy.packet import Packet + +from framework.testbed_model.topology import Topology + +from .traffic_generator import TrafficGenerator + + +@dataclass(slots=True) +class PerformanceTrafficStats: + """Data structure to store performance statistics for a given test run. + + Attributes: + tx_pps: Recorded tx packets per second + tx_bps: Recorded tx bytes per second + rx_pps: Recorded rx packets per second + rx_bps: Recorded rx bytes per second + frame_size: The total length of the frame + """ + + tx_pps: float + tx_bps: float + rx_pps: float + rx_bps: float + + frame_size: int | None = None + + +class PerformanceTrafficGenerator(TrafficGenerator): + """An abstract base class for all performance-oriented traffic generators. + + Provides an intermediary interface for performance-based traffic generator. + """ + + @abstractmethod + def calculate_traffic_and_stats( + self, + packet: Packet, + duration: float, + send_mpps: int | None = None, + ) -> PerformanceTrafficStats: + """Send packet traffic and acquire associated statistics. + + If `send_mpps` is provided, attempt to transmit traffic at the `send_mpps` rate. + Otherwise, attempt to transmit at line rate. + + Args: + packet: The packet to send. + duration: Performance test duration (in seconds). + send_mpps: The millions packets per second send rate. + + Returns: + Performance statistics of the generated test. + """ + + def setup(self, topology: Topology) -> None: + """Overrides :meth:`.traffic_generator.TrafficGenerator.setup`.""" + for port in self._tg_node.ports: + self._tg_node.main_session.configure_port_mtu(2000, port) diff --git a/dts/framework/testbed_model/traffic_generator/traffic_generator.py b/dts/framework/testbed_model/traffic_generator/traffic_generator.py index cac119c183..e5f246df7a 100644 --- a/dts/framework/testbed_model/traffic_generator/traffic_generator.py +++ b/dts/framework/testbed_model/traffic_generator/traffic_generator.py @@ -11,14 +11,10 @@ from abc import ABC, abstractmethod from typing import Any -from scapy.packet import Packet - from framework.config.test_run import TrafficGeneratorConfig from framework.logger import DTSLogger, get_dts_logger from framework.testbed_model.node import Node -from framework.testbed_model.port import Port from framework.testbed_model.topology import Topology -from framework.utils import get_packet_summaries class TrafficGenerator(ABC): @@ -57,40 +53,6 @@ def teardown(self) -> None: """Teardown the traffic generator.""" self.close() - def send_packet(self, packet: Packet, port: Port) -> None: - """Send `packet` and block until it is fully sent. - - Send `packet` on `port`, then wait until `packet` is fully sent. - - Args: - packet: The packet to send. - port: The egress port on the TG node. - """ - self.send_packets([packet], port) - - def send_packets(self, packets: list[Packet], port: Port) -> None: - """Send `packets` and block until they are fully sent. - - Send `packets` on `port`, then wait until `packets` are fully sent. - - Args: - packets: The packets to send. - port: The egress port on the TG node. - """ - self._logger.info(f"Sending packet{'s' if len(packets) > 1 else ''}.") - self._logger.debug(get_packet_summaries(packets)) - self._send_packets(packets, port) - - @abstractmethod - def _send_packets(self, packets: list[Packet], port: Port) -> None: - """The implementation of :method:`send_packets`. - - The subclasses must implement this method which sends `packets` on `port`. - The method should block until all `packets` are fully sent. - - What fully sent means is defined by the traffic generator. - """ - @property def is_capturing(self) -> bool: """This traffic generator can't capture traffic.""" -- 2.49.0

