* [PATCH v1] dts: add virtual functions to framework
@ 2025-06-17 20:13 Dean Marx
2025-06-26 15:27 ` [PATCH v2 1/4] " Dean Marx
0 siblings, 1 reply; 5+ messages in thread
From: Dean Marx @ 2025-06-17 20:13 UTC (permalink / raw)
To: probb, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli, paul.szczepanek
Cc: dev, Dean Marx
Add virtual functions to DTS framework, along with
a field for specifying VF test runs in the config file.
Signed-off-by: Patrick Robb <probb@iol.unh.edu>
Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
dts/framework/config/test_run.py | 2 +
dts/framework/test_run.py | 7 +++
dts/framework/testbed_model/linux_session.py | 53 +++++++++++++++++++-
dts/framework/testbed_model/os_session.py | 42 ++++++++++++++++
dts/framework/testbed_model/topology.py | 42 +++++++++++++++-
5 files changed, 143 insertions(+), 3 deletions(-)
diff --git a/dts/framework/config/test_run.py b/dts/framework/config/test_run.py
index b6e4099eeb..eefa32c3cb 100644
--- a/dts/framework/config/test_run.py
+++ b/dts/framework/config/test_run.py
@@ -467,6 +467,8 @@ class TestRunConfiguration(FrozenModel):
perf: bool
#: Whether to run functional tests.
func: bool
+ #: Whether to run the testing with virtual functions instead of physical functions
+ virtual_functions_testrun: bool
#: Whether to skip smoke tests.
skip_smoke_tests: bool = False
#: The names of test suites and/or test cases to execute.
diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
index 60a9ec8148..5163881aef 100644
--- a/dts/framework/test_run.py
+++ b/dts/framework/test_run.py
@@ -346,6 +346,10 @@ def next(self) -> State | None:
test_run.ctx.tg_node.setup()
test_run.ctx.dpdk.setup()
test_run.ctx.topology.setup()
+
+ if self.test_run.config.virtual_functions_testrun:
+ self.test_run.ctx.topology.instantiate_vf_ports()
+
self.test_run.ctx.topology.configure_ports("sut", "dpdk")
test_run.ctx.tg.setup(test_run.ctx.topology)
@@ -432,6 +436,9 @@ def description(self) -> str:
def next(self) -> State | None:
"""Next state."""
+ if self.test_run.config.virtual_functions_testrun:
+ self.test_run.ctx.topology.delete_vf_ports()
+
self.test_run.ctx.shell_pool.terminate_current_pool()
self.test_run.ctx.tg.teardown()
self.test_run.ctx.topology.teardown()
diff --git a/dts/framework/testbed_model/linux_session.py b/dts/framework/testbed_model/linux_session.py
index e01c2dd712..604245d855 100644
--- a/dts/framework/testbed_model/linux_session.py
+++ b/dts/framework/testbed_model/linux_session.py
@@ -17,7 +17,11 @@
from typing_extensions import NotRequired
-from framework.exception import ConfigurationError, InternalError, RemoteCommandExecutionError
+from framework.exception import (
+ ConfigurationError,
+ InternalError,
+ RemoteCommandExecutionError,
+)
from framework.testbed_model.os_session import PortInfo
from framework.utils import expand_range
@@ -211,11 +215,58 @@ def devbind_script_path(self) -> PurePath:
"""
raise InternalError("Accessed devbind script path before setup.")
+ def create_vfs(self, pf_port: Port) -> None:
+ """Overrides :meth:`~.os_session.OSSession.create_vfs`.
+
+ Raises:
+ InternalError: If there are existing VFs which have to be deleted.
+ """
+ sys_bus_path = f"/sys/bus/pci/devices/{pf_port.pci}".replace(":", "\\:")
+ curr_num_vfs = int(
+ self.send_command(f"cat {sys_bus_path}/sriov_numvfs", privileged=True).stdout
+ )
+ if 0 < curr_num_vfs:
+ raise InternalError("There are existing VFs on the port which must be deleted.")
+ if curr_num_vfs == 0:
+ self.send_command(f"echo 1 | sudo tee {sys_bus_path}/sriov_numvfs", privileged=True)
+ self.refresh_lshw()
+
+ def delete_vfs(self, pf_port: Port) -> None:
+ """Overrides :meth:`~.os_session.OSSession.delete_vfs`."""
+ sys_bus_path = f"/sys/bus/pci/devices/{pf_port.pci}".replace(":", "\\:")
+ curr_num_vfs = int(
+ self.send_command(f"cat {sys_bus_path}/sriov_numvfs", privileged=True).stdout
+ )
+ if curr_num_vfs == 0:
+ self._logger.debug(f"No VFs found on port {pf_port.pci}, skipping deletion")
+ else:
+ self.send_command(f"echo 0 | sudo tee {sys_bus_path}/sriov_numvfs", privileged=True)
+
+ def get_pci_addr_of_vfs(self, pf_port: Port) -> list[str]:
+ """Overrides :meth:`~.os_session.OSSession.get_pci_addr_of_vfs`."""
+ sys_bus_path = f"/sys/bus/pci/devices/{pf_port.pci}".replace(":", "\\:")
+ curr_num_vfs = int(self.send_command(f"cat {sys_bus_path}/sriov_numvfs").stdout)
+ if curr_num_vfs > 0:
+ pci_addrs = self.send_command(
+ 'awk -F "PCI_SLOT_NAME=" "/PCI_SLOT_NAME=/ {print \\$2}" '
+ + f"{sys_bus_path}/virtfn*/uevent",
+ privileged=True,
+ )
+ return pci_addrs.stdout.splitlines()
+ else:
+ return []
+
@cached_property
def _lshw_net_info(self) -> list[LshwOutput]:
output = self.send_command("lshw -quiet -json -C network", verify=True)
return json.loads(output.stdout)
+ def refresh_lshw(self) -> None:
+ """Force refresh of cached lshw network info."""
+ if "_lshw_net_info" in self.__dict__:
+ del self.__dict__["_lshw_net_info"]
+ _ = self._lshw_net_info
+
def _update_port_attr(self, port: Port, attr_value: str | None, attr_name: str) -> None:
if attr_value:
setattr(port, attr_name, attr_value)
diff --git a/dts/framework/testbed_model/os_session.py b/dts/framework/testbed_model/os_session.py
index d7a09a0d5d..b6e03aa83d 100644
--- a/dts/framework/testbed_model/os_session.py
+++ b/dts/framework/testbed_model/os_session.py
@@ -603,3 +603,45 @@ def configure_port_mtu(self, mtu: int, port: Port) -> None:
mtu: Desired MTU value.
port: Port to set `mtu` on.
"""
+
+ @abstractmethod
+ def create_vfs(self, pf_port: Port) -> None:
+ """Creates virtual functions for `pf_port`.
+
+ Checks how many virtual functions (VFs) `pf_port` supports, and creates that
+ number of VFs on the port.
+
+ Args:
+ pf_port: The port to create virtual functions on.
+
+ Raises:
+ InternalError: If the number of VFs is greater than 0 but less than the
+ maximum for `pf_port`.
+ """
+
+ @abstractmethod
+ def delete_vfs(self, pf_port: Port) -> None:
+ """Deletes virtual functions for `pf_port`.
+
+ Checks how many virtual functions (VFs) `pf_port` supports, and deletes that
+ number of VFs on the port.
+
+ Args:
+ pf_port: The port to delete virtual functions on.
+
+ Raises:
+ InternalError: If the number of VFs is greater than 0 but less than the
+ maximum for `pf_port`.
+ """
+
+ @abstractmethod
+ def get_pci_addr_of_vfs(self, pf_port: Port) -> list[str]:
+ """Find the PCI addresses of all virtual functions (VFs) on the port `pf_port`.
+
+ Args:
+ pf_port: The port to find the VFs on.
+
+ Returns:
+ A list containing all of the PCI addresses of the VFs on the port. If the port has no
+ VFs then the list will be empty.
+ """
diff --git a/dts/framework/testbed_model/topology.py b/dts/framework/testbed_model/topology.py
index fb45969136..ef4f97dbda 100644
--- a/dts/framework/testbed_model/topology.py
+++ b/dts/framework/testbed_model/topology.py
@@ -19,7 +19,7 @@
from framework.exception import ConfigurationError, InternalError
from framework.testbed_model.node import Node
-from .port import DriverKind, Port
+from .port import DriverKind, Port, PortConfig
class TopologyType(int, Enum):
@@ -74,6 +74,8 @@ class Topology:
type: TopologyType
sut_ports: list[Port]
tg_ports: list[Port]
+ pf_ports: list[Port]
+ vf_ports: list[Port]
@classmethod
def from_port_links(cls, port_links: Iterator[PortLink]) -> Self:
@@ -101,7 +103,7 @@ def from_port_links(cls, port_links: Iterator[PortLink]) -> Self:
msg = "More than two links in a topology are not supported."
raise ConfigurationError(msg)
- return cls(type, sut_ports, tg_ports)
+ return cls(type, sut_ports, tg_ports, [], [])
def node_and_ports_from_id(self, node_identifier: NodeIdentifier) -> tuple[Node, list[Port]]:
"""Retrieve node and its ports for the current topology.
@@ -160,6 +162,42 @@ def _setup_ports(self, node_identifier: NodeIdentifier) -> None:
f"for port {port.name} in node {node.name}."
)
+ def instantiate_vf_ports(self) -> None:
+ """Create, setup, and add virtual functions to the list of ports on the SUT node."""
+ from framework.context import get_ctx
+
+ ctx = get_ctx()
+
+ for port in self.sut_ports:
+ self.pf_ports.append(port)
+
+ for port in self.pf_ports:
+ ctx.sut_node.main_session.create_vfs(port)
+ addr_list = ctx.sut_node.main_session.get_pci_addr_of_vfs(port)
+ for addr in addr_list:
+ vf_config = PortConfig(
+ name=f"{port.name}-vf-{addr}",
+ pci=addr,
+ os_driver_for_dpdk=port.config.os_driver_for_dpdk,
+ os_driver=port.config.os_driver,
+ )
+ self.vf_ports.append(Port(node=port.node, config=vf_config))
+ ctx.sut_node.main_session.send_command(f"ip link set {port.logical_name} vf 0 trust on")
+
+ self.sut_ports.clear()
+ self.sut_ports.extend(self.vf_ports)
+
+ def delete_vf_ports(self) -> None:
+ """Delete virtual functions from the SUT node during test run teardown."""
+ from framework.context import get_ctx
+
+ ctx = get_ctx()
+
+ for port in self.pf_ports:
+ ctx.sut_node.main_session.delete_vfs(port)
+ self.sut_ports.clear()
+ self.sut_ports.extend(self.pf_ports)
+
def configure_ports(
self, node_identifier: NodeIdentifier, drivers: DriverKind | tuple[DriverKind, ...]
) -> None:
--
2.49.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/4] dts: add virtual functions to framework
2025-06-17 20:13 [PATCH v1] dts: add virtual functions to framework Dean Marx
@ 2025-06-26 15:27 ` Dean Marx
2025-06-26 15:27 ` [PATCH v2 2/4] dts: remove unnecessary testpmd verification Dean Marx
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Dean Marx @ 2025-06-26 15:27 UTC (permalink / raw)
To: probb, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli, paul.szczepanek
Cc: dev, Dean Marx
Add virtual functions to DTS framework, along with
a field for specifying VF test runs in the config file.
Signed-off-by: Patrick Robb <probb@iol.unh.edu>
Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
dts/framework/config/test_run.py | 2 +
dts/framework/test_run.py | 7 +++
dts/framework/testbed_model/linux_session.py | 53 +++++++++++++++++++-
dts/framework/testbed_model/os_session.py | 42 ++++++++++++++++
dts/framework/testbed_model/topology.py | 47 ++++++++++++++++-
5 files changed, 148 insertions(+), 3 deletions(-)
diff --git a/dts/framework/config/test_run.py b/dts/framework/config/test_run.py
index b6e4099eeb..eefa32c3cb 100644
--- a/dts/framework/config/test_run.py
+++ b/dts/framework/config/test_run.py
@@ -467,6 +467,8 @@ class TestRunConfiguration(FrozenModel):
perf: bool
#: Whether to run functional tests.
func: bool
+ #: Whether to run the testing with virtual functions instead of physical functions
+ virtual_functions_testrun: bool
#: Whether to skip smoke tests.
skip_smoke_tests: bool = False
#: The names of test suites and/or test cases to execute.
diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
index 10a5e1a6b8..22a7d5eea1 100644
--- a/dts/framework/test_run.py
+++ b/dts/framework/test_run.py
@@ -346,6 +346,10 @@ def next(self) -> State | None:
test_run.ctx.tg_node.setup()
test_run.ctx.dpdk.setup()
test_run.ctx.topology.setup()
+
+ if test_run.config.virtual_functions_testrun:
+ test_run.ctx.topology.instantiate_vf_ports()
+
test_run.ctx.topology.configure_ports("sut", "dpdk")
test_run.ctx.tg.setup(test_run.ctx.topology)
@@ -432,6 +436,9 @@ def description(self) -> str:
def next(self) -> State | None:
"""Next state."""
+ if self.test_run.config.virtual_functions_testrun:
+ self.test_run.ctx.topology.delete_vf_ports()
+
self.test_run.ctx.shell_pool.terminate_current_pool()
self.test_run.ctx.tg.teardown()
self.test_run.ctx.topology.teardown()
diff --git a/dts/framework/testbed_model/linux_session.py b/dts/framework/testbed_model/linux_session.py
index e01c2dd712..604245d855 100644
--- a/dts/framework/testbed_model/linux_session.py
+++ b/dts/framework/testbed_model/linux_session.py
@@ -17,7 +17,11 @@
from typing_extensions import NotRequired
-from framework.exception import ConfigurationError, InternalError, RemoteCommandExecutionError
+from framework.exception import (
+ ConfigurationError,
+ InternalError,
+ RemoteCommandExecutionError,
+)
from framework.testbed_model.os_session import PortInfo
from framework.utils import expand_range
@@ -211,11 +215,58 @@ def devbind_script_path(self) -> PurePath:
"""
raise InternalError("Accessed devbind script path before setup.")
+ def create_vfs(self, pf_port: Port) -> None:
+ """Overrides :meth:`~.os_session.OSSession.create_vfs`.
+
+ Raises:
+ InternalError: If there are existing VFs which have to be deleted.
+ """
+ sys_bus_path = f"/sys/bus/pci/devices/{pf_port.pci}".replace(":", "\\:")
+ curr_num_vfs = int(
+ self.send_command(f"cat {sys_bus_path}/sriov_numvfs", privileged=True).stdout
+ )
+ if 0 < curr_num_vfs:
+ raise InternalError("There are existing VFs on the port which must be deleted.")
+ if curr_num_vfs == 0:
+ self.send_command(f"echo 1 | sudo tee {sys_bus_path}/sriov_numvfs", privileged=True)
+ self.refresh_lshw()
+
+ def delete_vfs(self, pf_port: Port) -> None:
+ """Overrides :meth:`~.os_session.OSSession.delete_vfs`."""
+ sys_bus_path = f"/sys/bus/pci/devices/{pf_port.pci}".replace(":", "\\:")
+ curr_num_vfs = int(
+ self.send_command(f"cat {sys_bus_path}/sriov_numvfs", privileged=True).stdout
+ )
+ if curr_num_vfs == 0:
+ self._logger.debug(f"No VFs found on port {pf_port.pci}, skipping deletion")
+ else:
+ self.send_command(f"echo 0 | sudo tee {sys_bus_path}/sriov_numvfs", privileged=True)
+
+ def get_pci_addr_of_vfs(self, pf_port: Port) -> list[str]:
+ """Overrides :meth:`~.os_session.OSSession.get_pci_addr_of_vfs`."""
+ sys_bus_path = f"/sys/bus/pci/devices/{pf_port.pci}".replace(":", "\\:")
+ curr_num_vfs = int(self.send_command(f"cat {sys_bus_path}/sriov_numvfs").stdout)
+ if curr_num_vfs > 0:
+ pci_addrs = self.send_command(
+ 'awk -F "PCI_SLOT_NAME=" "/PCI_SLOT_NAME=/ {print \\$2}" '
+ + f"{sys_bus_path}/virtfn*/uevent",
+ privileged=True,
+ )
+ return pci_addrs.stdout.splitlines()
+ else:
+ return []
+
@cached_property
def _lshw_net_info(self) -> list[LshwOutput]:
output = self.send_command("lshw -quiet -json -C network", verify=True)
return json.loads(output.stdout)
+ def refresh_lshw(self) -> None:
+ """Force refresh of cached lshw network info."""
+ if "_lshw_net_info" in self.__dict__:
+ del self.__dict__["_lshw_net_info"]
+ _ = self._lshw_net_info
+
def _update_port_attr(self, port: Port, attr_value: str | None, attr_name: str) -> None:
if attr_value:
setattr(port, attr_name, attr_value)
diff --git a/dts/framework/testbed_model/os_session.py b/dts/framework/testbed_model/os_session.py
index d7a09a0d5d..b6e03aa83d 100644
--- a/dts/framework/testbed_model/os_session.py
+++ b/dts/framework/testbed_model/os_session.py
@@ -603,3 +603,45 @@ def configure_port_mtu(self, mtu: int, port: Port) -> None:
mtu: Desired MTU value.
port: Port to set `mtu` on.
"""
+
+ @abstractmethod
+ def create_vfs(self, pf_port: Port) -> None:
+ """Creates virtual functions for `pf_port`.
+
+ Checks how many virtual functions (VFs) `pf_port` supports, and creates that
+ number of VFs on the port.
+
+ Args:
+ pf_port: The port to create virtual functions on.
+
+ Raises:
+ InternalError: If the number of VFs is greater than 0 but less than the
+ maximum for `pf_port`.
+ """
+
+ @abstractmethod
+ def delete_vfs(self, pf_port: Port) -> None:
+ """Deletes virtual functions for `pf_port`.
+
+ Checks how many virtual functions (VFs) `pf_port` supports, and deletes that
+ number of VFs on the port.
+
+ Args:
+ pf_port: The port to delete virtual functions on.
+
+ Raises:
+ InternalError: If the number of VFs is greater than 0 but less than the
+ maximum for `pf_port`.
+ """
+
+ @abstractmethod
+ def get_pci_addr_of_vfs(self, pf_port: Port) -> list[str]:
+ """Find the PCI addresses of all virtual functions (VFs) on the port `pf_port`.
+
+ Args:
+ pf_port: The port to find the VFs on.
+
+ Returns:
+ A list containing all of the PCI addresses of the VFs on the port. If the port has no
+ VFs then the list will be empty.
+ """
diff --git a/dts/framework/testbed_model/topology.py b/dts/framework/testbed_model/topology.py
index fb45969136..e5c29cb5e7 100644
--- a/dts/framework/testbed_model/topology.py
+++ b/dts/framework/testbed_model/topology.py
@@ -19,7 +19,7 @@
from framework.exception import ConfigurationError, InternalError
from framework.testbed_model.node import Node
-from .port import DriverKind, Port
+from .port import DriverKind, Port, PortConfig
class TopologyType(int, Enum):
@@ -74,6 +74,8 @@ class Topology:
type: TopologyType
sut_ports: list[Port]
tg_ports: list[Port]
+ pf_ports: list[Port]
+ vf_ports: list[Port]
@classmethod
def from_port_links(cls, port_links: Iterator[PortLink]) -> Self:
@@ -101,7 +103,7 @@ def from_port_links(cls, port_links: Iterator[PortLink]) -> Self:
msg = "More than two links in a topology are not supported."
raise ConfigurationError(msg)
- return cls(type, sut_ports, tg_ports)
+ return cls(type, sut_ports, tg_ports, [], [])
def node_and_ports_from_id(self, node_identifier: NodeIdentifier) -> tuple[Node, list[Port]]:
"""Retrieve node and its ports for the current topology.
@@ -160,6 +162,47 @@ def _setup_ports(self, node_identifier: NodeIdentifier) -> None:
f"for port {port.name} in node {node.name}."
)
+ def instantiate_vf_ports(self) -> None:
+ """Create, setup, and add virtual functions to the list of ports on the SUT node."""
+ from framework.context import get_ctx
+
+ ctx = get_ctx()
+
+ for port in self.sut_ports:
+ self.pf_ports.append(port)
+
+ for port in self.pf_ports:
+ ctx.sut_node.main_session.create_vfs(port)
+ addr_list = ctx.sut_node.main_session.get_pci_addr_of_vfs(port)
+ for addr in addr_list:
+ vf_config = PortConfig(
+ name=f"{port.name}-vf-{addr}",
+ pci=addr,
+ os_driver_for_dpdk=port.config.os_driver_for_dpdk,
+ os_driver=port.config.os_driver,
+ )
+ self.vf_ports.append(Port(node=port.node, config=vf_config))
+ ctx.sut_node.main_session.send_command(f"ip link set {port.logical_name} vf 0 trust on")
+
+ self.sut_ports.clear()
+ self.sut_ports.extend(self.vf_ports)
+
+ for port in self.pf_ports:
+ ctx.sut_node.main_session.send_command(
+ f"ip link set dev {port.logical_name} up", privileged=True
+ )
+
+ def delete_vf_ports(self) -> None:
+ """Delete virtual functions from the SUT node during test run teardown."""
+ from framework.context import get_ctx
+
+ ctx = get_ctx()
+
+ for port in self.pf_ports:
+ ctx.sut_node.main_session.delete_vfs(port)
+ self.sut_ports.clear()
+ self.sut_ports.extend(self.pf_ports)
+
def configure_ports(
self, node_identifier: NodeIdentifier, drivers: DriverKind | tuple[DriverKind, ...]
) -> None:
--
2.49.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 2/4] dts: remove unnecessary testpmd verification
2025-06-26 15:27 ` [PATCH v2 1/4] " Dean Marx
@ 2025-06-26 15:27 ` Dean Marx
2025-06-26 15:27 ` [PATCH v2 3/4] dts: modify existing suites to work with VFs Dean Marx
2025-06-26 15:27 ` [PATCH v2 4/4] dts: add physical function capability check Dean Marx
2 siblings, 0 replies; 5+ messages in thread
From: Dean Marx @ 2025-06-26 15:27 UTC (permalink / raw)
To: probb, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli, paul.szczepanek
Cc: dev, Dean Marx
Remove unnecessary verification step in the start method
of TestPmdShell which checks the link status.
Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
dts/framework/remote_session/testpmd_shell.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index 0b9bb4070a..a035452bcf 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -1578,13 +1578,6 @@ def start(self, verify: bool = True) -> None:
self._logger.debug(f"Failed to start packet forwarding: \n{start_cmd_output}")
raise InteractiveCommandExecutionError("Testpmd failed to start packet forwarding.")
- number_of_ports = len(self._app_params.allowed_ports or [])
- for port_id in range(number_of_ports):
- if not self.wait_link_status_up(port_id):
- raise InteractiveCommandExecutionError(
- "Not all ports came up after starting packet forwarding in testpmd."
- )
-
def stop(self, verify: bool = True) -> str:
"""Stop packet forwarding.
--
2.49.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 3/4] dts: modify existing suites to work with VFs
2025-06-26 15:27 ` [PATCH v2 1/4] " Dean Marx
2025-06-26 15:27 ` [PATCH v2 2/4] dts: remove unnecessary testpmd verification Dean Marx
@ 2025-06-26 15:27 ` Dean Marx
2025-06-26 15:27 ` [PATCH v2 4/4] dts: add physical function capability check Dean Marx
2 siblings, 0 replies; 5+ messages in thread
From: Dean Marx @ 2025-06-26 15:27 UTC (permalink / raw)
To: probb, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli, paul.szczepanek
Cc: dev, Dean Marx
Modify existing test suites to use broadcast destination
MAC addresses when possible, rather than a default
MAC address assigned by DTS during execution.
VFs do not consistently receive and forward packets
unless the MAC address is broadcast or matches the
VF address, even with promiscuous mode enabled.
Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
dts/tests/TestSuite_checksum_offload.py | 69 ++++++++++++-----------
dts/tests/TestSuite_dual_vlan.py | 6 +-
dts/tests/TestSuite_dynamic_queue_conf.py | 2 +-
dts/tests/TestSuite_mtu.py | 7 ++-
dts/tests/TestSuite_packet_capture.py | 23 ++++----
dts/tests/TestSuite_queue_start_stop.py | 2 +-
dts/tests/TestSuite_vlan.py | 4 +-
7 files changed, 62 insertions(+), 51 deletions(-)
diff --git a/dts/tests/TestSuite_checksum_offload.py b/dts/tests/TestSuite_checksum_offload.py
index c9efdcaa1c..9d8d38b0f0 100644
--- a/dts/tests/TestSuite_checksum_offload.py
+++ b/dts/tests/TestSuite_checksum_offload.py
@@ -89,8 +89,13 @@ def send_packet_and_verify_checksum(
if testpmd_packet.l4_dport == id:
is_IP = PacketOffloadFlag.RTE_MBUF_F_RX_IP_CKSUM_GOOD in testpmd_packet.ol_flags
is_L4 = PacketOffloadFlag.RTE_MBUF_F_RX_L4_CKSUM_GOOD in testpmd_packet.ol_flags
- self.verify(is_L4 == good_L4, "Layer 4 checksum flag did not match expected checksum flag.")
- self.verify(is_IP == good_IP, "IP checksum flag did not match expected checksum flag.")
+ try:
+ self.verify(
+ is_L4 == good_L4, "Layer 4 checksum flag did not match expected checksum flag."
+ )
+ self.verify(is_IP == good_IP, "IP checksum flag did not match expected checksum flag.")
+ except NameError:
+ self.verify(False, f"Test packet {packet} was not found in verbose output.")
def setup_hw_offload(self, testpmd: TestPmdShell) -> None:
"""Sets IP, UDP, and TCP layers to hardware offload.
@@ -122,10 +127,10 @@ def test_insert_checksums(self) -> None:
dport_id = 50000
payload = b"xxxxx"
packet_list = [
- Ether() / IP() / UDP(dport=dport_id) / Raw(payload),
- Ether() / IP() / TCP(dport=dport_id) / Raw(payload),
- Ether() / IPv6(src="::1") / UDP(dport=dport_id) / Raw(payload),
- Ether() / IPv6(src="::1") / TCP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / TCP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / UDP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / TCP(dport=dport_id) / Raw(payload),
]
with TestPmdShell(enable_rx_cksum=True) as testpmd:
testpmd.set_forward_mode(SimpleForwardingModes.csum)
@@ -154,10 +159,10 @@ def test_no_insert_checksums(self) -> None:
dport_id = 50000
payload = b"xxxxx"
packet_list = [
- Ether() / IP() / UDP(dport=dport_id) / Raw(payload),
- Ether() / IP() / TCP(dport=dport_id) / Raw(payload),
- Ether() / IPv6(src="::1") / UDP(dport=dport_id) / Raw(payload),
- Ether() / IPv6(src="::1") / TCP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / TCP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / UDP(dport=dport_id) / Raw(payload),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / TCP(dport=dport_id) / Raw(payload),
]
with TestPmdShell(enable_rx_cksum=True) as testpmd:
testpmd.set_forward_mode(SimpleForwardingModes.csum)
@@ -184,10 +189,10 @@ def test_l4_rx_checksum(self) -> None:
"""
dport_id = 50000
packet_list = [
- Ether() / IP() / UDP(dport=dport_id),
- Ether() / IP() / TCP(dport=dport_id),
- Ether() / IP() / UDP(chksum=0xF, dport=dport_id),
- Ether() / IP() / TCP(chksum=0xF, dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / TCP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(chksum=0xF, dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / TCP(chksum=0xF, dport=dport_id),
]
with TestPmdShell(enable_rx_cksum=True) as testpmd:
testpmd.set_forward_mode(SimpleForwardingModes.csum)
@@ -217,10 +222,10 @@ def test_l3_rx_checksum(self) -> None:
"""
dport_id = 50000
packet_list = [
- Ether() / IP() / UDP(dport=dport_id),
- Ether() / IP() / TCP(dport=dport_id),
- Ether() / IP(chksum=0xF) / UDP(dport=dport_id),
- Ether() / IP(chksum=0xF) / TCP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / TCP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP(chksum=0xF) / UDP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP(chksum=0xF) / TCP(dport=dport_id),
]
with TestPmdShell(enable_rx_cksum=True) as testpmd:
testpmd.set_forward_mode(SimpleForwardingModes.csum)
@@ -250,14 +255,14 @@ def test_validate_rx_checksum(self) -> None:
"""
dport_id = 50000
packet_list = [
- Ether() / IP() / UDP(dport=dport_id),
- Ether() / IP() / TCP(dport=dport_id),
- Ether() / IPv6(src="::1") / UDP(dport=dport_id),
- Ether() / IPv6(src="::1") / TCP(dport=dport_id),
- Ether() / IP(chksum=0x0) / UDP(chksum=0xF, dport=dport_id),
- Ether() / IP(chksum=0x0) / TCP(chksum=0xF, dport=dport_id),
- Ether() / IPv6(src="::1") / UDP(chksum=0xF, dport=dport_id),
- Ether() / IPv6(src="::1") / TCP(chksum=0xF, dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / TCP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / UDP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / TCP(dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP(chksum=0x0) / UDP(chksum=0xF, dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP(chksum=0x0) / TCP(chksum=0xF, dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / UDP(chksum=0xF, dport=dport_id),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6(src="::1") / TCP(chksum=0xF, dport=dport_id),
]
with TestPmdShell(enable_rx_cksum=True) as testpmd:
testpmd.set_forward_mode(SimpleForwardingModes.csum)
@@ -297,22 +302,22 @@ def test_vlan_checksum(self) -> None:
dport_id = 50000
payload = b"xxxxx"
packet_list = [
- Ether()
+ Ether(dts="FF:FF:FF:FF:FF:FF")
/ Dot1Q(vlan=1)
/ IP(chksum=0x0)
/ UDP(chksum=0xF, dport=dport_id)
/ Raw(payload),
- Ether()
+ Ether(dts="FF:FF:FF:FF:FF:FF")
/ Dot1Q(vlan=1)
/ IP(chksum=0x0)
/ TCP(chksum=0xF, dport=dport_id)
/ Raw(payload),
- Ether()
+ Ether(dts="FF:FF:FF:FF:FF:FF")
/ Dot1Q(vlan=1)
/ IPv6(src="::1")
/ UDP(chksum=0xF, dport=dport_id)
/ Raw(payload),
- Ether()
+ Ether(dts="FF:FF:FF:FF:FF:FF")
/ Dot1Q(vlan=1)
/ IPv6(src="::1")
/ TCP(chksum=0xF, dport=dport_id)
@@ -353,8 +358,8 @@ def test_validate_sctp_checksum(self) -> None:
"""
dport_id = 50000
packet_list = [
- Ether() / IP() / UDP(dport=dport_id) / SCTP(),
- Ether() / IP() / UDP(dport=dport_id) / SCTP(chksum=0xF),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(dport=dport_id) / SCTP(),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP(dport=dport_id) / SCTP(chksum=0xF),
]
with TestPmdShell(enable_rx_cksum=True) as testpmd:
testpmd.set_forward_mode(SimpleForwardingModes.csum)
diff --git a/dts/tests/TestSuite_dual_vlan.py b/dts/tests/TestSuite_dual_vlan.py
index 6af503528d..de58af8c74 100644
--- a/dts/tests/TestSuite_dual_vlan.py
+++ b/dts/tests/TestSuite_dual_vlan.py
@@ -197,7 +197,7 @@ def insert_second_vlan(self) -> None:
testpmd.tx_vlan_set(port=self.tx_port, enable=True, vlan=self.vlan_insert_tag)
testpmd.start()
recv = self.send_packet_and_capture(
- Ether() / Dot1Q(vlan=self.outer_vlan_tag) / Raw(b"X" * 20)
+ Ether(dst="FF:FF:FF:FF:FF:FF") / Dot1Q(vlan=self.outer_vlan_tag) / Raw(b"X" * 20)
)
self.verify(len(recv) > 0, "Did not receive any packets when testing VLAN insertion.")
self.verify(
@@ -224,7 +224,7 @@ def all_vlan_functions(self) -> None:
VLAN functions work as expected.
"""
send_pkt = (
- Ether()
+ Ether(dst="FF:FF:FF:FF:FF:FF")
/ Dot1Q(vlan=self.outer_vlan_tag)
/ Dot1Q(vlan=self.inner_vlan_tag)
/ Raw(b"X" * 20)
@@ -264,7 +264,7 @@ def maintains_priority(self) -> None:
Priorities are unchanged.
"""
pkt = (
- Ether()
+ Ether(dst="FF:FF:FF:FF:FF:FF")
/ Dot1Q(vlan=self.outer_vlan_tag, prio=1)
/ Dot1Q(vlan=self.inner_vlan_tag, prio=2)
/ Raw(b"X" * 20)
diff --git a/dts/tests/TestSuite_dynamic_queue_conf.py b/dts/tests/TestSuite_dynamic_queue_conf.py
index 344dd540eb..62da208c45 100644
--- a/dts/tests/TestSuite_dynamic_queue_conf.py
+++ b/dts/tests/TestSuite_dynamic_queue_conf.py
@@ -165,7 +165,7 @@ def send_packets_with_different_addresses(self, number_of_packets: int) -> None:
generator.
"""
packets_to_send = [
- Ether()
+ Ether(dst="FF:FF:FF:FF:FF:FF")
/ IP(src=self.src_addr, dst=f"{self.dst_address_subnet}.{(i % 254) + 1}")
/ Raw()
for i in range(number_of_packets)
diff --git a/dts/tests/TestSuite_mtu.py b/dts/tests/TestSuite_mtu.py
index af6ab88501..ee5242a9c1 100644
--- a/dts/tests/TestSuite_mtu.py
+++ b/dts/tests/TestSuite_mtu.py
@@ -68,7 +68,12 @@ def send_packet_and_verify(self, pkt_size: int, should_receive: bool) -> None:
"""
padding = pkt_size - IP_HEADER_LEN
# Insert ' ' as placeholder 'CRC' error correction.
- packet = Ether() / Raw(load=" ") / IP(len=pkt_size) / Raw(load="X" * padding)
+ packet = (
+ Ether(dst="FF:FF:FF:FF:FF:FF")
+ / Raw(load=" ")
+ / IP(len=pkt_size)
+ / Raw(load="X" * padding)
+ )
received_packets = self.send_packet_and_capture(packet)
found = any(
("X" * padding) in str(packets.load)
diff --git a/dts/tests/TestSuite_packet_capture.py b/dts/tests/TestSuite_packet_capture.py
index e162bded87..4cefdc97d3 100644
--- a/dts/tests/TestSuite_packet_capture.py
+++ b/dts/tests/TestSuite_packet_capture.py
@@ -28,6 +28,7 @@
from framework.context import get_ctx
from framework.params import Params
+from framework.params.testpmd import SimpleForwardingModes
from framework.remote_session.dpdk_shell import compute_eal_params
from framework.remote_session.interactive_shell import InteractiveShell
from framework.remote_session.testpmd_shell import TestPmdShell
@@ -118,16 +119,16 @@ def set_up_suite(self) -> None:
Prepare the packets, file paths and queue range to be used in the test suite.
"""
self.packets = [
- Ether() / IP() / Raw(b"\0" * 60),
- Ether() / IP() / TCP() / Raw(b"\0" * 60),
- Ether() / IP() / UDP() / Raw(b"\0" * 60),
- Ether() / IP() / SCTP() / Raw(b"\0" * 40),
- Ether() / IPv6() / TCP() / Raw(b"\0" * 60),
- Ether() / IPv6() / UDP() / Raw(b"\0" * 60),
- Ether() / IP() / IPv6() / SCTP() / Raw(b"\0" * 40),
- Ether() / Dot1Q() / IP() / UDP() / Raw(b"\0" * 40),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / Raw(b"\0" * 60),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / TCP() / Raw(b"\0" * 60),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / UDP() / Raw(b"\0" * 60),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / SCTP() / Raw(b"\0" * 40),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6() / TCP() / Raw(b"\0" * 60),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IPv6() / UDP() / Raw(b"\0" * 60),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / IPv6() / SCTP() / Raw(b"\0" * 40),
+ Ether(dst="FF:FF:FF:FF:FF:FF") / Dot1Q() / IP() / UDP() / Raw(b"\0" * 40),
Ether(dst="FF:FF:FF:FF:FF:FF", type=0x88F7) / Raw(b"\0" * 60),
- Ether(type=0x88CC)
+ Ether(dst="FF:FF:FF:FF:FF:FF", type=0x88CC)
/ LLDPDUChassisID(subtype=4, id=self.topology.tg_port_egress.mac_address)
/ LLDPDUPortID(subtype=5, id="Test Id")
/ LLDPDUTimeToLive(ttl=180)
@@ -192,7 +193,7 @@ def test_dumpcap(self) -> None:
* The expected packets are the same as the Rx packets.
* The Tx packets are the same as the packets received from Scapy.
"""
- with TestPmdShell() as testpmd:
+ with TestPmdShell(forward_mode=SimpleForwardingModes.mac) as testpmd:
testpmd.start()
received_packets = self._send_and_dump()
@@ -221,7 +222,7 @@ def test_dumpcap_filter(self) -> None:
Verify:
* The dumped packets did not contain any of the packets meant for filtering.
"""
- with TestPmdShell() as testpmd:
+ with TestPmdShell(forward_mode=SimpleForwardingModes.mac) as testpmd:
testpmd.start()
self._send_and_dump("tcp", rx_only=True)
filtered_packets = [
diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
index d739ddedfe..3a5d4b6147 100644
--- a/dts/tests/TestSuite_queue_start_stop.py
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -42,7 +42,7 @@ def send_packet_and_verify(self, should_receive: bool = True) -> None:
Args:
should_receive: Indicate whether the packet should be received.
"""
- packet = Ether() / IP() / Raw(load="xxxxx")
+ packet = Ether(dst="FF:FF:FF:FF:FF:FF") / IP() / Raw(load="xxxxx")
received = self.send_packet_and_capture(packet)
contains_packet = any(
packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
diff --git a/dts/tests/TestSuite_vlan.py b/dts/tests/TestSuite_vlan.py
index d2a9e614d4..1cc5a200d4 100644
--- a/dts/tests/TestSuite_vlan.py
+++ b/dts/tests/TestSuite_vlan.py
@@ -48,7 +48,7 @@ def send_vlan_packet_and_verify(self, should_receive: bool, strip: bool, vlan_id
(as it has been stripped off.)
vlan_id: Expected VLAN ID.
"""
- packet = Ether() / Dot1Q(vlan=vlan_id) / Raw(load="xxxxx")
+ packet = Ether(dst="FF:FF:FF:FF:FF:FF") / Dot1Q(vlan=vlan_id) / Raw(load="xxxxx")
received_packets = self.send_packet_and_capture(packet)
test_packet = None
for packet in received_packets:
@@ -83,7 +83,7 @@ def send_packet_and_verify_insertion(self, expected_id: int) -> None:
Args:
expected_id: The VLAN id that is being inserted through tx_offload configuration.
"""
- packet = Ether() / Raw(load="xxxxx")
+ packet = Ether(dst="FF:FF:FF:FF:FF:FF") / Raw(load="xxxxx")
received_packets = self.send_packet_and_capture(packet)
test_packet = None
for packet in received_packets:
--
2.49.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 4/4] dts: add physical function capability check
2025-06-26 15:27 ` [PATCH v2 1/4] " Dean Marx
2025-06-26 15:27 ` [PATCH v2 2/4] dts: remove unnecessary testpmd verification Dean Marx
2025-06-26 15:27 ` [PATCH v2 3/4] dts: modify existing suites to work with VFs Dean Marx
@ 2025-06-26 15:27 ` Dean Marx
2 siblings, 0 replies; 5+ messages in thread
From: Dean Marx @ 2025-06-26 15:27 UTC (permalink / raw)
To: probb, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli, paul.szczepanek
Cc: dev, Dean Marx
Add a physical function NIC capability that checks
if the test run is using PFs. Add PF capability
requirement to all suites/cases that do not
run without error on virtual functions.
Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
dts/framework/remote_session/testpmd_shell.py | 22 +++++++++++++++++++
dts/tests/TestSuite_dynamic_config.py | 3 ++-
dts/tests/TestSuite_dynamic_queue_conf.py | 1 +
dts/tests/TestSuite_l2fwd.py | 3 ++-
dts/tests/TestSuite_mac_filter.py | 1 +
dts/tests/TestSuite_pmd_buffer_scatter.py | 1 +
dts/tests/TestSuite_port_control.py | 3 ++-
dts/tests/TestSuite_port_stats.py | 2 ++
dts/tests/TestSuite_promisc_support.py | 4 +++-
dts/tests/TestSuite_softnic.py | 3 ++-
dts/tests/TestSuite_uni_pkt.py | 2 ++
11 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index a035452bcf..4156a289a1 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -2640,6 +2640,23 @@ def get_capabilities_flow_ctrl(
else:
unsupported_capabilities.add(NicCapability.FLOW_CTRL)
+ def get_capabilities_physical_function(
+ self,
+ supported_capabilities: MutableSet["NicCapability"],
+ unsupported_capabilities: MutableSet["NicCapability"],
+ ) -> None:
+ """Store capability representing a physical function test run.
+
+ Args:
+ supported_capabilities: Supported capabilities will be added to this set.
+ unsupported_capabilities: Unsupported capabilities will be added to this set.
+ """
+ ctx = get_ctx()
+ if ctx.topology.vf_ports == []:
+ supported_capabilities.add(NicCapability.PHYSICAL_FUNCTION)
+ else:
+ unsupported_capabilities.add(NicCapability.PHYSICAL_FUNCTION)
+
class NicCapability(NoAliasEnum):
"""A mapping between capability names and the associated :class:`TestPmdShell` methods.
@@ -2788,6 +2805,11 @@ class NicCapability(NoAliasEnum):
)
#: Device supports flow ctrl.
FLOW_CTRL: TestPmdShellNicCapability = (TestPmdShell.get_capabilities_flow_ctrl, None)
+ #: Device is running on a physical function.
+ PHYSICAL_FUNCTION: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_physical_function,
+ None,
+ )
def __call__(
self,
diff --git a/dts/tests/TestSuite_dynamic_config.py b/dts/tests/TestSuite_dynamic_config.py
index 1fce31a0b5..49f295a39a 100644
--- a/dts/tests/TestSuite_dynamic_config.py
+++ b/dts/tests/TestSuite_dynamic_config.py
@@ -20,11 +20,12 @@
from scapy.packet import Raw
from framework.params.testpmd import SimpleForwardingModes
-from framework.remote_session.testpmd_shell import TestPmdShell
+from framework.remote_session.testpmd_shell import NicCapability, TestPmdShell
from framework.test_suite import TestSuite, func_test
from framework.testbed_model.capability import TopologyType, requires
+@requires(NicCapability.PHYSICAL_FUNCTION)
@requires(topology_type=TopologyType.two_links)
class TestDynamicConfig(TestSuite):
"""Dynamic config suite.
diff --git a/dts/tests/TestSuite_dynamic_queue_conf.py b/dts/tests/TestSuite_dynamic_queue_conf.py
index 62da208c45..cd35e73087 100644
--- a/dts/tests/TestSuite_dynamic_queue_conf.py
+++ b/dts/tests/TestSuite_dynamic_queue_conf.py
@@ -117,6 +117,7 @@ def wrap(self: "TestDynamicQueueConf", is_rx_testing: bool) -> None:
return wrap
+@requires(NicCapability.PHYSICAL_FUNCTION)
class TestDynamicQueueConf(TestSuite):
"""DPDK dynamic queue configuration test suite.
diff --git a/dts/tests/TestSuite_l2fwd.py b/dts/tests/TestSuite_l2fwd.py
index 0555d75ed8..5ffa2dcd19 100644
--- a/dts/tests/TestSuite_l2fwd.py
+++ b/dts/tests/TestSuite_l2fwd.py
@@ -9,7 +9,7 @@
from framework.context import filter_cores
from framework.params.testpmd import EthPeer, SimpleForwardingModes
-from framework.remote_session.testpmd_shell import TestPmdShell
+from framework.remote_session.testpmd_shell import NicCapability, TestPmdShell
from framework.test_suite import TestSuite, func_test
from framework.testbed_model.capability import requires
from framework.testbed_model.cpu import LogicalCoreCount
@@ -17,6 +17,7 @@
from framework.utils import generate_random_packets
+@requires(NicCapability.PHYSICAL_FUNCTION)
@requires(topology_type=TopologyType.two_links)
class TestL2fwd(TestSuite):
"""L2 forwarding test suite."""
diff --git a/dts/tests/TestSuite_mac_filter.py b/dts/tests/TestSuite_mac_filter.py
index 9dbfec5da2..2387fdfac2 100644
--- a/dts/tests/TestSuite_mac_filter.py
+++ b/dts/tests/TestSuite_mac_filter.py
@@ -25,6 +25,7 @@
from framework.testbed_model.capability import requires
+@requires(NicCapability.PHYSICAL_FUNCTION)
class TestMacFilter(TestSuite):
"""Mac address allowlist filtering test suite.
diff --git a/dts/tests/TestSuite_pmd_buffer_scatter.py b/dts/tests/TestSuite_pmd_buffer_scatter.py
index 5e23f28bc6..015163dd11 100644
--- a/dts/tests/TestSuite_pmd_buffer_scatter.py
+++ b/dts/tests/TestSuite_pmd_buffer_scatter.py
@@ -28,6 +28,7 @@
from framework.testbed_model.capability import NicCapability, requires
+@requires(NicCapability.PHYSICAL_FUNCTION)
@requires(NicCapability.RX_OFFLOAD_SCATTER)
class TestPmdBufferScatter(TestSuite):
"""DPDK PMD packet scattering test suite.
diff --git a/dts/tests/TestSuite_port_control.py b/dts/tests/TestSuite_port_control.py
index ad5a09c58e..58783f1d18 100644
--- a/dts/tests/TestSuite_port_control.py
+++ b/dts/tests/TestSuite_port_control.py
@@ -13,11 +13,12 @@
from scapy.packet import Packet, Raw
from framework.params.testpmd import SimpleForwardingModes
-from framework.remote_session.testpmd_shell import TestPmdShell
+from framework.remote_session.testpmd_shell import NicCapability, TestPmdShell
from framework.test_suite import TestSuite, func_test
from framework.testbed_model.capability import TopologyType, requires
+@requires(NicCapability.PHYSICAL_FUNCTION)
@requires(topology_type=TopologyType.two_links)
class TestPortControl(TestSuite):
"""DPDK Port Control Testing Suite."""
diff --git a/dts/tests/TestSuite_port_stats.py b/dts/tests/TestSuite_port_stats.py
index 2bb8747399..ddd28623b3 100644
--- a/dts/tests/TestSuite_port_stats.py
+++ b/dts/tests/TestSuite_port_stats.py
@@ -19,6 +19,7 @@
from framework.params.testpmd import SimpleForwardingModes
from framework.remote_session.testpmd_shell import (
+ NicCapability,
RtePTypes,
TestPmdShell,
TestPmdVerbosePacket,
@@ -27,6 +28,7 @@
from framework.testbed_model.capability import TopologyType, requires
+@requires(NicCapability.PHYSICAL_FUNCTION)
@requires(topology_type=TopologyType.two_links)
class TestPortStats(TestSuite):
"""DPDK Port statistics testing suite.
diff --git a/dts/tests/TestSuite_promisc_support.py b/dts/tests/TestSuite_promisc_support.py
index 445f6e1d69..8a7a7efb57 100644
--- a/dts/tests/TestSuite_promisc_support.py
+++ b/dts/tests/TestSuite_promisc_support.py
@@ -11,10 +11,12 @@
from scapy.layers.l2 import Ether
from scapy.packet import Raw
-from framework.remote_session.testpmd_shell import TestPmdShell
+from framework.remote_session.testpmd_shell import NicCapability, TestPmdShell
from framework.test_suite import TestSuite, func_test
+from framework.testbed_model.capability import requires
+@requires(NicCapability.PHYSICAL_FUNCTION)
class TestPromiscSupport(TestSuite):
"""Promiscuous mode support test suite."""
diff --git a/dts/tests/TestSuite_softnic.py b/dts/tests/TestSuite_softnic.py
index c1873dca4c..27754c08e7 100644
--- a/dts/tests/TestSuite_softnic.py
+++ b/dts/tests/TestSuite_softnic.py
@@ -9,7 +9,7 @@
from pathlib import Path, PurePath
from framework.params.testpmd import EthPeer
-from framework.remote_session.testpmd_shell import TestPmdShell
+from framework.remote_session.testpmd_shell import NicCapability, TestPmdShell
from framework.test_suite import TestSuite, func_test
from framework.testbed_model.capability import requires
from framework.testbed_model.topology import TopologyType
@@ -17,6 +17,7 @@
from framework.utils import generate_random_packets
+@requires(NicCapability.PHYSICAL_FUNCTION)
@requires(topology_type=TopologyType.two_links)
class TestSoftnic(TestSuite):
"""Softnic test suite."""
diff --git a/dts/tests/TestSuite_uni_pkt.py b/dts/tests/TestSuite_uni_pkt.py
index fdb9c29059..690c5d4fd1 100644
--- a/dts/tests/TestSuite_uni_pkt.py
+++ b/dts/tests/TestSuite_uni_pkt.py
@@ -20,6 +20,7 @@
from scapy.packet import Packet, Raw
from framework.remote_session.testpmd_shell import (
+ NicCapability,
RtePTypes,
SimpleForwardingModes,
TestPmdShell,
@@ -258,6 +259,7 @@ def test_nsh_packet_detect(self) -> None:
with TestPmdShell() as testpmd:
self.setup_session(testpmd=testpmd, expected_flags=flag_list, packet_list=packet_list)
+ @requires(NicCapability.PHYSICAL_FUNCTION)
@func_test
def test_vxlan_tunnel_packet_detect(self) -> None:
"""Ensure the correct flags are shown in the verbose output when sending VXLAN packets.
--
2.49.0
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-06-26 15:28 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-17 20:13 [PATCH v1] dts: add virtual functions to framework Dean Marx
2025-06-26 15:27 ` [PATCH v2 1/4] " Dean Marx
2025-06-26 15:27 ` [PATCH v2 2/4] dts: remove unnecessary testpmd verification Dean Marx
2025-06-26 15:27 ` [PATCH v2 3/4] dts: modify existing suites to work with VFs Dean Marx
2025-06-26 15:27 ` [PATCH v2 4/4] dts: add physical function capability check Dean Marx
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).