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

Reply via email to