From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id EC2FF43421; Fri, 1 Dec 2023 19:05:43 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 73E8540298; Fri, 1 Dec 2023 19:05:43 +0100 (CET) Received: from mail-pj1-f45.google.com (mail-pj1-f45.google.com [209.85.216.45]) by mails.dpdk.org (Postfix) with ESMTP id 6E5304025F for ; Fri, 1 Dec 2023 19:05:42 +0100 (CET) Received: by mail-pj1-f45.google.com with SMTP id 98e67ed59e1d1-280351c32afso2267817a91.1 for ; Fri, 01 Dec 2023 10:05:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1701453941; x=1702058741; darn=dpdk.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=gbt6pGMXB/qld2U6dQ1E1hJUXjJ9HQTv1gaXY61Oe9E=; b=HNB2xgzwycB3Apj6Df74EylwLBH8jIda+E5UD1hma63MSipaHJzpDIgIIUQi18SkpZ TmAs90vJex1pUZGVgyGFFTUXoqFnYX4QZU1FyxEj0VmsL1KFMuk4BgLbxA8gwSrDgImG wACmUzcq8daixVbHCWTlCPAljrcxlyUeBD4bg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701453941; x=1702058741; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=gbt6pGMXB/qld2U6dQ1E1hJUXjJ9HQTv1gaXY61Oe9E=; b=a2Vk/g8fL1+ZrRk/j62gCYcmPorReKxnqpKz0NoPEzBl0DmZdIcdQQXuGcf5TX/9a6 9r9SV4sZUThOVYwBMkmJ0TCaIgDPIwfG75gwJXa2gRC44jOQOK/LlWN4oWOhejnVicgi EE/05Y0tkxYKRXvqngnNmdZX0zneUDdD9igklH8pOopk2s0W412iKQAzzXuzYbai7GAN v82+Gp7lNy/nCRTpOD9gfxU+MERBOo1bY8vNHdLYngEp03jIFpVG+bj8B5eRbtQBKQ7r azeEGiqlH4n3X44TDFNCtCTwoGEqpRBjcANRBgX9JAD/82gyBO4WZcGjeKx/br1n74l5 iMAQ== X-Gm-Message-State: AOJu0YyJU4o687A8DBnq0yGBiiuockBTezBmIS4q+fRAW6oh44Il7RND 9lVKq6msEw66V/OdsN4qMKwCxJ4uMhojsC0KLEdY9Q== X-Google-Smtp-Source: AGHT+IHvUVKKsD4FPV3X4qI5RCYYFy7y0+hnOqtY+e54dB8hIPwrwcbzsZaEzzrKru1sbIMGPy6gCbAHauL6hBi66Tg= X-Received: by 2002:a17:90b:1d0a:b0:285:75ab:40b9 with SMTP id on10-20020a17090b1d0a00b0028575ab40b9mr26543161pjb.14.1701453941430; Fri, 01 Dec 2023 10:05:41 -0800 (PST) MIME-Version: 1.0 References: <20231115130959.39420-1-juraj.linkes@pantheon.tech> <20231123151344.162812-1-juraj.linkes@pantheon.tech> <20231123151344.162812-20-juraj.linkes@pantheon.tech> In-Reply-To: <20231123151344.162812-20-juraj.linkes@pantheon.tech> From: Jeremy Spewock Date: Fri, 1 Dec 2023 13:05:30 -0500 Message-ID: Subject: Re: [PATCH v8 19/21] dts: base traffic generators docstring update To: =?UTF-8?Q?Juraj_Linke=C5=A1?= Cc: thomas@monjalon.net, Honnappa.Nagarahalli@arm.com, probb@iol.unh.edu, paul.szczepanek@arm.com, yoan.picchi@foss.arm.com, Luca.Vizzarro@arm.com, dev@dpdk.org Content-Type: multipart/alternative; boundary="000000000000c7f30c060b769dd8" X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org --000000000000c7f30c060b769dd8 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, Nov 23, 2023 at 10:14=E2=80=AFAM Juraj Linke=C5=A1 wrote: > Format according to the Google format and PEP257, with slight > deviations. > > Signed-off-by: Juraj Linke=C5=A1 > --- > .../traffic_generator/__init__.py | 22 ++++++++- > .../capturing_traffic_generator.py | 45 +++++++++++-------- > .../traffic_generator/traffic_generator.py | 33 ++++++++------ > 3 files changed, 67 insertions(+), 33 deletions(-) > > diff --git a/dts/framework/testbed_model/traffic_generator/__init__.py > b/dts/framework/testbed_model/traffic_generator/__init__.py > index 52888d03fa..11e2bd7d97 100644 > --- a/dts/framework/testbed_model/traffic_generator/__init__.py > +++ b/dts/framework/testbed_model/traffic_generator/__init__.py > @@ -1,6 +1,19 @@ > # SPDX-License-Identifier: BSD-3-Clause > # Copyright(c) 2023 PANTHEON.tech s.r.o. > > +"""DTS traffic generators. > + > +A traffic generator is capable of generating traffic and then monitor > returning traffic. > +All traffic generators must count the number of received packets. Some > may additionally capture > +individual packets. > + > +A traffic generator may be software running on generic hardware or it > could be specialized hardware. > + > +The traffic generators that only count the number of received packets ar= e > suitable only for > +performance testing. In functional testing, we need to be able to dissec= t > each arrived packet > +and a capturing traffic generator is required. > +""" > + > from framework.config import ScapyTrafficGeneratorConfig, > TrafficGeneratorType > from framework.exception import ConfigurationError > from framework.testbed_model.node import Node > @@ -12,8 +25,15 @@ > def create_traffic_generator( > tg_node: Node, traffic_generator_config: ScapyTrafficGeneratorConfig > ) -> CapturingTrafficGenerator: > - """A factory function for creating traffic generator object from use= r > config.""" > + """The factory function for creating traffic generator objects from > the test run configuration. > + > + Args: > + tg_node: The traffic generator node where the created traffic > generator will be running. > + traffic_generator_config: The traffic generator config. > > + Returns: > + A traffic generator capable of capturing received packets. > + """ > match traffic_generator_config.traffic_generator_type: > case TrafficGeneratorType.SCAPY: > return ScapyTrafficGenerator(tg_node, > traffic_generator_config) > diff --git > a/dts/framework/testbed_model/traffic_generator/capturing_traffic_generat= or.py > b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generat= or.py > index 1fc7f98c05..0246590333 100644 > --- > a/dts/framework/testbed_model/traffic_generator/capturing_traffic_generat= or.py > +++ > b/dts/framework/testbed_model/traffic_generator/capturing_traffic_generat= or.py > @@ -23,19 +23,21 @@ > > > def _get_default_capture_name() -> str: > - """ > - This is the function used for the default implementation of capture > names. > - """ > return str(uuid.uuid4()) > > > class CapturingTrafficGenerator(TrafficGenerator): > """Capture packets after sending traffic. > > - A mixin interface which enables a packet generator to declare that i= t > can capture > + The intermediary interface which enables a packet generator to > declare that it can capture > packets and return them to the user. > > + Similarly to :class:`~.traffic_generator.TrafficGenerator`, this > class exposes > + the public methods specific to capturing traffic generators and > defines a private method > + that must implement the traffic generation and capturing logic in > subclasses. > + > The methods of capturing traffic generators obey the following > workflow: > + > 1. send packets > 2. capture packets > 3. write the capture to a .pcap file > @@ -44,6 +46,7 @@ class CapturingTrafficGenerator(TrafficGenerator): > > @property > def is_capturing(self) -> bool: > + """This traffic generator can capture traffic.""" > return True > > def send_packet_and_capture( > @@ -54,11 +57,12 @@ def send_packet_and_capture( > duration: float, > capture_name: str =3D _get_default_capture_name(), > ) -> list[Packet]: > - """Send a packet, return received traffic. > + """Send `packet` and capture received traffic. > + > + Send `packet` on `send_port` and then return all traffic capture= d > + on `receive_port` for the given `duration`. > > - Send a packet on the send_port and then return all traffic > captured > - on the receive_port for the given duration. Also record the > captured traffic > - in a pcap file. > + The captured traffic is recorded in the `capture_name`.pcap file= . > > Args: > packet: The packet to send. > @@ -68,7 +72,7 @@ def send_packet_and_capture( > capture_name: The name of the .pcap file where to store the > capture. > > Returns: > - A list of received packets. May be empty if no packets are > captured. > + The received packets. May be empty if no packets are > captured. > """ > return self.send_packets_and_capture( > [packet], send_port, receive_port, duration, capture_name > @@ -82,11 +86,14 @@ def send_packets_and_capture( > duration: float, > capture_name: str =3D _get_default_capture_name(), > ) -> list[Packet]: > - """Send packets, return received traffic. > + """Send `packets` and capture received traffic. > > - Send packets on the send_port and then return all traffic captur= ed > - on the receive_port for the given duration. Also record the > captured traffic > - in a pcap file. > + Send `packets` on `send_port` and then return all traffic captur= ed > + on `receive_port` for the given `duration`. > + > + The captured traffic is recorded in the `capture_name`.pcap file= . > The target directory > + can be configured with the :option:`--output-dir` command line > argument or > + the :envvar:`DTS_OUTPUT_DIR` environment variable. > > Args: > packets: The packets to send. > @@ -96,7 +103,7 @@ def send_packets_and_capture( > capture_name: The name of the .pcap file where to store the > capture. > > Returns: > - A list of received packets. May be empty if no packets are > captured. > + The received packets. May be empty if no packets are > captured. > """ > self._logger.debug(get_packet_summaries(packets)) > self._logger.debug( > @@ -121,10 +128,12 @@ def _send_packets_and_capture( > receive_port: Port, > duration: float, > ) -> list[Packet]: > - """ > - The extended classes must implement this method which > - sends packets on send_port and receives packets on the > receive_port > - for the specified duration. It must be able to handle no receive= d > packets. > + """The implementation of :method:`send_packets_and_capture`. > + > + The subclasses must implement this method which sends `packets` > on `send_port` > + and receives packets on `receive_port` for the specified > `duration`. > + > + It must be able to handle receiving no packets. > """ > > def _write_capture_from_packets(self, capture_name: str, packets: > list[Packet]) -> None: > diff --git > a/dts/framework/testbed_model/traffic_generator/traffic_generator.py > b/dts/framework/testbed_model/traffic_generator/traffic_generator.py > index 0d9902ddb7..5fb9824568 100644 > --- a/dts/framework/testbed_model/traffic_generator/traffic_generator.py > +++ b/dts/framework/testbed_model/traffic_generator/traffic_generator.py > @@ -22,7 +22,8 @@ > class TrafficGenerator(ABC): > """The base traffic generator. > > - Defines the few basic methods that each traffic generator must > implement. > + Exposes the common public methods of all traffic generators and > defines private methods > + that must implement the traffic generation logic in subclasses. > """ > > _config: TrafficGeneratorConfig > @@ -30,14 +31,20 @@ class TrafficGenerator(ABC): > _logger: DTSLOG > > def __init__(self, tg_node: Node, config: TrafficGeneratorConfig): > + """Initialize the traffic generator. > + > + Args: > + tg_node: The traffic generator node where the created traffi= c > generator will be running. > + config: The traffic generator's test run configuration. > + """ > self._config =3D config > self._tg_node =3D tg_node > self._logger =3D getLogger(f"{self._tg_node.name} > {self._config.traffic_generator_type}") > > def send_packet(self, packet: Packet, port: Port) -> None: > - """Send a packet and block until it is fully sent. > + """Send `packet` and block until it is fully sent. > > - What fully sent means is defined by the traffic generator. > + Send `packet` on `port`, then wait until `packet` is fully sent. > > Args: > packet: The packet to send. > @@ -46,9 +53,9 @@ def send_packet(self, packet: Packet, port: Port) -> > None: > 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` and block until they are fully sent. > > - What fully sent means is defined by the traffic generator. > + Send `packets` on `port`, then wait until `packets` are fully > sent. > > Args: > packets: The packets to send. > @@ -60,19 +67,17 @@ def send_packets(self, packets: list[Packet], port: > Port) -> None: > > @abstractmethod > def _send_packets(self, packets: list[Packet], port: Port) -> None: > - """ > - The extended classes must implement this method which > - sends packets on send_port. The method should block until all > packets > - are fully sent. > + """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 full sent means is defined by the traffic generator. > """ > I think this should be "what fully sent means" > @property > def is_capturing(self) -> bool: > - """Whether this traffic generator can capture traffic. > - > - Returns: > - True if the traffic generator can capture traffic, False > otherwise. > - """ > + """This traffic generator can't capture traffic.""" > return False > > @abstractmethod > -- > 2.34.1 > > --000000000000c7f30c060b769dd8 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


<= div dir=3D"ltr" class=3D"gmail_attr">On Thu, Nov 23, 2023 at 10:14=E2=80=AF= AM Juraj Linke=C5=A1 <juraj.linkes@pantheon.tech> wrote:
Format according to the Goog= le format and PEP257, with slight
deviations.

Signed-off-by: Juraj Linke=C5=A1 <juraj.linkes@pantheon.tech>
---
=C2=A0.../traffic_generator/__init__.py=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0| 22 ++++++++-
=C2=A0.../capturing_traffic_generator.py=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 | 45 +++++++++++--------
=C2=A0.../traffic_generator/traffic_generator.py=C2=A0 =C2=A0 | 33 ++++++++= ------
=C2=A03 files changed, 67 insertions(+), 33 deletions(-)

diff --git a/dts/framework/testbed_model/traffic_generator/__init__.py b/dt= s/framework/testbed_model/traffic_generator/__init__.py
index 52888d03fa..11e2bd7d97 100644
--- a/dts/framework/testbed_model/traffic_generator/__init__.py
+++ b/dts/framework/testbed_model/traffic_generator/__init__.py
@@ -1,6 +1,19 @@
=C2=A0# SPDX-License-Identifier: BSD-3-Clause
=C2=A0# Copyright(c) 2023 PANTHEON.tech s.r.o.

+"""DTS traffic generators.
+
+A traffic generator is capable of generating traffic and then monitor retu= rning traffic.
+All traffic generators must count the number of received packets. Some may= additionally capture
+individual packets.
+
+A traffic generator may be software running on generic hardware or it coul= d be specialized hardware.
+
+The traffic generators that only count the number of received packets are = suitable only for
+performance testing. In functional testing, we need to be able to dissect = each arrived packet
+and a capturing traffic generator is required.
+"""
+
=C2=A0from framework.config import ScapyTrafficGeneratorConfig, TrafficGene= ratorType
=C2=A0from framework.exception import ConfigurationError
=C2=A0from framework.testbed_model.node import Node
@@ -12,8 +25,15 @@
=C2=A0def create_traffic_generator(
=C2=A0 =C2=A0 =C2=A0tg_node: Node, traffic_generator_config: ScapyTrafficGe= neratorConfig
=C2=A0) -> CapturingTrafficGenerator:
-=C2=A0 =C2=A0 """A factory function for creating traffic ge= nerator object from user config."""
+=C2=A0 =C2=A0 """The factory function for creating traffic = generator objects from the test run configuration.
+
+=C2=A0 =C2=A0 Args:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 tg_node: The traffic generator node where the = created traffic generator will be running.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 traffic_generator_config: The traffic generato= r config.

+=C2=A0 =C2=A0 Returns:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 A traffic generator capable of capturing recei= ved packets.
+=C2=A0 =C2=A0 """
=C2=A0 =C2=A0 =C2=A0match traffic_generator_config.traffic_generator_type:<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case TrafficGeneratorType.SCAPY:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return ScapyTrafficGenerato= r(tg_node, traffic_generator_config)
diff --git a/dts/framework/testbed_model/traffic_generator/capturing_traffi= c_generator.py b/dts/framework/testbed_model/traffic_generator/capturing_tr= affic_generator.py
index 1fc7f98c05..0246590333 100644
--- a/dts/framework/testbed_model/traffic_generator/capturing_traffic_gener= ator.py
+++ b/dts/framework/testbed_model/traffic_generator/capturing_traffic_gener= ator.py
@@ -23,19 +23,21 @@


=C2=A0def _get_default_capture_name() -> str:
-=C2=A0 =C2=A0 """
-=C2=A0 =C2=A0 This is the function used for the default implementation of = capture names.
-=C2=A0 =C2=A0 """
=C2=A0 =C2=A0 =C2=A0return str(uuid.uuid4())


=C2=A0class CapturingTrafficGenerator(TrafficGenerator):
=C2=A0 =C2=A0 =C2=A0"""Capture packets after sending traffic= .

-=C2=A0 =C2=A0 A mixin interface which enables a packet generator to declar= e that it can capture
+=C2=A0 =C2=A0 The intermediary interface which enables a packet generator = to declare that it can capture
=C2=A0 =C2=A0 =C2=A0packets and return them to the user.

+=C2=A0 =C2=A0 Similarly to :class:`~.traffic_generator.TrafficGenerator`, = this class exposes
+=C2=A0 =C2=A0 the public methods specific to capturing traffic generators = and defines a private method
+=C2=A0 =C2=A0 that must implement the traffic generation and capturing log= ic in subclasses.
+
=C2=A0 =C2=A0 =C2=A0The methods of capturing traffic generators obey the fo= llowing workflow:
+
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A01. send packets
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A02. capture packets
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A03. write the capture to a .pcap file
@@ -44,6 +46,7 @@ class CapturingTrafficGenerator(TrafficGenerator):

=C2=A0 =C2=A0 =C2=A0@property
=C2=A0 =C2=A0 =C2=A0def is_capturing(self) -> bool:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """This traffic generator can c= apture traffic."""
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return True

=C2=A0 =C2=A0 =C2=A0def send_packet_and_capture(
@@ -54,11 +57,12 @@ def send_packet_and_capture(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0duration: float,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0capture_name: str =3D _get_default_captur= e_name(),
=C2=A0 =C2=A0 =C2=A0) -> list[Packet]:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send a packet, return receiv= ed traffic.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send `packet` and capture re= ceived traffic.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 Send `packet` on `send_port` and then return a= ll traffic captured
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 on `receive_port` for the given `duration`.
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 Send a packet on the send_port and then return= all traffic captured
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 on the receive_port for the given duration. Al= so record the captured traffic
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 in a pcap file.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 The captured traffic is recorded in the `captu= re_name`.pcap file.

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Args:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0packet: The packet to send.=
@@ -68,7 +72,7 @@ def send_packet_and_capture(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0capture_name: The name of t= he .pcap file where to store the capture.

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Returns:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0A list of received packets= . May be empty if no packets are captured.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The received packets. May = be empty if no packets are captured.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"""
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return self.send_packets_and_capture(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0[packet], send_port, receiv= e_port, duration, capture_name
@@ -82,11 +86,14 @@ def send_packets_and_capture(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0duration: float,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0capture_name: str =3D _get_default_captur= e_name(),
=C2=A0 =C2=A0 =C2=A0) -> list[Packet]:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send packets, return receive= d traffic.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send `packets` and capture r= eceived traffic.

-=C2=A0 =C2=A0 =C2=A0 =C2=A0 Send packets on the send_port and then return = all traffic captured
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 on the receive_port for the given duration. Al= so record the captured traffic
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 in a pcap file.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 Send `packets` on `send_port` and then return = all traffic captured
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 on `receive_port` for the given `duration`. +
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 The captured traffic is recorded in the `captu= re_name`.pcap file. The target directory
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 can be configured with the :option:`--output-d= ir` command line argument or
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 the :envvar:`DTS_OUTPUT_DIR` environment varia= ble.

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Args:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0packets: The packets to sen= d.
@@ -96,7 +103,7 @@ def send_packets_and_capture(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0capture_name: The name of t= he .pcap file where to store the capture.

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Returns:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0A list of received packets= . May be empty if no packets are captured.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0The received packets. May = be empty if no packets are captured.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"""
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0self._logger.debug(get_packet_summaries(p= ackets))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0self._logger.debug(
@@ -121,10 +128,12 @@ def _send_packets_and_capture(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0receive_port: Port,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0duration: float,
=C2=A0 =C2=A0 =C2=A0) -> list[Packet]:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 The extended classes must implement this metho= d which
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 sends packets on send_port and receives packet= s on the receive_port
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 for the specified duration. It must be able to= handle no received packets.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """The implementation of :metho= d:`send_packets_and_capture`.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 The subclasses must implement this method whic= h sends `packets` on `send_port`
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 and receives packets on `receive_port` for the= specified `duration`.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 It must be able to handle receiving no packets= .
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"""

=C2=A0 =C2=A0 =C2=A0def _write_capture_from_packets(self, capture_name: str= , packets: list[Packet]) -> None:
diff --git a/dts/framework/testbed_model/traffic_generator/traffic_generato= r.py b/dts/framework/testbed_model/traffic_generator/traffic_generator.py index 0d9902ddb7..5fb9824568 100644
--- a/dts/framework/testbed_model/traffic_generator/traffic_generator.py +++ b/dts/framework/testbed_model/traffic_generator/traffic_generator.py @@ -22,7 +22,8 @@
=C2=A0class TrafficGenerator(ABC):
=C2=A0 =C2=A0 =C2=A0"""The base traffic generator.

-=C2=A0 =C2=A0 Defines the few basic methods that each traffic generator mu= st implement.
+=C2=A0 =C2=A0 Exposes the common public methods of all traffic generators = and defines private methods
+=C2=A0 =C2=A0 that must implement the traffic generation logic in subclass= es.
=C2=A0 =C2=A0 =C2=A0"""

=C2=A0 =C2=A0 =C2=A0_config: TrafficGeneratorConfig
@@ -30,14 +31,20 @@ class TrafficGenerator(ABC):
=C2=A0 =C2=A0 =C2=A0_logger: DTSLOG

=C2=A0 =C2=A0 =C2=A0def __init__(self, tg_node: Node, config: TrafficGenera= torConfig):
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Initialize the traffic gener= ator.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 Args:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 tg_node: The traffic generator n= ode where the created traffic generator will be running.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 config: The traffic generator= 9;s test run configuration.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0self._config =3D config
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0self._tg_node =3D tg_node
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0self._logger =3D getLogger(f"{self._= tg_nod= e.name} {self._config.traffic_generator_type}")

=C2=A0 =C2=A0 =C2=A0def send_packet(self, packet: Packet, port: Port) ->= None:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send a packet and block unti= l it is fully sent.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send `packet` and block unti= l it is fully sent.

-=C2=A0 =C2=A0 =C2=A0 =C2=A0 What fully sent means is defined by the traffi= c generator.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 Send `packet` on `port`, then wait until `pack= et` is fully sent.

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Args:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0packet: The packet to send.=
@@ -46,9 +53,9 @@ def send_packet(self, packet: Packet, port: Port) -> N= one:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0self.send_packets([packet], port)

=C2=A0 =C2=A0 =C2=A0def send_packets(self, packets: list[Packet], port: Por= t) -> None:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send packets and block until= they are fully sent.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Send `packets` and block unt= il they are fully sent.

-=C2=A0 =C2=A0 =C2=A0 =C2=A0 What fully sent means is defined by the traffi= c generator.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 Send `packets` on `port`, then wait until `pac= kets` are fully sent.

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Args:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0packets: The packets to sen= d.
@@ -60,19 +67,17 @@ def send_packets(self, packets: list[Packet], port: Por= t) -> None:

=C2=A0 =C2=A0 =C2=A0@abstractmethod
=C2=A0 =C2=A0 =C2=A0def _send_packets(self, packets: list[Packet], port: Po= rt) -> None:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 The extended classes must implement this metho= d which
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 sends packets on send_port. The method should = block until all packets
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 are fully sent.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """The implementation of :metho= d:`send_packets`.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 The subclasses must implement this method whic= h sends `packets` on `port`.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 The method should block until all `packets` ar= e fully sent.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 What full sent means is defined by the traffic= generator.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"""
<= br>
I think this should be "what fully sent means"

=C2=A0 =C2=A0 =C2=A0@property
=C2=A0 =C2=A0 =C2=A0def is_capturing(self) -> bool:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """Whether this traffic generat= or can capture traffic.
-
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 Returns:
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 True if the traffic generator ca= n capture traffic, False otherwise.
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 """
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 """This traffic generator can&#= 39;t capture traffic."""
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return False

=C2=A0 =C2=A0 =C2=A0@abstractmethod
--
2.34.1

--000000000000c7f30c060b769dd8--