[v5,2/2] dts: add VF configuration and workflow
Checks
Commit Message
This patch adds an additional test run config option for
selecting physical functions or virtual functions for the
testrun. If virtual function is selected, it adds a workflow
for creating the virtual functions during test run setup.
Bugzilla ID: 1500
Signed-off-by: Jeremy Spewock <jspewock@iol.unh.edu>
Signed-off-by: Patrick Robb <probb@iol.unh.edu>
---
dts/framework/config/test_run.py | 2 ++
dts/framework/remote_session/dpdk.py | 11 +++++++++--
dts/framework/test_run.py | 7 ++++++-
dts/framework/testbed_model/node.py | 5 +++++
dts/framework/testbed_model/port.py | 16 ++++++++++++++++
dts/test_run.example.yaml | 1 +
6 files changed, 39 insertions(+), 3 deletions(-)
Comments
On Wed, Mar 12, 2025 at 11:40 PM Patrick Robb <probb@iol.unh.edu> wrote:
>
> + def set_vfs(self):
> + """Create virtual functions for the port."""
> + self.node.main_session.create_vfs(self)
> + addr_list = self.node.main_session.get_pci_addr_of_vfs(self)
> + for addr in addr_list:
> + vf_port_config = PortConfig(
> + name=f"{self.name}-vf-{addr}",
> + pci=addr,
> + os_driver_for_dpdk=self.config.os_driver_for_dpdk,
> + os_driver=self.config.os_driver,
> + )
> + self.virtual_functions.append(Port(self.node, vf_port_config))
>
From doing additional runs from this patch, I am seeing for some reason
like 10% of the time there will be some StopIteration error on a VF port
init from get_port_info(pci), when it is indeed being provided with a pci
address (I think but I can debug).
>
@@ -464,6 +464,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.
@@ -415,12 +415,19 @@ def __init__(
self._ports_bound_to_dpdk = False
self._kill_session = None
- def setup(self, ports: Iterable[Port]):
+ def setup(self, ports: Iterable[Port], vf_ports: bool):
"""Set up the DPDK runtime on the target node."""
if self.build:
self.build.setup()
self._prepare_devbind_script()
- self.bind_ports_to_driver(ports)
+
+ if not vf_ports:
+ # for PF test, bind PFs to the DPDK driver
+ self.bind_ports_to_driver(ports)
+ else:
+ # for VF test, leave PFs bound to kernel driver. Bind each PF's VFs to the DPDK driver
+ for port in ports:
+ self.bind_ports_to_driver(port.virtual_functions)
def teardown(self, ports: Iterable[Port]) -> None:
"""Reset DPDK variables and bind port driver to the OS driver."""
@@ -202,6 +202,9 @@ def __init__(
for link in self.config.port_topology
)
+ if self.config.virtual_functions_testrun:
+ sut_node.set_vfs()
+
dpdk_build_env = DPDKBuildEnvironment(config.dpdk.build, sut_node)
dpdk_runtime_env = DPDKRuntimeEnvironment(config.dpdk, sut_node, dpdk_build_env)
traffic_generator = create_traffic_generator(config.traffic_generator, tg_node)
@@ -344,7 +347,9 @@ def next(self) -> State | None:
test_run.ctx.sut_node.setup()
test_run.ctx.tg_node.setup()
- test_run.ctx.dpdk.setup(test_run.ctx.topology.sut_ports)
+ test_run.ctx.dpdk.setup(
+ test_run.ctx.topology.sut_ports, test_run.config.virtual_functions_testrun
+ )
test_run.ctx.tg.setup(test_run.ctx.topology.tg_ports)
self.result.ports = test_run.ctx.topology.sut_ports + test_run.ctx.topology.tg_ports
@@ -185,6 +185,11 @@ def close(self) -> None:
for session in self._other_sessions:
session.close()
+ def set_vfs(self):
+ """Iterate through node ports and create VFs."""
+ for port in self.ports:
+ port.set_vfs()
+
def create_session(node_config: NodeConfiguration, name: str, logger: DTSLogger) -> OSSession:
"""Factory for OS-aware sessions.
@@ -26,6 +26,7 @@ class Port:
mac_address: The MAC address of the port.
logical_name: The logical name of the port.
bound_for_dpdk: :data:`True` if the port is bound to the driver for DPDK.
+ virtual_functions: The list of virtual functions on the port.
"""
node: Final["Node"]
@@ -33,6 +34,7 @@ class Port:
mac_address: Final[str]
logical_name: Final[str]
bound_for_dpdk: bool
+ virtual_functions: list["Port"]
def __init__(self, node: "Node", config: PortConfig):
"""Initialize the port from `node` and `config`.
@@ -45,6 +47,7 @@ def __init__(self, node: "Node", config: PortConfig):
self.config = config
self.logical_name, self.mac_address = node.main_session.get_port_info(config.pci)
self.bound_for_dpdk = False
+ self.virtual_functions = []
@property
def name(self) -> str:
@@ -64,6 +67,19 @@ def configure_mtu(self, mtu: int):
"""
return self.node.main_session.configure_port_mtu(mtu, self)
+ def set_vfs(self):
+ """Create virtual functions for the port."""
+ self.node.main_session.create_vfs(self)
+ addr_list = self.node.main_session.get_pci_addr_of_vfs(self)
+ for addr in addr_list:
+ vf_port_config = PortConfig(
+ name=f"{self.name}-vf-{addr}",
+ pci=addr,
+ os_driver_for_dpdk=self.config.os_driver_for_dpdk,
+ os_driver=self.config.os_driver,
+ )
+ self.virtual_functions.append(Port(self.node, vf_port_config))
+
def to_dict(self) -> dict[str, Any]:
"""Convert to a dictionary."""
return {
@@ -27,6 +27,7 @@ traffic_generator:
type: SCAPY
perf: false # disable performance testing
func: true # enable functional testing
+virtual_functions_testrun: false # testsuites are run from physical functions if set to false, and virtual functions if set to true
skip_smoke_tests: false # optional
# by removing the `test_suites` field, this test run will run every test suite available
test_suites: # the following test suites will be run in their entirety