Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ suri_cmd_params = {"capture-mode": ["dpdk"]}

filter = {
"dpdk": [lambda x: x["dpdk.interfaces[0].mtu"] <= 3000],
"af-packet": [lambda x: True]
"af-packet": [lambda x: True],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mysterious comma!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That one is from the ruff markdown formatting commit, and I figured it won't hurt to leave it there 😝

Speaking of that, there is a new ruff version which has new linter rules (and this markdown formatting), so we might want to update it.

}
```

Expand Down Expand Up @@ -396,7 +396,7 @@ filter = {
lambda x: x["dpdk.interfaces[0].mtu"] <= 3000,
lambda x: x["dpdk.interfaces[0].rx-descriptors"] >= 4096,
],
"af-packet": [lambda x: True]
"af-packet": [lambda x: True],
}
```

Expand Down
130 changes: 80 additions & 50 deletions assets/trex/traffic_profiles/trex_client_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import warnings
from pathlib import Path
from time import sleep, time
from typing import Callable, Dict, Literal, NamedTuple, Self
from typing import Any, Callable, Literal, NamedTuple, Self, cast

from lbr_testsuite.trex import (
TRexAdvancedStateful,
Expand All @@ -27,6 +27,7 @@
# against in `isinstance()` (e.g. STLClient.add_streams). Importing from
# `lbr_trex_client.interactive.trex.*` instead would create distinct class
# objects and break those checks.
from conftest import fmt_bytes, fmt_thousands
from trex.astf import trex_astf_profile
from trex.astf.trex_astf_client import ASTFClient
from trex.common.trex_exceptions import TRexError
Expand All @@ -35,10 +36,9 @@
from pytest import FixtureRequest

from util.add_vlan import edit_vlan
from util.config_builder import ConfigBuilder
from util.config_builder import DEFAULT_TREX_CONF, ConfigBuilder
from util.suri_util import RunInfo
from util.trex_util import (
PcapList,
TrexMode,
get_trex_mac,
merge_pcaps,
Expand All @@ -63,13 +63,13 @@ class BaseTrexClientManager:

Subclasses are created as `MyProfile(BaseTrexClientManager, pcaps)`.

`pcaps: PcapList` is a list of (str, int) tuples, where int is:
`pcaps: list[Pcap]` is a list of (str, int) tuples, where int is:
- cps in STF
- cps in ASTF
- the divisor for `self.BASE_IPG_USEC` in STL
"""
Comment thread
matyas7dub marked this conversation as resolved.

pcaps: PcapList
pcaps: list[Pcap]
multiplier: float | None = None
duration: int | None = None
_stf_config_path: Path | None = None
Expand All @@ -84,7 +84,7 @@ def __new__(cls, *args, **kwargs) -> Self:
)
return super().__new__(cls)

def __init_subclass__(cls, pcaps: PcapList) -> None:
def __init_subclass__(cls, pcaps: list[Pcap]) -> None:
cls.profile_pcaps = pcaps

def __init__(
Expand All @@ -97,13 +97,13 @@ def __init__(
) -> None:
# self.pcaps holds (absolute local Path, weight) Pcap objects; the
# class-level `pcaps`/`profile_pcaps` are (relative str, weight).
self.pcaps: list[Pcap] = [
self.pcaps = [
Pcap(self.PCAP_PATH_PREFIX / p[0], p[1]) for p in self.profile_pcaps
]
self.mode = mode
self.vlan_id = target_vlan
self.request = request
self.multiplier: float | None = None
self.multiplier = None

# warn once per profile instead of on every run()/multiplier iteration
if (
Expand All @@ -123,19 +123,22 @@ def __init__(
"Initializing TRex client manager: mode=%s vlan_id=%d pcaps=%s",
self.mode.name,
self.vlan_id,
[p.path for p in self.pcaps],
[str(p.path.relative_to(self.PCAP_PATH_PREFIX)) for p in self.pcaps],
)

trex_gen = request.config.getoption("--trex-generator")
assert trex_gen is not None
trex_host = trex_gen[0].split(",")
trex_hostname = trex_host[0]
trex_pcie = trex_host[1]

match self.mode:
case TrexMode.STL:
self.stl_generator: TRexStateless = manager.request_stateless(request)
self.stl_generator = cast(
TRexStateless, manager.request_stateless(request)
)
self.trex_version = (
self.stl_generator.get_handler().get_server_version()["version"]
self.stl_generator.get_handler().get_server_version()["version"] # pyright: ignore[reportOptionalMemberAccess]
)

self.stl_generator.set_dst_mac(target_mac)
Expand Down Expand Up @@ -172,17 +175,21 @@ def __init__(
pcap.path,
trex_hostname,
pcap_remote_path,
force=self.request.config.getoption("--force-pcap-upload"),
force=cast(
bool, self.request.config.getoption("--force-pcap-upload")
),
)

case TrexMode.ASTF:
self.client: TRexAdvancedStateful = manager.request_stateful(
request, role="client"
self.client = cast(
TRexAdvancedStateful,
manager.request_stateful(request, role="client"),
)
self.server: TRexAdvancedStateful = manager.request_stateful(
request, role="server"
self.server = cast(
TRexAdvancedStateful,
manager.request_stateful(request, role="server"),
)
self.trex_version = self.server.get_handler().get_server_version()[
self.trex_version = self.server.get_handler().get_server_version()[ # pyright: ignore[reportOptionalMemberAccess]
"version"
]

Expand All @@ -204,7 +211,7 @@ def __init__(
os.makedirs("tmp", exist_ok=True)
config = ConfigBuilder(
"tmp/trex_cfg.yaml",
str(Path(__file__).parent / "default_trex.yaml"),
str(DEFAULT_TREX_CONF),
)
config.set_option("[0].interfaces", [trex_pcie, "dummy"])
config.set_option("[0].port_info[.=dest_mac].dest_mac", target_mac)
Expand All @@ -222,7 +229,9 @@ def __init__(
config_path = Path(config.build())
config_remote_path = self.get_remote_data_path(config_path)
self.remote_stf_config = config_remote_path
force_upload = self.request.config.getoption("--force-pcap-upload")
force_upload = cast(
bool, self.request.config.getoption("--force-pcap-upload")
)
send_to_remote(
config_path, trex_hostname, config_remote_path, force=force_upload
)
Expand Down Expand Up @@ -386,8 +395,8 @@ def prepare(self) -> None:
)

profile = self.get_astf_profile(self.multiplier)
client_handler: ASTFClient = self.client.get_handler()
server_handler: ASTFClient = self.server.get_handler()
client_handler = cast(ASTFClient, self.client.get_handler())
server_handler = cast(ASTFClient, self.server.get_handler())
client_handler.load_profile(profile)
server_handler.load_profile(profile)

Expand Down Expand Up @@ -439,7 +448,7 @@ def _mark_measurement_start() -> None:

match self.mode:
case TrexMode.STL:
client: STLClient = self.stl_generator.get_handler()
client = cast(STLClient, self.stl_generator.get_handler())
burst = self.request.config.getoption("--trex-stl-burst")

if burst is not None:
Expand Down Expand Up @@ -543,10 +552,11 @@ def wait_on_traffic(self) -> None:
match self.mode:
case TrexMode.STL:
self.stl_generator.wait_on_traffic()
self.stop()

case TrexMode.ASTF:
self.client.wait_on_traffic()
self.server.stop()
self.stop()

case TrexMode.STF:
assert self.duration is not None
Expand All @@ -558,7 +568,12 @@ def wait_on_traffic(self) -> None:
self.stop()

def stop(self) -> None:
logger.info("Stopping TRex traffic: mode=%s", self.mode.name)
logger.info(
"Stopping TRex traffic (%s, %s pkts, %s)",
self.mode.name,
fmt_thousands(self.get_tx_packets()),
fmt_bytes(self.get_tx_bytes()),
)
match self.mode:
case TrexMode.STL:
self.stl_generator.stop()
Expand Down Expand Up @@ -593,31 +608,41 @@ def get_tx_packets(self) -> int:
"""Current cumulative TRex transmit packet count."""
match self.mode:
case TrexMode.STL:
return int(self.stl_generator.get_stats()["total"]["opackets"])
case TrexMode.ASTF:
return int(self.server.get_stats()["total"]["opackets"]) + int(
self.client.get_stats()["total"]["opackets"]
return int(
self.stl_generator.get_stats().get("total", {}).get("opackets", 0)
)
case TrexMode.ASTF:
return int(
self.server.get_stats().get("total", {}).get("opackets", 0)
) + int(self.client.get_stats().get("total", {}).get("opackets", 0))
case TrexMode.STF:
data = self.stf_generator.get_result_obj().get_latest_dump()[
"trex-global"
]["data"]
return int(data["m_total_tx_pkts"])
return int(
self.stf_generator.get_result_obj()
.get_latest_dump()
.get("trex-global", {})
.get("data", {})
.get("m_total_tx_pkts", 0)
)

def get_tx_bytes(self) -> int:
"""Current cumulative TRex transmit byte count."""
match self.mode:
case TrexMode.STL:
return int(self.stl_generator.get_stats()["total"]["obytes"])
case TrexMode.ASTF:
return int(self.server.get_stats()["total"]["obytes"]) + int(
self.client.get_stats()["total"]["obytes"]
return int(
self.stl_generator.get_stats().get("total", {}).get("obytes", 0)
)
case TrexMode.ASTF:
return int(
self.server.get_stats().get("total", {}).get("obytes", 0)
) + int(self.client.get_stats().get("total", {}).get("obytes", 0))
case TrexMode.STF:
data = self.stf_generator.get_result_obj().get_latest_dump()[
"trex-global"
]["data"]
return int(data["m_total_tx_bytes"])
return int(
self.stf_generator.get_result_obj()
.get_latest_dump()
.get("trex-global", {})
.get("data", {})
.get("m_total_tx_bytes", 0)
)

def get_tx_pps(self) -> float:
"""Current instantaneous TRex transmit rate (packets per second).
Expand All @@ -629,18 +654,23 @@ def get_tx_pps(self) -> float:
"""
match self.mode:
case TrexMode.STL:
return float(self.stl_generator.get_stats()["total"]["tx_pps"])
case TrexMode.ASTF:
return float(self.server.get_stats()["total"]["tx_pps"]) + float(
self.client.get_stats()["total"]["tx_pps"]
return float(
self.stl_generator.get_stats().get("total", {}).get("tx_pps", 0.0)
)
case TrexMode.ASTF:
return float(
self.server.get_stats().get("total", {}).get("tx_pps", 0.0)
) + float(self.client.get_stats().get("total", {}).get("tx_pps", 0.0))
case TrexMode.STF:
data = self.stf_generator.get_result_obj().get_latest_dump()[
"trex-global"
]["data"]
return float(data.get("m_tx_pps", 0.0))
return float(
self.stf_generator.get_result_obj()
.get_latest_dump()
.get("trex-global", {})
.get("data", {})
.get("m_tx_pps", 0.0)
)

def get_stats(self, role: Literal["server"] | Literal["client"] = "server") -> Dict:
def get_stats(self, role: Literal["server", "client"] = "server") -> dict[str, Any]:
assert role in ("server", "client")

match self.mode:
Expand All @@ -667,7 +697,7 @@ class BaseAdHocTrex(BaseTrexClientManager, pcaps=[]):

def __init__(
self,
pcaps: PcapList,
pcaps: list[Pcap],
manager: TRexManager,
request: FixtureRequest,
target_mac: str,
Expand Down
Loading
Loading