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 <jspew...@iol.unh.edu> Signed-off-by: Patrick Robb <pr...@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(-) diff --git a/dts/framework/config/test_run.py b/dts/framework/config/test_run.py index 06fe28143c..2298960f48 100644 --- a/dts/framework/config/test_run.py +++ b/dts/framework/config/test_run.py @@ -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. diff --git a/dts/framework/remote_session/dpdk.py b/dts/framework/remote_session/dpdk.py index 8d9f3b8948..b0445caded 100644 --- a/dts/framework/remote_session/dpdk.py +++ b/dts/framework/remote_session/dpdk.py @@ -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.""" diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py index f9cfe5e908..9fe30113c2 100644 --- a/dts/framework/test_run.py +++ b/dts/framework/test_run.py @@ -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 diff --git a/dts/framework/testbed_model/node.py b/dts/framework/testbed_model/node.py index e6737cd173..ac4f44550b 100644 --- a/dts/framework/testbed_model/node.py +++ b/dts/framework/testbed_model/node.py @@ -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. diff --git a/dts/framework/testbed_model/port.py b/dts/framework/testbed_model/port.py index f638120eeb..e47ee7948e 100644 --- a/dts/framework/testbed_model/port.py +++ b/dts/framework/testbed_model/port.py @@ -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 { diff --git a/dts/test_run.example.yaml b/dts/test_run.example.yaml index 330a31bb18..16d15dc568 100644 --- a/dts/test_run.example.yaml +++ b/dts/test_run.example.yaml @@ -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 -- 2.48.1