The scatter Rx offload capability is needed for the pmd_buffer_scatter
test suite. The command that retrieves the capability is:
show port <port_id> rx_offload capabilities

The command also retrieves a lot of other capabilities (RX_OFFLOAD_*)
which are all added into a Flag. The Flag members correspond to NIC
capability names so a convenience function that looks for the supported
Flags in a testpmd output is also added.

The NIC capability names (mentioned above) are copy-pasted from the
Flag. Dynamic addition of Enum members runs into problems with typing
(mypy doesn't know about the members) and documentation generation
(Sphinx doesn't know about the members).

Signed-off-by: Juraj Linkeš <juraj.lin...@pantheon.tech>
---
 dts/framework/remote_session/testpmd_shell.py | 213 ++++++++++++++++++
 dts/tests/TestSuite_pmd_buffer_scatter.py     |   1 +
 2 files changed, 214 insertions(+)

diff --git a/dts/framework/remote_session/testpmd_shell.py 
b/dts/framework/remote_session/testpmd_shell.py
index 48c31124d1..f83569669e 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -659,6 +659,103 @@ class TestPmdPortStats(TextParser):
     tx_bps: int = field(metadata=TextParser.find_int(r"Tx-bps:\s+(\d+)"))
 
 
+class RxOffloadCapability(Flag):
+    """Rx offload capabilities of a device."""
+
+    #:
+    RX_OFFLOAD_VLAN_STRIP = auto()
+    #: Device supports L3 checksum offload.
+    RX_OFFLOAD_IPV4_CKSUM = auto()
+    #: Device supports L4 checksum offload.
+    RX_OFFLOAD_UDP_CKSUM = auto()
+    #: Device supports L4 checksum offload.
+    RX_OFFLOAD_TCP_CKSUM = auto()
+    #: Device supports Large Receive Offload.
+    RX_OFFLOAD_TCP_LRO = auto()
+    #: Device supports QinQ (queue in queue) offload.
+    RX_OFFLOAD_QINQ_STRIP = auto()
+    #: Device supports inner packet L3 checksum.
+    RX_OFFLOAD_OUTER_IPV4_CKSUM = auto()
+    #: Device supports MACsec.
+    RX_OFFLOAD_MACSEC_STRIP = auto()
+    #: Device supports filtering of a VLAN Tag identifier.
+    RX_OFFLOAD_VLAN_FILTER = 1 << 9
+    #: Device supports VLAN offload.
+    RX_OFFLOAD_VLAN_EXTEND = auto()
+    #: Device supports receiving segmented mbufs.
+    RX_OFFLOAD_SCATTER = 1 << 13
+    #: Device supports Timestamp.
+    RX_OFFLOAD_TIMESTAMP = auto()
+    #: Device supports crypto processing while packet is received in NIC.
+    RX_OFFLOAD_SECURITY = auto()
+    #: Device supports CRC stripping.
+    RX_OFFLOAD_KEEP_CRC = auto()
+    #: Device supports L4 checksum offload.
+    RX_OFFLOAD_SCTP_CKSUM = auto()
+    #: Device supports inner packet L4 checksum.
+    RX_OFFLOAD_OUTER_UDP_CKSUM = auto()
+    #: Device supports RSS hashing.
+    RX_OFFLOAD_RSS_HASH = auto()
+    #: Device supports
+    RX_OFFLOAD_BUFFER_SPLIT = auto()
+    #: Device supports all checksum capabilities.
+    RX_OFFLOAD_CHECKSUM = RX_OFFLOAD_IPV4_CKSUM | RX_OFFLOAD_UDP_CKSUM | 
RX_OFFLOAD_TCP_CKSUM
+    #: Device supports all VLAN capabilities.
+    RX_OFFLOAD_VLAN = (
+        RX_OFFLOAD_VLAN_STRIP
+        | RX_OFFLOAD_VLAN_FILTER
+        | RX_OFFLOAD_VLAN_EXTEND
+        | RX_OFFLOAD_QINQ_STRIP
+    )
+
+    @classmethod
+    def from_string(cls, line: str) -> Self:
+        """Make an instance from a string containing the flag names separated 
with a space.
+
+        Args:
+            line: The line to parse.
+
+        Returns:
+            A new instance containing all found flags.
+        """
+        flag = cls(0)
+        for flag_name in line.split():
+            flag |= cls[f"RX_OFFLOAD_{flag_name}"]
+        return flag
+
+    @classmethod
+    def make_parser(cls, per_port: bool) -> ParserFn:
+        """Make a parser function.
+
+        Args:
+            per_port: If :data:`True`, will return capabilities per port. If 
:data:`False`,
+                will return capabilities per queue.
+
+        Returns:
+            ParserFn: A dictionary for the `dataclasses.field` metadata 
argument containing a
+                parser function that makes an instance of this flag from text.
+        """
+        granularity = "Port" if per_port else "Queue"
+        return TextParser.wrap(
+            TextParser.find(rf"Per {granularity}\s+:(.*)$", re.MULTILINE),
+            cls.from_string,
+        )
+
+
+@dataclass
+class RxOffloadCapabilities(TextParser):
+    """The result of testpmd's ``show port <port_id> rx_offload capabilities`` 
command."""
+
+    #:
+    port_id: int = field(
+        metadata=TextParser.find_int(r"Rx Offloading Capabilities of port 
(\d+) :")
+    )
+    #: Per-queue Rx offload capabilities.
+    per_queue: RxOffloadCapability = 
field(metadata=RxOffloadCapability.make_parser(False))
+    #: Capabilities other than per-queue Rx offload capabilities.
+    per_port: RxOffloadCapability = 
field(metadata=RxOffloadCapability.make_parser(True))
+
+
 T = TypeVarTuple("T")  # type: ignore[misc]
 
 
@@ -1048,6 +1145,42 @@ def _close(self) -> None:
     ====== Capability retrieval methods ======
     """
 
+    def get_capabilities_rx_offload(
+        self,
+        supported_capabilities: MutableSet["NicCapability"],
+        unsupported_capabilities: MutableSet["NicCapability"],
+    ) -> None:
+        """Get all rx offload capabilities and divide them into supported and 
unsupported.
+
+        Args:
+            supported_capabilities: Supported capabilities will be added to 
this set.
+            unsupported_capabilities: Unsupported capabilities will be added 
to this set.
+        """
+        self._logger.debug("Getting rx offload capabilities.")
+        command = f"show port {self.ports[0].id} rx_offload capabilities"
+        rx_offload_capabilities_out = self.send_command(command)
+        rx_offload_capabilities = 
RxOffloadCapabilities.parse(rx_offload_capabilities_out)
+        self._update_capabilities_from_flag(
+            supported_capabilities,
+            unsupported_capabilities,
+            RxOffloadCapability,
+            rx_offload_capabilities.per_port | 
rx_offload_capabilities.per_queue,
+        )
+
+    def _update_capabilities_from_flag(
+        self,
+        supported_capabilities: MutableSet["NicCapability"],
+        unsupported_capabilities: MutableSet["NicCapability"],
+        flag_class: type[Flag],
+        supported_flags: Flag,
+    ) -> None:
+        """Divide all flags from `flag_class` into supported and 
unsupported."""
+        for flag in flag_class:
+            if flag in supported_flags:
+                supported_capabilities.add(NicCapability[str(flag.name)])
+            else:
+                unsupported_capabilities.add(NicCapability[str(flag.name)])
+
     def get_capabilities_rxq_info(
         self,
         supported_capabilities: MutableSet["NicCapability"],
@@ -1119,6 +1252,86 @@ class NicCapability(NoAliasEnum):
     SCATTERED_RX_ENABLED: TestPmdShellCapabilityMethod = partial(
         TestPmdShell.get_capabilities_rxq_info
     )
+    #:
+    RX_OFFLOAD_VLAN_STRIP: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports L3 checksum offload.
+    RX_OFFLOAD_IPV4_CKSUM: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports L4 checksum offload.
+    RX_OFFLOAD_UDP_CKSUM: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports L4 checksum offload.
+    RX_OFFLOAD_TCP_CKSUM: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports Large Receive Offload.
+    RX_OFFLOAD_TCP_LRO: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports QinQ (queue in queue) offload.
+    RX_OFFLOAD_QINQ_STRIP: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports inner packet L3 checksum.
+    RX_OFFLOAD_OUTER_IPV4_CKSUM: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports MACsec.
+    RX_OFFLOAD_MACSEC_STRIP: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports filtering of a VLAN Tag identifier.
+    RX_OFFLOAD_VLAN_FILTER: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports VLAN offload.
+    RX_OFFLOAD_VLAN_EXTEND: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports receiving segmented mbufs.
+    RX_OFFLOAD_SCATTER: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports Timestamp.
+    RX_OFFLOAD_TIMESTAMP: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports crypto processing while packet is received in NIC.
+    RX_OFFLOAD_SECURITY: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports CRC stripping.
+    RX_OFFLOAD_KEEP_CRC: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports L4 checksum offload.
+    RX_OFFLOAD_SCTP_CKSUM: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports inner packet L4 checksum.
+    RX_OFFLOAD_OUTER_UDP_CKSUM: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports RSS hashing.
+    RX_OFFLOAD_RSS_HASH: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports scatter Rx packets to segmented mbufs.
+    RX_OFFLOAD_BUFFER_SPLIT: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports all checksum capabilities.
+    RX_OFFLOAD_CHECKSUM: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
+    #: Device supports all VLAN capabilities.
+    RX_OFFLOAD_VLAN: TestPmdShellCapabilityMethod = partial(
+        TestPmdShell.get_capabilities_rx_offload
+    )
 
     def __call__(
         self,
diff --git a/dts/tests/TestSuite_pmd_buffer_scatter.py 
b/dts/tests/TestSuite_pmd_buffer_scatter.py
index 89ece2ef56..64c48b0793 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.RX_OFFLOAD_SCATTER)
 class TestPmdBufferScatter(TestSuite):
     """DPDK PMD packet scattering test suite.
 
-- 
2.34.1

Reply via email to