xref: /dpdk/dts/framework/remote_session/testpmd_shell.py (revision d64f6ba5f38a847b540fe1e3a592b82ec56fa32c)
1840b1e01SJuraj Linkeš# SPDX-License-Identifier: BSD-3-Clause
2840b1e01SJuraj Linkeš# Copyright(c) 2023 University of New Hampshire
36ef07151SJuraj Linkeš# Copyright(c) 2023 PANTHEON.tech s.r.o.
461d5bc9bSLuca Vizzarro# Copyright(c) 2024 Arm Limited
56ef07151SJuraj Linkeš
66ef07151SJuraj Linkeš"""Testpmd interactive shell.
76ef07151SJuraj Linkeš
86ef07151SJuraj LinkešTypical usage example in a TestSuite::
96ef07151SJuraj Linkeš
10bfad0948SLuca Vizzarro    testpmd_shell = TestPmdShell(self.sut_node)
116ef07151SJuraj Linkeš    devices = testpmd_shell.get_devices()
126ef07151SJuraj Linkeš    for device in devices:
136ef07151SJuraj Linkeš        print(device)
146ef07151SJuraj Linkeš    testpmd_shell.close()
156ef07151SJuraj Linkeš"""
16840b1e01SJuraj Linkeš
172ecfd126SLuca Vizzarroimport functools
1861d5bc9bSLuca Vizzarroimport re
19369d34b8SJeremy Spewockimport time
20c89d0038SJuraj Linkešfrom collections.abc import Callable, MutableSet
2161d5bc9bSLuca Vizzarrofrom dataclasses import dataclass, field
2261d5bc9bSLuca Vizzarrofrom enum import Flag, auto
23840b1e01SJuraj Linkešfrom pathlib import PurePath
24c89d0038SJuraj Linkešfrom typing import TYPE_CHECKING, Any, ClassVar, Concatenate, ParamSpec, TypeAlias
25c89d0038SJuraj Linkeš
26c89d0038SJuraj Linkešif TYPE_CHECKING:
27c89d0038SJuraj Linkeš    from enum import Enum as NoAliasEnum
28c89d0038SJuraj Linkešelse:
29c89d0038SJuraj Linkeš    from aenum import NoAliasEnum
30840b1e01SJuraj Linkeš
3187ba4cdcSLuca Vizzarrofrom typing_extensions import Self, Unpack
3261d5bc9bSLuca Vizzarro
332ecfd126SLuca Vizzarrofrom framework.exception import InteractiveCommandExecutionError, InternalError
34fc0f7dc4SLuca Vizzarrofrom framework.params.testpmd import SimpleForwardingModes, TestPmdParams
3587ba4cdcSLuca Vizzarrofrom framework.params.types import TestPmdParamsDict
3661d5bc9bSLuca Vizzarrofrom framework.parser import ParserFn, TextParser
37bfad0948SLuca Vizzarrofrom framework.remote_session.dpdk_shell import DPDKShell
38369d34b8SJeremy Spewockfrom framework.settings import SETTINGS
39bfad0948SLuca Vizzarrofrom framework.testbed_model.cpu import LogicalCoreCount, LogicalCoreList
40bfad0948SLuca Vizzarrofrom framework.testbed_model.sut_node import SutNode
41a91d5f47SJeremy Spewockfrom framework.utils import REGEX_FOR_MAC_ADDRESS, StrEnum
42369d34b8SJeremy Spewock
432ecfd126SLuca VizzarroP = ParamSpec("P")
442ecfd126SLuca VizzarroTestPmdShellMethod = Callable[Concatenate["TestPmdShell", P], Any]
452ecfd126SLuca Vizzarro
46c89d0038SJuraj LinkešTestPmdShellCapabilityMethod: TypeAlias = Callable[
47c89d0038SJuraj Linkeš    ["TestPmdShell", MutableSet["NicCapability"], MutableSet["NicCapability"]], None
48c89d0038SJuraj Linkeš]
49c89d0038SJuraj Linkeš
50c89d0038SJuraj LinkešTestPmdShellDecorator: TypeAlias = Callable[[TestPmdShellMethod], TestPmdShellMethod]
51c89d0038SJuraj Linkeš
52c0119400SJuraj LinkešTestPmdShellNicCapability = (
53c0119400SJuraj Linkeš    TestPmdShellCapabilityMethod | tuple[TestPmdShellCapabilityMethod, TestPmdShellDecorator]
54c0119400SJuraj Linkeš)
55c0119400SJuraj Linkeš
56840b1e01SJuraj Linkeš
573e967643SJuraj Linkešclass TestPmdDevice:
586ef07151SJuraj Linkeš    """The data of a device that testpmd can recognize.
596ef07151SJuraj Linkeš
606ef07151SJuraj Linkeš    Attributes:
616ef07151SJuraj Linkeš        pci_address: The PCI address of the device.
626ef07151SJuraj Linkeš    """
636ef07151SJuraj Linkeš
64840b1e01SJuraj Linkeš    pci_address: str
65840b1e01SJuraj Linkeš
66840b1e01SJuraj Linkeš    def __init__(self, pci_address_line: str):
676ef07151SJuraj Linkeš        """Initialize the device from the testpmd output line string.
686ef07151SJuraj Linkeš
696ef07151SJuraj Linkeš        Args:
706ef07151SJuraj Linkeš            pci_address_line: A line of testpmd output that contains a device.
716ef07151SJuraj Linkeš        """
72840b1e01SJuraj Linkeš        self.pci_address = pci_address_line.strip().split(": ")[1].strip()
73840b1e01SJuraj Linkeš
74840b1e01SJuraj Linkeš    def __str__(self) -> str:
756ef07151SJuraj Linkeš        """The PCI address captures what the device is."""
76840b1e01SJuraj Linkeš        return self.pci_address
77840b1e01SJuraj Linkeš
78840b1e01SJuraj Linkeš
7961d5bc9bSLuca Vizzarroclass VLANOffloadFlag(Flag):
8061d5bc9bSLuca Vizzarro    """Flag representing the VLAN offload settings of a NIC port."""
8161d5bc9bSLuca Vizzarro
8261d5bc9bSLuca Vizzarro    #:
8361d5bc9bSLuca Vizzarro    STRIP = auto()
8461d5bc9bSLuca Vizzarro    #:
8561d5bc9bSLuca Vizzarro    FILTER = auto()
8661d5bc9bSLuca Vizzarro    #:
8761d5bc9bSLuca Vizzarro    EXTEND = auto()
8861d5bc9bSLuca Vizzarro    #:
8961d5bc9bSLuca Vizzarro    QINQ_STRIP = auto()
9061d5bc9bSLuca Vizzarro
9161d5bc9bSLuca Vizzarro    @classmethod
9261d5bc9bSLuca Vizzarro    def from_str_dict(cls, d):
9361d5bc9bSLuca Vizzarro        """Makes an instance from a dict containing the flag member names with an "on" value.
9461d5bc9bSLuca Vizzarro
9561d5bc9bSLuca Vizzarro        Args:
9661d5bc9bSLuca Vizzarro            d: A dictionary containing the flag members as keys and any string value.
9761d5bc9bSLuca Vizzarro
9861d5bc9bSLuca Vizzarro        Returns:
9961d5bc9bSLuca Vizzarro            A new instance of the flag.
10061d5bc9bSLuca Vizzarro        """
10161d5bc9bSLuca Vizzarro        flag = cls(0)
10261d5bc9bSLuca Vizzarro        for name in cls.__members__:
10361d5bc9bSLuca Vizzarro            if d.get(name) == "on":
10461d5bc9bSLuca Vizzarro                flag |= cls[name]
10561d5bc9bSLuca Vizzarro        return flag
10661d5bc9bSLuca Vizzarro
10761d5bc9bSLuca Vizzarro    @classmethod
10861d5bc9bSLuca Vizzarro    def make_parser(cls) -> ParserFn:
10961d5bc9bSLuca Vizzarro        """Makes a parser function.
11061d5bc9bSLuca Vizzarro
11161d5bc9bSLuca Vizzarro        Returns:
11261d5bc9bSLuca Vizzarro            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
11361d5bc9bSLuca Vizzarro                parser function that makes an instance of this flag from text.
11461d5bc9bSLuca Vizzarro        """
11561d5bc9bSLuca Vizzarro        return TextParser.wrap(
11661d5bc9bSLuca Vizzarro            TextParser.find(
11761d5bc9bSLuca Vizzarro                r"VLAN offload:\s+"
11861d5bc9bSLuca Vizzarro                r"strip (?P<STRIP>on|off), "
11961d5bc9bSLuca Vizzarro                r"filter (?P<FILTER>on|off), "
12061d5bc9bSLuca Vizzarro                r"extend (?P<EXTEND>on|off), "
12161d5bc9bSLuca Vizzarro                r"qinq strip (?P<QINQ_STRIP>on|off)$",
12261d5bc9bSLuca Vizzarro                re.MULTILINE,
12361d5bc9bSLuca Vizzarro                named=True,
12461d5bc9bSLuca Vizzarro            ),
12561d5bc9bSLuca Vizzarro            cls.from_str_dict,
12661d5bc9bSLuca Vizzarro        )
12761d5bc9bSLuca Vizzarro
12861d5bc9bSLuca Vizzarro
12961d5bc9bSLuca Vizzarroclass RSSOffloadTypesFlag(Flag):
13061d5bc9bSLuca Vizzarro    """Flag representing the RSS offload flow types supported by the NIC port."""
13161d5bc9bSLuca Vizzarro
13261d5bc9bSLuca Vizzarro    #:
13361d5bc9bSLuca Vizzarro    ipv4 = auto()
13461d5bc9bSLuca Vizzarro    #:
13561d5bc9bSLuca Vizzarro    ipv4_frag = auto()
13661d5bc9bSLuca Vizzarro    #:
13761d5bc9bSLuca Vizzarro    ipv4_tcp = auto()
13861d5bc9bSLuca Vizzarro    #:
13961d5bc9bSLuca Vizzarro    ipv4_udp = auto()
14061d5bc9bSLuca Vizzarro    #:
14161d5bc9bSLuca Vizzarro    ipv4_sctp = auto()
14261d5bc9bSLuca Vizzarro    #:
14361d5bc9bSLuca Vizzarro    ipv4_other = auto()
14461d5bc9bSLuca Vizzarro    #:
14561d5bc9bSLuca Vizzarro    ipv6 = auto()
14661d5bc9bSLuca Vizzarro    #:
14761d5bc9bSLuca Vizzarro    ipv6_frag = auto()
14861d5bc9bSLuca Vizzarro    #:
14961d5bc9bSLuca Vizzarro    ipv6_tcp = auto()
15061d5bc9bSLuca Vizzarro    #:
15161d5bc9bSLuca Vizzarro    ipv6_udp = auto()
15261d5bc9bSLuca Vizzarro    #:
15361d5bc9bSLuca Vizzarro    ipv6_sctp = auto()
15461d5bc9bSLuca Vizzarro    #:
15561d5bc9bSLuca Vizzarro    ipv6_other = auto()
15661d5bc9bSLuca Vizzarro    #:
15761d5bc9bSLuca Vizzarro    l2_payload = auto()
15861d5bc9bSLuca Vizzarro    #:
15961d5bc9bSLuca Vizzarro    ipv6_ex = auto()
16061d5bc9bSLuca Vizzarro    #:
16161d5bc9bSLuca Vizzarro    ipv6_tcp_ex = auto()
16261d5bc9bSLuca Vizzarro    #:
16361d5bc9bSLuca Vizzarro    ipv6_udp_ex = auto()
16461d5bc9bSLuca Vizzarro    #:
16561d5bc9bSLuca Vizzarro    port = auto()
16661d5bc9bSLuca Vizzarro    #:
16761d5bc9bSLuca Vizzarro    vxlan = auto()
16861d5bc9bSLuca Vizzarro    #:
16961d5bc9bSLuca Vizzarro    geneve = auto()
17061d5bc9bSLuca Vizzarro    #:
17161d5bc9bSLuca Vizzarro    nvgre = auto()
17261d5bc9bSLuca Vizzarro    #:
17361d5bc9bSLuca Vizzarro    user_defined_22 = auto()
17461d5bc9bSLuca Vizzarro    #:
17561d5bc9bSLuca Vizzarro    gtpu = auto()
17661d5bc9bSLuca Vizzarro    #:
17761d5bc9bSLuca Vizzarro    eth = auto()
17861d5bc9bSLuca Vizzarro    #:
17961d5bc9bSLuca Vizzarro    s_vlan = auto()
18061d5bc9bSLuca Vizzarro    #:
18161d5bc9bSLuca Vizzarro    c_vlan = auto()
18261d5bc9bSLuca Vizzarro    #:
18361d5bc9bSLuca Vizzarro    esp = auto()
18461d5bc9bSLuca Vizzarro    #:
18561d5bc9bSLuca Vizzarro    ah = auto()
18661d5bc9bSLuca Vizzarro    #:
18761d5bc9bSLuca Vizzarro    l2tpv3 = auto()
18861d5bc9bSLuca Vizzarro    #:
18961d5bc9bSLuca Vizzarro    pfcp = auto()
19061d5bc9bSLuca Vizzarro    #:
19161d5bc9bSLuca Vizzarro    pppoe = auto()
19261d5bc9bSLuca Vizzarro    #:
19361d5bc9bSLuca Vizzarro    ecpri = auto()
19461d5bc9bSLuca Vizzarro    #:
19561d5bc9bSLuca Vizzarro    mpls = auto()
19661d5bc9bSLuca Vizzarro    #:
19761d5bc9bSLuca Vizzarro    ipv4_chksum = auto()
19861d5bc9bSLuca Vizzarro    #:
19961d5bc9bSLuca Vizzarro    l4_chksum = auto()
20061d5bc9bSLuca Vizzarro    #:
20161d5bc9bSLuca Vizzarro    l2tpv2 = auto()
20261d5bc9bSLuca Vizzarro    #:
20361d5bc9bSLuca Vizzarro    ipv6_flow_label = auto()
20461d5bc9bSLuca Vizzarro    #:
20561d5bc9bSLuca Vizzarro    user_defined_38 = auto()
20661d5bc9bSLuca Vizzarro    #:
20761d5bc9bSLuca Vizzarro    user_defined_39 = auto()
20861d5bc9bSLuca Vizzarro    #:
20961d5bc9bSLuca Vizzarro    user_defined_40 = auto()
21061d5bc9bSLuca Vizzarro    #:
21161d5bc9bSLuca Vizzarro    user_defined_41 = auto()
21261d5bc9bSLuca Vizzarro    #:
21361d5bc9bSLuca Vizzarro    user_defined_42 = auto()
21461d5bc9bSLuca Vizzarro    #:
21561d5bc9bSLuca Vizzarro    user_defined_43 = auto()
21661d5bc9bSLuca Vizzarro    #:
21761d5bc9bSLuca Vizzarro    user_defined_44 = auto()
21861d5bc9bSLuca Vizzarro    #:
21961d5bc9bSLuca Vizzarro    user_defined_45 = auto()
22061d5bc9bSLuca Vizzarro    #:
22161d5bc9bSLuca Vizzarro    user_defined_46 = auto()
22261d5bc9bSLuca Vizzarro    #:
22361d5bc9bSLuca Vizzarro    user_defined_47 = auto()
22461d5bc9bSLuca Vizzarro    #:
22561d5bc9bSLuca Vizzarro    user_defined_48 = auto()
22661d5bc9bSLuca Vizzarro    #:
22761d5bc9bSLuca Vizzarro    user_defined_49 = auto()
22861d5bc9bSLuca Vizzarro    #:
22961d5bc9bSLuca Vizzarro    user_defined_50 = auto()
23061d5bc9bSLuca Vizzarro    #:
23161d5bc9bSLuca Vizzarro    user_defined_51 = auto()
23261d5bc9bSLuca Vizzarro    #:
23361d5bc9bSLuca Vizzarro    l3_pre96 = auto()
23461d5bc9bSLuca Vizzarro    #:
23561d5bc9bSLuca Vizzarro    l3_pre64 = auto()
23661d5bc9bSLuca Vizzarro    #:
23761d5bc9bSLuca Vizzarro    l3_pre56 = auto()
23861d5bc9bSLuca Vizzarro    #:
23961d5bc9bSLuca Vizzarro    l3_pre48 = auto()
24061d5bc9bSLuca Vizzarro    #:
24161d5bc9bSLuca Vizzarro    l3_pre40 = auto()
24261d5bc9bSLuca Vizzarro    #:
24361d5bc9bSLuca Vizzarro    l3_pre32 = auto()
24461d5bc9bSLuca Vizzarro    #:
24561d5bc9bSLuca Vizzarro    l2_dst_only = auto()
24661d5bc9bSLuca Vizzarro    #:
24761d5bc9bSLuca Vizzarro    l2_src_only = auto()
24861d5bc9bSLuca Vizzarro    #:
24961d5bc9bSLuca Vizzarro    l4_dst_only = auto()
25061d5bc9bSLuca Vizzarro    #:
25161d5bc9bSLuca Vizzarro    l4_src_only = auto()
25261d5bc9bSLuca Vizzarro    #:
25361d5bc9bSLuca Vizzarro    l3_dst_only = auto()
25461d5bc9bSLuca Vizzarro    #:
25561d5bc9bSLuca Vizzarro    l3_src_only = auto()
25661d5bc9bSLuca Vizzarro
25761d5bc9bSLuca Vizzarro    #:
25861d5bc9bSLuca Vizzarro    ip = ipv4 | ipv4_frag | ipv4_other | ipv6 | ipv6_frag | ipv6_other | ipv6_ex
25961d5bc9bSLuca Vizzarro    #:
26061d5bc9bSLuca Vizzarro    udp = ipv4_udp | ipv6_udp | ipv6_udp_ex
26161d5bc9bSLuca Vizzarro    #:
26261d5bc9bSLuca Vizzarro    tcp = ipv4_tcp | ipv6_tcp | ipv6_tcp_ex
26361d5bc9bSLuca Vizzarro    #:
26461d5bc9bSLuca Vizzarro    sctp = ipv4_sctp | ipv6_sctp
26561d5bc9bSLuca Vizzarro    #:
26661d5bc9bSLuca Vizzarro    tunnel = vxlan | geneve | nvgre
26761d5bc9bSLuca Vizzarro    #:
26861d5bc9bSLuca Vizzarro    vlan = s_vlan | c_vlan
26961d5bc9bSLuca Vizzarro    #:
27061d5bc9bSLuca Vizzarro    all = (
27161d5bc9bSLuca Vizzarro        eth
27261d5bc9bSLuca Vizzarro        | vlan
27361d5bc9bSLuca Vizzarro        | ip
27461d5bc9bSLuca Vizzarro        | tcp
27561d5bc9bSLuca Vizzarro        | udp
27661d5bc9bSLuca Vizzarro        | sctp
27761d5bc9bSLuca Vizzarro        | l2_payload
27861d5bc9bSLuca Vizzarro        | l2tpv3
27961d5bc9bSLuca Vizzarro        | esp
28061d5bc9bSLuca Vizzarro        | ah
28161d5bc9bSLuca Vizzarro        | pfcp
28261d5bc9bSLuca Vizzarro        | gtpu
28361d5bc9bSLuca Vizzarro        | ecpri
28461d5bc9bSLuca Vizzarro        | mpls
28561d5bc9bSLuca Vizzarro        | l2tpv2
28661d5bc9bSLuca Vizzarro    )
28761d5bc9bSLuca Vizzarro
28861d5bc9bSLuca Vizzarro    @classmethod
28961d5bc9bSLuca Vizzarro    def from_list_string(cls, names: str) -> Self:
29061d5bc9bSLuca Vizzarro        """Makes a flag from a whitespace-separated list of names.
29161d5bc9bSLuca Vizzarro
29261d5bc9bSLuca Vizzarro        Args:
29361d5bc9bSLuca Vizzarro            names: a whitespace-separated list containing the members of this flag.
29461d5bc9bSLuca Vizzarro
29561d5bc9bSLuca Vizzarro        Returns:
29661d5bc9bSLuca Vizzarro            An instance of this flag.
29761d5bc9bSLuca Vizzarro        """
29861d5bc9bSLuca Vizzarro        flag = cls(0)
29961d5bc9bSLuca Vizzarro        for name in names.split():
30061d5bc9bSLuca Vizzarro            flag |= cls.from_str(name)
30161d5bc9bSLuca Vizzarro        return flag
30261d5bc9bSLuca Vizzarro
30361d5bc9bSLuca Vizzarro    @classmethod
30461d5bc9bSLuca Vizzarro    def from_str(cls, name: str) -> Self:
30561d5bc9bSLuca Vizzarro        """Makes a flag matching the supplied name.
30661d5bc9bSLuca Vizzarro
30761d5bc9bSLuca Vizzarro        Args:
30861d5bc9bSLuca Vizzarro            name: a valid member of this flag in text
30961d5bc9bSLuca Vizzarro        Returns:
31061d5bc9bSLuca Vizzarro            An instance of this flag.
31161d5bc9bSLuca Vizzarro        """
31261d5bc9bSLuca Vizzarro        member_name = name.strip().replace("-", "_")
31361d5bc9bSLuca Vizzarro        return cls[member_name]
31461d5bc9bSLuca Vizzarro
31561d5bc9bSLuca Vizzarro    @classmethod
31661d5bc9bSLuca Vizzarro    def make_parser(cls) -> ParserFn:
31761d5bc9bSLuca Vizzarro        """Makes a parser function.
31861d5bc9bSLuca Vizzarro
31961d5bc9bSLuca Vizzarro        Returns:
32061d5bc9bSLuca Vizzarro            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
32161d5bc9bSLuca Vizzarro                parser function that makes an instance of this flag from text.
32261d5bc9bSLuca Vizzarro        """
32361d5bc9bSLuca Vizzarro        return TextParser.wrap(
32461d5bc9bSLuca Vizzarro            TextParser.find(r"Supported RSS offload flow types:((?:\r?\n?  \S+)+)", re.MULTILINE),
32561d5bc9bSLuca Vizzarro            RSSOffloadTypesFlag.from_list_string,
32661d5bc9bSLuca Vizzarro        )
32761d5bc9bSLuca Vizzarro
32861d5bc9bSLuca Vizzarro
32961d5bc9bSLuca Vizzarroclass DeviceCapabilitiesFlag(Flag):
33061d5bc9bSLuca Vizzarro    """Flag representing the device capabilities."""
33161d5bc9bSLuca Vizzarro
33261d5bc9bSLuca Vizzarro    #: Device supports Rx queue setup after device started.
33361d5bc9bSLuca Vizzarro    RUNTIME_RX_QUEUE_SETUP = auto()
33461d5bc9bSLuca Vizzarro    #: Device supports Tx queue setup after device started.
33561d5bc9bSLuca Vizzarro    RUNTIME_TX_QUEUE_SETUP = auto()
33661d5bc9bSLuca Vizzarro    #: Device supports shared Rx queue among ports within Rx domain and switch domain.
33761d5bc9bSLuca Vizzarro    RXQ_SHARE = auto()
33861d5bc9bSLuca Vizzarro    #: Device supports keeping flow rules across restart.
33961d5bc9bSLuca Vizzarro    FLOW_RULE_KEEP = auto()
34061d5bc9bSLuca Vizzarro    #: Device supports keeping shared flow objects across restart.
34161d5bc9bSLuca Vizzarro    FLOW_SHARED_OBJECT_KEEP = auto()
34261d5bc9bSLuca Vizzarro
34361d5bc9bSLuca Vizzarro    @classmethod
34461d5bc9bSLuca Vizzarro    def make_parser(cls) -> ParserFn:
34561d5bc9bSLuca Vizzarro        """Makes a parser function.
34661d5bc9bSLuca Vizzarro
34761d5bc9bSLuca Vizzarro        Returns:
34861d5bc9bSLuca Vizzarro            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
34961d5bc9bSLuca Vizzarro                parser function that makes an instance of this flag from text.
35061d5bc9bSLuca Vizzarro        """
35161d5bc9bSLuca Vizzarro        return TextParser.wrap(
35261d5bc9bSLuca Vizzarro            TextParser.find_int(r"Device capabilities: (0x[A-Fa-f\d]+)"),
35361d5bc9bSLuca Vizzarro            cls,
35461d5bc9bSLuca Vizzarro        )
35561d5bc9bSLuca Vizzarro
35661d5bc9bSLuca Vizzarro
35761d5bc9bSLuca Vizzarroclass DeviceErrorHandlingMode(StrEnum):
35861d5bc9bSLuca Vizzarro    """Enum representing the device error handling mode."""
35961d5bc9bSLuca Vizzarro
36061d5bc9bSLuca Vizzarro    #:
36161d5bc9bSLuca Vizzarro    none = auto()
36261d5bc9bSLuca Vizzarro    #:
36361d5bc9bSLuca Vizzarro    passive = auto()
36461d5bc9bSLuca Vizzarro    #:
36561d5bc9bSLuca Vizzarro    proactive = auto()
36661d5bc9bSLuca Vizzarro    #:
36761d5bc9bSLuca Vizzarro    unknown = auto()
36861d5bc9bSLuca Vizzarro
36961d5bc9bSLuca Vizzarro    @classmethod
37061d5bc9bSLuca Vizzarro    def make_parser(cls) -> ParserFn:
37161d5bc9bSLuca Vizzarro        """Makes a parser function.
37261d5bc9bSLuca Vizzarro
37361d5bc9bSLuca Vizzarro        Returns:
37461d5bc9bSLuca Vizzarro            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
37561d5bc9bSLuca Vizzarro                parser function that makes an instance of this enum from text.
37661d5bc9bSLuca Vizzarro        """
37761d5bc9bSLuca Vizzarro        return TextParser.wrap(TextParser.find(r"Device error handling mode: (\w+)"), cls)
37861d5bc9bSLuca Vizzarro
37961d5bc9bSLuca Vizzarro
38061d5bc9bSLuca Vizzarrodef make_device_private_info_parser() -> ParserFn:
38161d5bc9bSLuca Vizzarro    """Device private information parser.
38261d5bc9bSLuca Vizzarro
38361d5bc9bSLuca Vizzarro    Ensures that we are not parsing invalid device private info output.
38461d5bc9bSLuca Vizzarro
38561d5bc9bSLuca Vizzarro    Returns:
38661d5bc9bSLuca Vizzarro        ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a parser
38761d5bc9bSLuca Vizzarro            function that parses the device private info from the TestPmd port info output.
38861d5bc9bSLuca Vizzarro    """
38961d5bc9bSLuca Vizzarro
39061d5bc9bSLuca Vizzarro    def _validate(info: str):
39161d5bc9bSLuca Vizzarro        info = info.strip()
39261d5bc9bSLuca Vizzarro        if info == "none" or info.startswith("Invalid file") or info.startswith("Failed to dump"):
39361d5bc9bSLuca Vizzarro            return None
39461d5bc9bSLuca Vizzarro        return info
39561d5bc9bSLuca Vizzarro
39661d5bc9bSLuca Vizzarro    return TextParser.wrap(TextParser.find(r"Device private info:\s+([\s\S]+)"), _validate)
39761d5bc9bSLuca Vizzarro
39861d5bc9bSLuca Vizzarro
399c0119400SJuraj Linkešclass RxQueueState(StrEnum):
400c0119400SJuraj Linkeš    """RX queue states.
401c0119400SJuraj Linkeš
402c0119400SJuraj Linkeš    References:
403c0119400SJuraj Linkeš        DPDK lib: ``lib/ethdev/rte_ethdev.h``
404c0119400SJuraj Linkeš        testpmd display function: ``app/test-pmd/config.c:get_queue_state_name()``
405c0119400SJuraj Linkeš    """
406c0119400SJuraj Linkeš
407c0119400SJuraj Linkeš    #:
408c0119400SJuraj Linkeš    stopped = auto()
409c0119400SJuraj Linkeš    #:
410c0119400SJuraj Linkeš    started = auto()
411c0119400SJuraj Linkeš    #:
412c0119400SJuraj Linkeš    hairpin = auto()
413c0119400SJuraj Linkeš    #:
414c0119400SJuraj Linkeš    unknown = auto()
415c0119400SJuraj Linkeš
416c0119400SJuraj Linkeš    @classmethod
417c0119400SJuraj Linkeš    def make_parser(cls) -> ParserFn:
418c0119400SJuraj Linkeš        """Makes a parser function.
419c0119400SJuraj Linkeš
420c0119400SJuraj Linkeš        Returns:
421c0119400SJuraj Linkeš            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
422c0119400SJuraj Linkeš                parser function that makes an instance of this enum from text.
423c0119400SJuraj Linkeš        """
424c0119400SJuraj Linkeš        return TextParser.wrap(TextParser.find(r"Rx queue state: ([^\r\n]+)"), cls)
425c0119400SJuraj Linkeš
426c0119400SJuraj Linkeš
427c0119400SJuraj Linkeš@dataclass
428c0119400SJuraj Linkešclass TestPmdRxqInfo(TextParser):
429c0119400SJuraj Linkeš    """Representation of testpmd's ``show rxq info <port_id> <queue_id>`` command.
430c0119400SJuraj Linkeš
431c0119400SJuraj Linkeš    References:
432c0119400SJuraj Linkeš        testpmd command function: ``app/test-pmd/cmdline.c:cmd_showqueue()``
433c0119400SJuraj Linkeš        testpmd display function: ``app/test-pmd/config.c:rx_queue_infos_display()``
434c0119400SJuraj Linkeš    """
435c0119400SJuraj Linkeš
436c0119400SJuraj Linkeš    #:
437c0119400SJuraj Linkeš    port_id: int = field(metadata=TextParser.find_int(r"Infos for port (\d+)\b ?, RX queue \d+\b"))
438c0119400SJuraj Linkeš    #:
439c0119400SJuraj Linkeš    queue_id: int = field(metadata=TextParser.find_int(r"Infos for port \d+\b ?, RX queue (\d+)\b"))
440c0119400SJuraj Linkeš    #: Mempool used by that queue
441c0119400SJuraj Linkeš    mempool: str = field(metadata=TextParser.find(r"Mempool: ([^\r\n]+)"))
442c0119400SJuraj Linkeš    #: Ring prefetch threshold
443c0119400SJuraj Linkeš    rx_prefetch_threshold: int = field(
444c0119400SJuraj Linkeš        metadata=TextParser.find_int(r"RX prefetch threshold: (\d+)\b")
445c0119400SJuraj Linkeš    )
446c0119400SJuraj Linkeš    #: Ring host threshold
447c0119400SJuraj Linkeš    rx_host_threshold: int = field(metadata=TextParser.find_int(r"RX host threshold: (\d+)\b"))
448c0119400SJuraj Linkeš    #: Ring writeback threshold
449c0119400SJuraj Linkeš    rx_writeback_threshold: int = field(
450c0119400SJuraj Linkeš        metadata=TextParser.find_int(r"RX writeback threshold: (\d+)\b")
451c0119400SJuraj Linkeš    )
452c0119400SJuraj Linkeš    #: Drives the freeing of Rx descriptors
453c0119400SJuraj Linkeš    rx_free_threshold: int = field(metadata=TextParser.find_int(r"RX free threshold: (\d+)\b"))
454c0119400SJuraj Linkeš    #: Drop packets if no descriptors are available
455c0119400SJuraj Linkeš    rx_drop_packets: bool = field(metadata=TextParser.find(r"RX drop packets: on"))
456c0119400SJuraj Linkeš    #: Do not start queue with rte_eth_dev_start()
457c0119400SJuraj Linkeš    rx_deferred_start: bool = field(metadata=TextParser.find(r"RX deferred start: on"))
458c0119400SJuraj Linkeš    #: Scattered packets Rx enabled
459c0119400SJuraj Linkeš    rx_scattered_packets: bool = field(metadata=TextParser.find(r"RX scattered packets: on"))
460c0119400SJuraj Linkeš    #: The state of the queue
461c0119400SJuraj Linkeš    rx_queue_state: str = field(metadata=RxQueueState.make_parser())
462c0119400SJuraj Linkeš    #: Configured number of RXDs
463c0119400SJuraj Linkeš    number_of_rxds: int = field(metadata=TextParser.find_int(r"Number of RXDs: (\d+)\b"))
464c0119400SJuraj Linkeš    #: Hardware receive buffer size
465c0119400SJuraj Linkeš    rx_buffer_size: int | None = field(
466c0119400SJuraj Linkeš        default=None, metadata=TextParser.find_int(r"RX buffer size: (\d+)\b")
467c0119400SJuraj Linkeš    )
468c0119400SJuraj Linkeš    #: Burst mode information
469c0119400SJuraj Linkeš    burst_mode: str | None = field(
470c0119400SJuraj Linkeš        default=None, metadata=TextParser.find(r"Burst mode: ([^\r\n]+)")
471c0119400SJuraj Linkeš    )
472c0119400SJuraj Linkeš
473c0119400SJuraj Linkeš
47461d5bc9bSLuca Vizzarro@dataclass
47561d5bc9bSLuca Vizzarroclass TestPmdPort(TextParser):
47661d5bc9bSLuca Vizzarro    """Dataclass representing the result of testpmd's ``show port info`` command."""
47761d5bc9bSLuca Vizzarro
47861d5bc9bSLuca Vizzarro    #:
47961d5bc9bSLuca Vizzarro    id: int = field(metadata=TextParser.find_int(r"Infos for port (\d+)\b"))
48061d5bc9bSLuca Vizzarro    #:
48161d5bc9bSLuca Vizzarro    device_name: str = field(metadata=TextParser.find(r"Device name: ([^\r\n]+)"))
48261d5bc9bSLuca Vizzarro    #:
48361d5bc9bSLuca Vizzarro    driver_name: str = field(metadata=TextParser.find(r"Driver name: ([^\r\n]+)"))
48461d5bc9bSLuca Vizzarro    #:
48561d5bc9bSLuca Vizzarro    socket_id: int = field(metadata=TextParser.find_int(r"Connect to socket: (\d+)"))
48661d5bc9bSLuca Vizzarro    #:
48761d5bc9bSLuca Vizzarro    is_link_up: bool = field(metadata=TextParser.find("Link status: up"))
48861d5bc9bSLuca Vizzarro    #:
48961d5bc9bSLuca Vizzarro    link_speed: str = field(metadata=TextParser.find(r"Link speed: ([^\r\n]+)"))
49061d5bc9bSLuca Vizzarro    #:
49161d5bc9bSLuca Vizzarro    is_link_full_duplex: bool = field(metadata=TextParser.find("Link duplex: full-duplex"))
49261d5bc9bSLuca Vizzarro    #:
49361d5bc9bSLuca Vizzarro    is_link_autonegotiated: bool = field(metadata=TextParser.find("Autoneg status: On"))
49461d5bc9bSLuca Vizzarro    #:
49561d5bc9bSLuca Vizzarro    is_promiscuous_mode_enabled: bool = field(metadata=TextParser.find("Promiscuous mode: enabled"))
49661d5bc9bSLuca Vizzarro    #:
49761d5bc9bSLuca Vizzarro    is_allmulticast_mode_enabled: bool = field(
49861d5bc9bSLuca Vizzarro        metadata=TextParser.find("Allmulticast mode: enabled")
49961d5bc9bSLuca Vizzarro    )
50061d5bc9bSLuca Vizzarro    #: Maximum number of MAC addresses
50161d5bc9bSLuca Vizzarro    max_mac_addresses_num: int = field(
50261d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Maximum number of MAC addresses: (\d+)")
50361d5bc9bSLuca Vizzarro    )
50461d5bc9bSLuca Vizzarro    #: Maximum configurable length of RX packet
50561d5bc9bSLuca Vizzarro    max_hash_mac_addresses_num: int = field(
50661d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Maximum number of MAC addresses of hash filtering: (\d+)")
50761d5bc9bSLuca Vizzarro    )
50861d5bc9bSLuca Vizzarro    #: Minimum size of RX buffer
50961d5bc9bSLuca Vizzarro    min_rx_bufsize: int = field(metadata=TextParser.find_int(r"Minimum size of RX buffer: (\d+)"))
51061d5bc9bSLuca Vizzarro    #: Maximum configurable length of RX packet
51161d5bc9bSLuca Vizzarro    max_rx_packet_length: int = field(
51261d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Maximum configurable length of RX packet: (\d+)")
51361d5bc9bSLuca Vizzarro    )
51461d5bc9bSLuca Vizzarro    #: Maximum configurable size of LRO aggregated packet
51561d5bc9bSLuca Vizzarro    max_lro_packet_size: int = field(
51661d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Maximum configurable size of LRO aggregated packet: (\d+)")
51761d5bc9bSLuca Vizzarro    )
51861d5bc9bSLuca Vizzarro
51961d5bc9bSLuca Vizzarro    #: Current number of RX queues
52061d5bc9bSLuca Vizzarro    rx_queues_num: int = field(metadata=TextParser.find_int(r"Current number of RX queues: (\d+)"))
52161d5bc9bSLuca Vizzarro    #: Max possible RX queues
52261d5bc9bSLuca Vizzarro    max_rx_queues_num: int = field(metadata=TextParser.find_int(r"Max possible RX queues: (\d+)"))
52361d5bc9bSLuca Vizzarro    #: Max possible number of RXDs per queue
52461d5bc9bSLuca Vizzarro    max_queue_rxd_num: int = field(
52561d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Max possible number of RXDs per queue: (\d+)")
52661d5bc9bSLuca Vizzarro    )
52761d5bc9bSLuca Vizzarro    #: Min possible number of RXDs per queue
52861d5bc9bSLuca Vizzarro    min_queue_rxd_num: int = field(
52961d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Min possible number of RXDs per queue: (\d+)")
53061d5bc9bSLuca Vizzarro    )
53161d5bc9bSLuca Vizzarro    #: RXDs number alignment
53261d5bc9bSLuca Vizzarro    rxd_alignment_num: int = field(metadata=TextParser.find_int(r"RXDs number alignment: (\d+)"))
53361d5bc9bSLuca Vizzarro
53461d5bc9bSLuca Vizzarro    #: Current number of TX queues
53561d5bc9bSLuca Vizzarro    tx_queues_num: int = field(metadata=TextParser.find_int(r"Current number of TX queues: (\d+)"))
53661d5bc9bSLuca Vizzarro    #: Max possible TX queues
53761d5bc9bSLuca Vizzarro    max_tx_queues_num: int = field(metadata=TextParser.find_int(r"Max possible TX queues: (\d+)"))
53861d5bc9bSLuca Vizzarro    #: Max possible number of TXDs per queue
53961d5bc9bSLuca Vizzarro    max_queue_txd_num: int = field(
54061d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Max possible number of TXDs per queue: (\d+)")
54161d5bc9bSLuca Vizzarro    )
54261d5bc9bSLuca Vizzarro    #: Min possible number of TXDs per queue
54361d5bc9bSLuca Vizzarro    min_queue_txd_num: int = field(
54461d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Min possible number of TXDs per queue: (\d+)")
54561d5bc9bSLuca Vizzarro    )
54661d5bc9bSLuca Vizzarro    #: TXDs number alignment
54761d5bc9bSLuca Vizzarro    txd_alignment_num: int = field(metadata=TextParser.find_int(r"TXDs number alignment: (\d+)"))
54861d5bc9bSLuca Vizzarro    #: Max segment number per packet
54961d5bc9bSLuca Vizzarro    max_packet_segment_num: int = field(
55061d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Max segment number per packet: (\d+)")
55161d5bc9bSLuca Vizzarro    )
55261d5bc9bSLuca Vizzarro    #: Max segment number per MTU/TSO
55361d5bc9bSLuca Vizzarro    max_mtu_segment_num: int = field(
55461d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"Max segment number per MTU\/TSO: (\d+)")
55561d5bc9bSLuca Vizzarro    )
55661d5bc9bSLuca Vizzarro
55761d5bc9bSLuca Vizzarro    #:
55861d5bc9bSLuca Vizzarro    device_capabilities: DeviceCapabilitiesFlag = field(
55961d5bc9bSLuca Vizzarro        metadata=DeviceCapabilitiesFlag.make_parser(),
56061d5bc9bSLuca Vizzarro    )
56161d5bc9bSLuca Vizzarro    #:
562618d9140SJuraj Linkeš    device_error_handling_mode: DeviceErrorHandlingMode | None = field(
563618d9140SJuraj Linkeš        default=None, metadata=DeviceErrorHandlingMode.make_parser()
56461d5bc9bSLuca Vizzarro    )
56561d5bc9bSLuca Vizzarro    #:
56661d5bc9bSLuca Vizzarro    device_private_info: str | None = field(
56761d5bc9bSLuca Vizzarro        default=None,
56861d5bc9bSLuca Vizzarro        metadata=make_device_private_info_parser(),
56961d5bc9bSLuca Vizzarro    )
57061d5bc9bSLuca Vizzarro
57161d5bc9bSLuca Vizzarro    #:
57261d5bc9bSLuca Vizzarro    hash_key_size: int | None = field(
57361d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Hash key size in bytes: (\d+)")
57461d5bc9bSLuca Vizzarro    )
57561d5bc9bSLuca Vizzarro    #:
57661d5bc9bSLuca Vizzarro    redirection_table_size: int | None = field(
57761d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Redirection table size: (\d+)")
57861d5bc9bSLuca Vizzarro    )
57961d5bc9bSLuca Vizzarro    #:
58061d5bc9bSLuca Vizzarro    supported_rss_offload_flow_types: RSSOffloadTypesFlag = field(
58161d5bc9bSLuca Vizzarro        default=RSSOffloadTypesFlag(0), metadata=RSSOffloadTypesFlag.make_parser()
58261d5bc9bSLuca Vizzarro    )
58361d5bc9bSLuca Vizzarro
58461d5bc9bSLuca Vizzarro    #:
58561d5bc9bSLuca Vizzarro    mac_address: str | None = field(
58661d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find(r"MAC address: ([A-Fa-f0-9:]+)")
58761d5bc9bSLuca Vizzarro    )
58861d5bc9bSLuca Vizzarro    #:
58961d5bc9bSLuca Vizzarro    fw_version: str | None = field(
59061d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find(r"Firmware-version: ([^\r\n]+)")
59161d5bc9bSLuca Vizzarro    )
59261d5bc9bSLuca Vizzarro    #:
59361d5bc9bSLuca Vizzarro    dev_args: str | None = field(default=None, metadata=TextParser.find(r"Devargs: ([^\r\n]+)"))
59461d5bc9bSLuca Vizzarro    #: Socket id of the memory allocation
59561d5bc9bSLuca Vizzarro    mem_alloc_socket_id: int | None = field(
59661d5bc9bSLuca Vizzarro        default=None,
59761d5bc9bSLuca Vizzarro        metadata=TextParser.find_int(r"memory allocation on the socket: (\d+)"),
59861d5bc9bSLuca Vizzarro    )
59961d5bc9bSLuca Vizzarro    #:
60061d5bc9bSLuca Vizzarro    mtu: int | None = field(default=None, metadata=TextParser.find_int(r"MTU: (\d+)"))
60161d5bc9bSLuca Vizzarro
60261d5bc9bSLuca Vizzarro    #:
60361d5bc9bSLuca Vizzarro    vlan_offload: VLANOffloadFlag | None = field(
60461d5bc9bSLuca Vizzarro        default=None,
60561d5bc9bSLuca Vizzarro        metadata=VLANOffloadFlag.make_parser(),
60661d5bc9bSLuca Vizzarro    )
60761d5bc9bSLuca Vizzarro
60861d5bc9bSLuca Vizzarro    #: Maximum size of RX buffer
60961d5bc9bSLuca Vizzarro    max_rx_bufsize: int | None = field(
61061d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Maximum size of RX buffer: (\d+)")
61161d5bc9bSLuca Vizzarro    )
61261d5bc9bSLuca Vizzarro    #: Maximum number of VFs
61361d5bc9bSLuca Vizzarro    max_vfs_num: int | None = field(
61461d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Maximum number of VFs: (\d+)")
61561d5bc9bSLuca Vizzarro    )
61661d5bc9bSLuca Vizzarro    #: Maximum number of VMDq pools
61761d5bc9bSLuca Vizzarro    max_vmdq_pools_num: int | None = field(
61861d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Maximum number of VMDq pools: (\d+)")
61961d5bc9bSLuca Vizzarro    )
62061d5bc9bSLuca Vizzarro
62161d5bc9bSLuca Vizzarro    #:
62261d5bc9bSLuca Vizzarro    switch_name: str | None = field(
62361d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find(r"Switch name: ([\r\n]+)")
62461d5bc9bSLuca Vizzarro    )
62561d5bc9bSLuca Vizzarro    #:
62661d5bc9bSLuca Vizzarro    switch_domain_id: int | None = field(
62761d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Switch domain Id: (\d+)")
62861d5bc9bSLuca Vizzarro    )
62961d5bc9bSLuca Vizzarro    #:
63061d5bc9bSLuca Vizzarro    switch_port_id: int | None = field(
63161d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Switch Port Id: (\d+)")
63261d5bc9bSLuca Vizzarro    )
63361d5bc9bSLuca Vizzarro    #:
63461d5bc9bSLuca Vizzarro    switch_rx_domain: int | None = field(
63561d5bc9bSLuca Vizzarro        default=None, metadata=TextParser.find_int(r"Switch Rx domain: (\d+)")
63661d5bc9bSLuca Vizzarro    )
63761d5bc9bSLuca Vizzarro
63861d5bc9bSLuca Vizzarro
63953eacf3dSLuca Vizzarro@dataclass
64053eacf3dSLuca Vizzarroclass TestPmdPortStats(TextParser):
64153eacf3dSLuca Vizzarro    """Port statistics."""
64253eacf3dSLuca Vizzarro
64353eacf3dSLuca Vizzarro    #:
64453eacf3dSLuca Vizzarro    port_id: int = field(metadata=TextParser.find_int(r"NIC statistics for port (\d+)"))
64553eacf3dSLuca Vizzarro
64653eacf3dSLuca Vizzarro    #:
64753eacf3dSLuca Vizzarro    rx_packets: int = field(metadata=TextParser.find_int(r"RX-packets:\s+(\d+)"))
64853eacf3dSLuca Vizzarro    #:
64953eacf3dSLuca Vizzarro    rx_missed: int = field(metadata=TextParser.find_int(r"RX-missed:\s+(\d+)"))
65053eacf3dSLuca Vizzarro    #:
65153eacf3dSLuca Vizzarro    rx_bytes: int = field(metadata=TextParser.find_int(r"RX-bytes:\s+(\d+)"))
65253eacf3dSLuca Vizzarro    #:
65353eacf3dSLuca Vizzarro    rx_errors: int = field(metadata=TextParser.find_int(r"RX-errors:\s+(\d+)"))
65453eacf3dSLuca Vizzarro    #:
65553eacf3dSLuca Vizzarro    rx_nombuf: int = field(metadata=TextParser.find_int(r"RX-nombuf:\s+(\d+)"))
65653eacf3dSLuca Vizzarro
65753eacf3dSLuca Vizzarro    #:
65853eacf3dSLuca Vizzarro    tx_packets: int = field(metadata=TextParser.find_int(r"TX-packets:\s+(\d+)"))
65953eacf3dSLuca Vizzarro    #:
66053eacf3dSLuca Vizzarro    tx_errors: int = field(metadata=TextParser.find_int(r"TX-errors:\s+(\d+)"))
66153eacf3dSLuca Vizzarro    #:
66253eacf3dSLuca Vizzarro    tx_bytes: int = field(metadata=TextParser.find_int(r"TX-bytes:\s+(\d+)"))
66353eacf3dSLuca Vizzarro
66453eacf3dSLuca Vizzarro    #:
66553eacf3dSLuca Vizzarro    rx_pps: int = field(metadata=TextParser.find_int(r"Rx-pps:\s+(\d+)"))
66653eacf3dSLuca Vizzarro    #:
66753eacf3dSLuca Vizzarro    rx_bps: int = field(metadata=TextParser.find_int(r"Rx-bps:\s+(\d+)"))
66853eacf3dSLuca Vizzarro
66953eacf3dSLuca Vizzarro    #:
67053eacf3dSLuca Vizzarro    tx_pps: int = field(metadata=TextParser.find_int(r"Tx-pps:\s+(\d+)"))
67153eacf3dSLuca Vizzarro    #:
67253eacf3dSLuca Vizzarro    tx_bps: int = field(metadata=TextParser.find_int(r"Tx-bps:\s+(\d+)"))
67353eacf3dSLuca Vizzarro
67453eacf3dSLuca Vizzarro
675a91d5f47SJeremy Spewockclass PacketOffloadFlag(Flag):
676a91d5f47SJeremy Spewock    """Flag representing the Packet Offload Features Flags in DPDK.
677a91d5f47SJeremy Spewock
678a91d5f47SJeremy Spewock    Values in this class are taken from the definitions in the RTE MBUF core library in DPDK
679a91d5f47SJeremy Spewock    located in ``lib/mbuf/rte_mbuf_core.h``. It is expected that flag values in this class will
680a91d5f47SJeremy Spewock    match the values they are set to in said DPDK library with one exception; all values must be
681a91d5f47SJeremy Spewock    unique. For example, the definitions for unknown checksum flags in ``rte_mbuf_core.h`` are all
682a91d5f47SJeremy Spewock    set to :data:`0`, but it is valuable to distinguish between them in this framework. For this
683a91d5f47SJeremy Spewock    reason flags that are not unique in the DPDK library are set either to values within the
684a91d5f47SJeremy Spewock    RTE_MBUF_F_FIRST_FREE-RTE_MBUF_F_LAST_FREE range for Rx or shifted 61+ bits for Tx.
685a91d5f47SJeremy Spewock
686a91d5f47SJeremy Spewock    References:
687a91d5f47SJeremy Spewock        DPDK lib: ``lib/mbuf/rte_mbuf_core.h``
688a91d5f47SJeremy Spewock    """
689a91d5f47SJeremy Spewock
690a91d5f47SJeremy Spewock    # RX flags
691a91d5f47SJeremy Spewock
692a91d5f47SJeremy Spewock    #: The RX packet is a 802.1q VLAN packet, and the tci has been saved in mbuf->vlan_tci. If the
693a91d5f47SJeremy Spewock    #: flag RTE_MBUF_F_RX_VLAN_STRIPPED is also present, the VLAN header has been stripped from
694a91d5f47SJeremy Spewock    #: mbuf data, else it is still present.
695a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_VLAN = auto()
696a91d5f47SJeremy Spewock
697a91d5f47SJeremy Spewock    #: RX packet with RSS hash result.
698a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_RSS_HASH = auto()
699a91d5f47SJeremy Spewock
700a91d5f47SJeremy Spewock    #: RX packet with FDIR match indicate.
701a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_FDIR = auto()
702a91d5f47SJeremy Spewock
703a91d5f47SJeremy Spewock    #: This flag is set when the outermost IP header checksum is detected as wrong by the hardware.
704a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD = 1 << 5
705a91d5f47SJeremy Spewock
706a91d5f47SJeremy Spewock    #: A vlan has been stripped by the hardware and its tci is saved in mbuf->vlan_tci. This can
707a91d5f47SJeremy Spewock    #: only happen if vlan stripping is enabled in the RX configuration of the PMD. When
708a91d5f47SJeremy Spewock    #: RTE_MBUF_F_RX_VLAN_STRIPPED is set, RTE_MBUF_F_RX_VLAN must also be set.
709a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_VLAN_STRIPPED = auto()
710a91d5f47SJeremy Spewock
711a91d5f47SJeremy Spewock    #: No information about the RX IP checksum. Value is 0 in the DPDK library.
712a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN = 1 << 23
713a91d5f47SJeremy Spewock    #: The IP checksum in the packet is wrong.
714a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_IP_CKSUM_BAD = 1 << 4
715a91d5f47SJeremy Spewock    #: The IP checksum in the packet is valid.
716a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_IP_CKSUM_GOOD = 1 << 7
717a91d5f47SJeremy Spewock    #: The IP checksum is not correct in the packet data, but the integrity of the IP header is
718a91d5f47SJeremy Spewock    #: verified. Value is RTE_MBUF_F_RX_IP_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_GOOD in the DPDK
719a91d5f47SJeremy Spewock    #: library.
720a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_IP_CKSUM_NONE = 1 << 24
721a91d5f47SJeremy Spewock
722a91d5f47SJeremy Spewock    #: No information about the RX L4 checksum. Value is 0 in the DPDK library.
723a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_L4_CKSUM_UNKNOWN = 1 << 25
724a91d5f47SJeremy Spewock    #: The L4 checksum in the packet is wrong.
725a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_L4_CKSUM_BAD = 1 << 3
726a91d5f47SJeremy Spewock    #: The L4 checksum in the packet is valid.
727a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_L4_CKSUM_GOOD = 1 << 8
728a91d5f47SJeremy Spewock    #: The L4 checksum is not correct in the packet data, but the integrity of the L4 data is
729a91d5f47SJeremy Spewock    #: verified. Value is RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD in the DPDK
730a91d5f47SJeremy Spewock    #: library.
731a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_L4_CKSUM_NONE = 1 << 26
732a91d5f47SJeremy Spewock
733a91d5f47SJeremy Spewock    #: RX IEEE1588 L2 Ethernet PT Packet.
734a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_IEEE1588_PTP = 1 << 9
735a91d5f47SJeremy Spewock    #: RX IEEE1588 L2/L4 timestamped packet.
736a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_IEEE1588_TMST = 1 << 10
737a91d5f47SJeremy Spewock
738a91d5f47SJeremy Spewock    #: FD id reported if FDIR match.
739a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_FDIR_ID = 1 << 13
740a91d5f47SJeremy Spewock    #: Flexible bytes reported if FDIR match.
741a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_FDIR_FLX = 1 << 14
742a91d5f47SJeremy Spewock
743a91d5f47SJeremy Spewock    #: If both RTE_MBUF_F_RX_QINQ_STRIPPED and RTE_MBUF_F_RX_VLAN_STRIPPED are set, the 2 VLANs
744a91d5f47SJeremy Spewock    #: have been stripped by the hardware. If RTE_MBUF_F_RX_QINQ_STRIPPED is set and
745a91d5f47SJeremy Spewock    #: RTE_MBUF_F_RX_VLAN_STRIPPED is unset, only the outer VLAN is removed from packet data.
746a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_QINQ_STRIPPED = auto()
747a91d5f47SJeremy Spewock
748a91d5f47SJeremy Spewock    #: When packets are coalesced by a hardware or virtual driver, this flag can be set in the RX
749a91d5f47SJeremy Spewock    #: mbuf, meaning that the m->tso_segsz field is valid and is set to the segment size of
750a91d5f47SJeremy Spewock    #: original packets.
751a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_LRO = auto()
752a91d5f47SJeremy Spewock
753a91d5f47SJeremy Spewock    #: Indicate that security offload processing was applied on the RX packet.
754a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_SEC_OFFLOAD = 1 << 18
755a91d5f47SJeremy Spewock    #: Indicate that security offload processing failed on the RX packet.
756a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED = auto()
757a91d5f47SJeremy Spewock
758a91d5f47SJeremy Spewock    #: The RX packet is a double VLAN. If this flag is set, RTE_MBUF_F_RX_VLAN must also be set. If
759a91d5f47SJeremy Spewock    #: the flag RTE_MBUF_F_RX_QINQ_STRIPPED is also present, both VLANs headers have been stripped
760a91d5f47SJeremy Spewock    #: from mbuf data, else they are still present.
761a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_QINQ = auto()
762a91d5f47SJeremy Spewock
763a91d5f47SJeremy Spewock    #: No info about the outer RX L4 checksum. Value is 0 in the DPDK library.
764a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_OUTER_L4_CKSUM_UNKNOWN = 1 << 27
765a91d5f47SJeremy Spewock    #: The outer L4 checksum in the packet is wrong
766a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_OUTER_L4_CKSUM_BAD = 1 << 21
767a91d5f47SJeremy Spewock    #: The outer L4 checksum in the packet is valid
768a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_OUTER_L4_CKSUM_GOOD = 1 << 22
769a91d5f47SJeremy Spewock    #: Invalid outer L4 checksum state. Value is
770a91d5f47SJeremy Spewock    #: RTE_MBUF_F_RX_OUTER_L4_CKSUM_BAD | RTE_MBUF_F_RX_OUTER_L4_CKSUM_GOOD in the DPDK library.
771a91d5f47SJeremy Spewock    RTE_MBUF_F_RX_OUTER_L4_CKSUM_INVALID = 1 << 28
772a91d5f47SJeremy Spewock
773a91d5f47SJeremy Spewock    # TX flags
774a91d5f47SJeremy Spewock
775a91d5f47SJeremy Spewock    #: Outer UDP checksum offload flag. This flag is used for enabling outer UDP checksum in PMD.
776a91d5f47SJeremy Spewock    #: To use outer UDP checksum, the user either needs to enable the following in mbuf:
777a91d5f47SJeremy Spewock    #:
778a91d5f47SJeremy Spewock    #:  a) Fill outer_l2_len and outer_l3_len in mbuf.
779a91d5f47SJeremy Spewock    #:  b) Set the RTE_MBUF_F_TX_OUTER_UDP_CKSUM flag.
780a91d5f47SJeremy Spewock    #:  c) Set the RTE_MBUF_F_TX_OUTER_IPV4 or RTE_MBUF_F_TX_OUTER_IPV6 flag.
781a91d5f47SJeremy Spewock    #:
782a91d5f47SJeremy Spewock    #: Or configure RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM offload flag.
783a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_OUTER_UDP_CKSUM = 1 << 41
784a91d5f47SJeremy Spewock
785a91d5f47SJeremy Spewock    #: UDP Fragmentation Offload flag. This flag is used for enabling UDP fragmentation in SW or in
786a91d5f47SJeremy Spewock    #: HW.
787a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_UDP_SEG = auto()
788a91d5f47SJeremy Spewock
789a91d5f47SJeremy Spewock    #: Request security offload processing on the TX packet. To use Tx security offload, the user
790a91d5f47SJeremy Spewock    #: needs to fill l2_len in mbuf indicating L2 header size and where L3 header starts.
791a91d5f47SJeremy Spewock    #: Similarly, l3_len should also be filled along with ol_flags reflecting current L3 type.
792a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_SEC_OFFLOAD = auto()
793a91d5f47SJeremy Spewock
794a91d5f47SJeremy Spewock    #: Offload the MACsec. This flag must be set by the application to enable this offload feature
795a91d5f47SJeremy Spewock    #: for a packet to be transmitted.
796a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_MACSEC = auto()
797a91d5f47SJeremy Spewock
798a91d5f47SJeremy Spewock    # Bits 45:48 are used for the tunnel type in ``lib/mbuf/rte_mbuf_core.h``, but some are modified
799a91d5f47SJeremy Spewock    # in this Flag to maintain uniqueness. The tunnel type must be specified for TSO or checksum on
800a91d5f47SJeremy Spewock    # the inner part of tunnel packets. These flags can be used with RTE_MBUF_F_TX_TCP_SEG for TSO,
801a91d5f47SJeremy Spewock    # or RTE_MBUF_F_TX_xxx_CKSUM. The mbuf fields for inner and outer header lengths are required:
802a91d5f47SJeremy Spewock    # outer_l2_len, outer_l3_len, l2_len, l3_len, l4_len and tso_segsz for TSO.
803a91d5f47SJeremy Spewock
804a91d5f47SJeremy Spewock    #:
805a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_VXLAN = 1 << 45
806a91d5f47SJeremy Spewock    #:
807a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_GRE = 1 << 46
808a91d5f47SJeremy Spewock    #: Value is 3 << 45 in the DPDK library.
809a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_IPIP = 1 << 61
810a91d5f47SJeremy Spewock    #:
811a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_GENEVE = 1 << 47
812a91d5f47SJeremy Spewock    #: TX packet with MPLS-in-UDP RFC 7510 header. Value is 5 << 45 in the DPDK library.
813a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_MPLSINUDP = 1 << 62
814a91d5f47SJeremy Spewock    #: Value is 6 << 45 in the DPDK library.
815a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE = 1 << 63
816a91d5f47SJeremy Spewock    #: Value is 7 << 45 in the DPDK library.
817a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_GTP = 1 << 64
818a91d5f47SJeremy Spewock    #:
819a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_ESP = 1 << 48
820a91d5f47SJeremy Spewock    #: Generic IP encapsulated tunnel type, used for TSO and checksum offload. This can be used for
821a91d5f47SJeremy Spewock    #: tunnels which are not standards or listed above. It is preferred to use specific tunnel
822a91d5f47SJeremy Spewock    #: flags like RTE_MBUF_F_TX_TUNNEL_GRE or RTE_MBUF_F_TX_TUNNEL_IPIP if possible. The ethdev
823a91d5f47SJeremy Spewock    #: must be configured with RTE_ETH_TX_OFFLOAD_IP_TNL_TSO.  Outer and inner checksums are done
824a91d5f47SJeremy Spewock    #: according to the existing flags like RTE_MBUF_F_TX_xxx_CKSUM. Specific tunnel headers that
825a91d5f47SJeremy Spewock    #: contain payload length, sequence id or checksum are not expected to be updated. Value is
826a91d5f47SJeremy Spewock    #: 0xD << 45 in the DPDK library.
827a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_IP = 1 << 65
828a91d5f47SJeremy Spewock    #: Generic UDP encapsulated tunnel type, used for TSO and checksum offload. UDP tunnel type
829a91d5f47SJeremy Spewock    #: implies outer IP layer. It can be used for tunnels which are not standards or listed above.
830a91d5f47SJeremy Spewock    #: It is preferred to use specific tunnel flags like RTE_MBUF_F_TX_TUNNEL_VXLAN if possible.
831a91d5f47SJeremy Spewock    #: The ethdev must be configured with RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO. Outer and inner checksums
832a91d5f47SJeremy Spewock    #: are done according to the existing flags like RTE_MBUF_F_TX_xxx_CKSUM. Specific tunnel
833a91d5f47SJeremy Spewock    #: headers that contain payload length, sequence id or checksum are not expected to be updated.
834a91d5f47SJeremy Spewock    #: value is 0xE << 45 in the DPDK library.
835a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TUNNEL_UDP = 1 << 66
836a91d5f47SJeremy Spewock
837a91d5f47SJeremy Spewock    #: Double VLAN insertion (QinQ) request to driver, driver may offload the insertion based on
838a91d5f47SJeremy Spewock    #: device capability. Mbuf 'vlan_tci' & 'vlan_tci_outer' must be valid when this flag is set.
839a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_QINQ = 1 << 49
840a91d5f47SJeremy Spewock
841a91d5f47SJeremy Spewock    #: TCP segmentation offload. To enable this offload feature for a packet to be transmitted on
842a91d5f47SJeremy Spewock    #: hardware supporting TSO:
843a91d5f47SJeremy Spewock    #:
844a91d5f47SJeremy Spewock    #:  - set the RTE_MBUF_F_TX_TCP_SEG flag in mbuf->ol_flags (this flag implies
845a91d5f47SJeremy Spewock    #:      RTE_MBUF_F_TX_TCP_CKSUM)
846a91d5f47SJeremy Spewock    #:  - set the flag RTE_MBUF_F_TX_IPV4 or RTE_MBUF_F_TX_IPV6
847a91d5f47SJeremy Spewock    #:      * if it's IPv4, set the RTE_MBUF_F_TX_IP_CKSUM flag
848a91d5f47SJeremy Spewock    #:  - fill the mbuf offload information: l2_len, l3_len, l4_len, tso_segsz
849a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TCP_SEG = auto()
850a91d5f47SJeremy Spewock
851a91d5f47SJeremy Spewock    #: TX IEEE1588 packet to timestamp.
852a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_IEEE1588_TMST = auto()
853a91d5f47SJeremy Spewock
854a91d5f47SJeremy Spewock    # Bits 52+53 used for L4 packet type with checksum enabled in ``lib/mbuf/rte_mbuf_core.h`` but
855a91d5f47SJeremy Spewock    # some values must be modified in this framework to maintain uniqueness. To use hardware
856a91d5f47SJeremy Spewock    # L4 checksum offload, the user needs to:
857a91d5f47SJeremy Spewock    #
858a91d5f47SJeremy Spewock    # - fill l2_len and l3_len in mbuf
859a91d5f47SJeremy Spewock    # - set the flags RTE_MBUF_F_TX_TCP_CKSUM, RTE_MBUF_F_TX_SCTP_CKSUM or
860a91d5f47SJeremy Spewock    #   RTE_MBUF_F_TX_UDP_CKSUM
861a91d5f47SJeremy Spewock    # - set the flag RTE_MBUF_F_TX_IPV4 or RTE_MBUF_F_TX_IPV6
862a91d5f47SJeremy Spewock
863a91d5f47SJeremy Spewock    #: Disable L4 cksum of TX pkt. Value is 0 in the DPDK library.
864a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_L4_NO_CKSUM = 1 << 67
865a91d5f47SJeremy Spewock    #: TCP cksum of TX pkt. Computed by NIC.
866a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_TCP_CKSUM = 1 << 52
867a91d5f47SJeremy Spewock    #: SCTP cksum of TX pkt. Computed by NIC.
868a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_SCTP_CKSUM = 1 << 53
869a91d5f47SJeremy Spewock    #: UDP cksum of TX pkt. Computed by NIC. Value is 3 << 52 in the DPDK library.
870a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_UDP_CKSUM = 1 << 68
871a91d5f47SJeremy Spewock
872a91d5f47SJeremy Spewock    #: Offload the IP checksum in the hardware. The flag RTE_MBUF_F_TX_IPV4 should also be set by
873a91d5f47SJeremy Spewock    #: the application, although a PMD will only check RTE_MBUF_F_TX_IP_CKSUM.
874a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_IP_CKSUM = 1 << 54
875a91d5f47SJeremy Spewock
876a91d5f47SJeremy Spewock    #: Packet is IPv4. This flag must be set when using any offload feature (TSO, L3 or L4
877a91d5f47SJeremy Spewock    #: checksum) to tell the NIC that the packet is an IPv4 packet. If the packet is a tunneled
878a91d5f47SJeremy Spewock    #: packet, this flag is related to the inner headers.
879a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_IPV4 = auto()
880a91d5f47SJeremy Spewock    #: Packet is IPv6. This flag must be set when using an offload feature (TSO or L4 checksum) to
881a91d5f47SJeremy Spewock    #: tell the NIC that the packet is an IPv6 packet. If the packet is a tunneled packet, this
882a91d5f47SJeremy Spewock    #: flag is related to the inner headers.
883a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_IPV6 = auto()
884a91d5f47SJeremy Spewock    #: VLAN tag insertion request to driver, driver may offload the insertion based on the device
885a91d5f47SJeremy Spewock    #: capability. mbuf 'vlan_tci' field must be valid when this flag is set.
886a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_VLAN = auto()
887a91d5f47SJeremy Spewock
888a91d5f47SJeremy Spewock    #: Offload the IP checksum of an external header in the hardware. The flag
889a91d5f47SJeremy Spewock    #: RTE_MBUF_F_TX_OUTER_IPV4 should also be set by the application, although a PMD will only
890a91d5f47SJeremy Spewock    #: check RTE_MBUF_F_TX_OUTER_IP_CKSUM.
891a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_OUTER_IP_CKSUM = auto()
892a91d5f47SJeremy Spewock    #: Packet outer header is IPv4. This flag must be set when using any outer offload feature (L3
893a91d5f47SJeremy Spewock    #: or L4 checksum) to tell the NIC that the outer header of the tunneled packet is an IPv4
894a91d5f47SJeremy Spewock    #: packet.
895a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_OUTER_IPV4 = auto()
896a91d5f47SJeremy Spewock    #: Packet outer header is IPv6. This flag must be set when using any outer offload feature (L4
897a91d5f47SJeremy Spewock    #: checksum) to tell the NIC that the outer header of the tunneled packet is an IPv6 packet.
898a91d5f47SJeremy Spewock    RTE_MBUF_F_TX_OUTER_IPV6 = auto()
899a91d5f47SJeremy Spewock
900a91d5f47SJeremy Spewock    @classmethod
901a91d5f47SJeremy Spewock    def from_list_string(cls, names: str) -> Self:
902a91d5f47SJeremy Spewock        """Makes a flag from a whitespace-separated list of names.
903a91d5f47SJeremy Spewock
904a91d5f47SJeremy Spewock        Args:
905a91d5f47SJeremy Spewock            names: a whitespace-separated list containing the members of this flag.
906a91d5f47SJeremy Spewock
907a91d5f47SJeremy Spewock        Returns:
908a91d5f47SJeremy Spewock            An instance of this flag.
909a91d5f47SJeremy Spewock        """
910a91d5f47SJeremy Spewock        flag = cls(0)
911a91d5f47SJeremy Spewock        for name in names.split():
912a91d5f47SJeremy Spewock            flag |= cls.from_str(name)
913a91d5f47SJeremy Spewock        return flag
914a91d5f47SJeremy Spewock
915a91d5f47SJeremy Spewock    @classmethod
916a91d5f47SJeremy Spewock    def from_str(cls, name: str) -> Self:
917a91d5f47SJeremy Spewock        """Makes a flag matching the supplied name.
918a91d5f47SJeremy Spewock
919a91d5f47SJeremy Spewock        Args:
920a91d5f47SJeremy Spewock            name: a valid member of this flag in text
921a91d5f47SJeremy Spewock        Returns:
922a91d5f47SJeremy Spewock            An instance of this flag.
923a91d5f47SJeremy Spewock        """
924a91d5f47SJeremy Spewock        member_name = name.strip().replace("-", "_")
925a91d5f47SJeremy Spewock        return cls[member_name]
926a91d5f47SJeremy Spewock
927a91d5f47SJeremy Spewock    @classmethod
928a91d5f47SJeremy Spewock    def make_parser(cls) -> ParserFn:
929a91d5f47SJeremy Spewock        """Makes a parser function.
930a91d5f47SJeremy Spewock
931a91d5f47SJeremy Spewock        Returns:
932a91d5f47SJeremy Spewock            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
933a91d5f47SJeremy Spewock                parser function that makes an instance of this flag from text.
934a91d5f47SJeremy Spewock        """
935a91d5f47SJeremy Spewock        return TextParser.wrap(
936a91d5f47SJeremy Spewock            TextParser.find(r"ol_flags: ([^\n]+)"),
937a91d5f47SJeremy Spewock            cls.from_list_string,
938a91d5f47SJeremy Spewock        )
939a91d5f47SJeremy Spewock
940a91d5f47SJeremy Spewock
941a91d5f47SJeremy Spewockclass RtePTypes(Flag):
942a91d5f47SJeremy Spewock    """Flag representing possible packet types in DPDK verbose output.
943a91d5f47SJeremy Spewock
944a91d5f47SJeremy Spewock    Values in this class are derived from definitions in the RTE MBUF ptype library in DPDK located
945a91d5f47SJeremy Spewock    in ``lib/mbuf/rte_mbuf_ptype.h``. Specifically, the names of values in this class should match
946a91d5f47SJeremy Spewock    the possible return options from the functions ``rte_get_ptype_*_name`` in ``rte_mbuf_ptype.c``.
947a91d5f47SJeremy Spewock
948a91d5f47SJeremy Spewock    References:
949a91d5f47SJeremy Spewock        DPDK lib: ``lib/mbuf/rte_mbuf_ptype.h``
950a91d5f47SJeremy Spewock        DPDK ptype name formatting functions: ``lib/mbuf/rte_mbuf_ptype.c:rte_get_ptype_*_name()``
951a91d5f47SJeremy Spewock    """
952a91d5f47SJeremy Spewock
953a91d5f47SJeremy Spewock    # L2
954a91d5f47SJeremy Spewock    #: Ethernet packet type. This is used for outer packet for tunneling cases.
955a91d5f47SJeremy Spewock    L2_ETHER = auto()
956a91d5f47SJeremy Spewock    #: Ethernet packet type for time sync.
957a91d5f47SJeremy Spewock    L2_ETHER_TIMESYNC = auto()
958a91d5f47SJeremy Spewock    #: ARP (Address Resolution Protocol) packet type.
959a91d5f47SJeremy Spewock    L2_ETHER_ARP = auto()
960a91d5f47SJeremy Spewock    #: LLDP (Link Layer Discovery Protocol) packet type.
961a91d5f47SJeremy Spewock    L2_ETHER_LLDP = auto()
962a91d5f47SJeremy Spewock    #: NSH (Network Service Header) packet type.
963a91d5f47SJeremy Spewock    L2_ETHER_NSH = auto()
964a91d5f47SJeremy Spewock    #: VLAN packet type.
965a91d5f47SJeremy Spewock    L2_ETHER_VLAN = auto()
966a91d5f47SJeremy Spewock    #: QinQ packet type.
967a91d5f47SJeremy Spewock    L2_ETHER_QINQ = auto()
968a91d5f47SJeremy Spewock    #: PPPOE packet type.
969a91d5f47SJeremy Spewock    L2_ETHER_PPPOE = auto()
970a91d5f47SJeremy Spewock    #: FCoE packet type..
971a91d5f47SJeremy Spewock    L2_ETHER_FCOE = auto()
972a91d5f47SJeremy Spewock    #: MPLS packet type.
973a91d5f47SJeremy Spewock    L2_ETHER_MPLS = auto()
974a91d5f47SJeremy Spewock    #: No L2 packet information.
975a91d5f47SJeremy Spewock    L2_UNKNOWN = auto()
976a91d5f47SJeremy Spewock
977a91d5f47SJeremy Spewock    # L3
978a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 4 packet type. This is used for outer packet for tunneling
979a91d5f47SJeremy Spewock    #: cases, and does not contain any header option.
980a91d5f47SJeremy Spewock    L3_IPV4 = auto()
981a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 4 packet type. This is used for outer packet for tunneling
982a91d5f47SJeremy Spewock    #: cases, and contains header options.
983a91d5f47SJeremy Spewock    L3_IPV4_EXT = auto()
984a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 6 packet type. This is used for outer packet for tunneling
985a91d5f47SJeremy Spewock    #: cases, and does not contain any extension header.
986a91d5f47SJeremy Spewock    L3_IPV6 = auto()
987a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 4 packet type. This is used for outer packet for tunneling
988a91d5f47SJeremy Spewock    #: cases, and may or maynot contain header options.
989a91d5f47SJeremy Spewock    L3_IPV4_EXT_UNKNOWN = auto()
990a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 6 packet type. This is used for outer packet for tunneling
991a91d5f47SJeremy Spewock    #: cases, and contains extension headers.
992a91d5f47SJeremy Spewock    L3_IPV6_EXT = auto()
993a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 6 packet type. This is used for outer packet for tunneling
994a91d5f47SJeremy Spewock    #: cases, and may or maynot contain extension headers.
995a91d5f47SJeremy Spewock    L3_IPV6_EXT_UNKNOWN = auto()
996a91d5f47SJeremy Spewock    #: No L3 packet information.
997a91d5f47SJeremy Spewock    L3_UNKNOWN = auto()
998a91d5f47SJeremy Spewock
999a91d5f47SJeremy Spewock    # L4
1000a91d5f47SJeremy Spewock    #: TCP (Transmission Control Protocol) packet type. This is used for outer packet for tunneling
1001a91d5f47SJeremy Spewock    #: cases.
1002a91d5f47SJeremy Spewock    L4_TCP = auto()
1003a91d5f47SJeremy Spewock    #: UDP (User Datagram Protocol) packet type. This is used for outer packet for tunneling cases.
1004a91d5f47SJeremy Spewock    L4_UDP = auto()
1005a91d5f47SJeremy Spewock    #: Fragmented IP (Internet Protocol) packet type. This is used for outer packet for tunneling
1006a91d5f47SJeremy Spewock    #: cases and refers to those packets of any IP types which can be recognized as fragmented. A
1007a91d5f47SJeremy Spewock    #: fragmented packet cannot be recognized as any other L4 types (RTE_PTYPE_L4_TCP,
1008a91d5f47SJeremy Spewock    #: RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP, RTE_PTYPE_L4_NONFRAG).
1009a91d5f47SJeremy Spewock    L4_FRAG = auto()
1010a91d5f47SJeremy Spewock    #: SCTP (Stream Control Transmission Protocol) packet type. This is used for outer packet for
1011a91d5f47SJeremy Spewock    #: tunneling cases.
1012a91d5f47SJeremy Spewock    L4_SCTP = auto()
1013a91d5f47SJeremy Spewock    #: ICMP (Internet Control Message Protocol) packet type. This is used for outer packet for
1014a91d5f47SJeremy Spewock    #: tunneling cases.
1015a91d5f47SJeremy Spewock    L4_ICMP = auto()
1016a91d5f47SJeremy Spewock    #: Non-fragmented IP (Internet Protocol) packet type. This is used for outer packet for
1017a91d5f47SJeremy Spewock    #: tunneling cases and refers to those packets of any IP types, that cannot be recognized as
1018a91d5f47SJeremy Spewock    #: any of the above L4 types (RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_FRAG,
1019a91d5f47SJeremy Spewock    #: RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP).
1020a91d5f47SJeremy Spewock    L4_NONFRAG = auto()
1021a91d5f47SJeremy Spewock    #: IGMP (Internet Group Management Protocol) packet type.
1022a91d5f47SJeremy Spewock    L4_IGMP = auto()
1023a91d5f47SJeremy Spewock    #: No L4 packet information.
1024a91d5f47SJeremy Spewock    L4_UNKNOWN = auto()
1025a91d5f47SJeremy Spewock
1026a91d5f47SJeremy Spewock    # Tunnel
1027a91d5f47SJeremy Spewock    #: IP (Internet Protocol) in IP (Internet Protocol) tunneling packet type.
1028a91d5f47SJeremy Spewock    TUNNEL_IP = auto()
1029a91d5f47SJeremy Spewock    #: GRE (Generic Routing Encapsulation) tunneling packet type.
1030a91d5f47SJeremy Spewock    TUNNEL_GRE = auto()
1031a91d5f47SJeremy Spewock    #: VXLAN (Virtual eXtensible Local Area Network) tunneling packet type.
1032a91d5f47SJeremy Spewock    TUNNEL_VXLAN = auto()
1033a91d5f47SJeremy Spewock    #: NVGRE (Network Virtualization using Generic Routing Encapsulation) tunneling packet type.
1034a91d5f47SJeremy Spewock    TUNNEL_NVGRE = auto()
1035a91d5f47SJeremy Spewock    #: GENEVE (Generic Network Virtualization Encapsulation) tunneling packet type.
1036a91d5f47SJeremy Spewock    TUNNEL_GENEVE = auto()
1037a91d5f47SJeremy Spewock    #: Tunneling packet type of Teredo, VXLAN (Virtual eXtensible Local Area Network) or GRE
1038a91d5f47SJeremy Spewock    #: (Generic Routing Encapsulation) could be recognized as this packet type, if they can not be
1039a91d5f47SJeremy Spewock    #: recognized independently as of hardware capability.
1040a91d5f47SJeremy Spewock    TUNNEL_GRENAT = auto()
1041a91d5f47SJeremy Spewock    #: GTP-C (GPRS Tunnelling Protocol) control tunneling packet type.
1042a91d5f47SJeremy Spewock    TUNNEL_GTPC = auto()
1043a91d5f47SJeremy Spewock    #: GTP-U (GPRS Tunnelling Protocol) user data tunneling packet type.
1044a91d5f47SJeremy Spewock    TUNNEL_GTPU = auto()
1045a91d5f47SJeremy Spewock    #: ESP (IP Encapsulating Security Payload) tunneling packet type.
1046a91d5f47SJeremy Spewock    TUNNEL_ESP = auto()
1047a91d5f47SJeremy Spewock    #: L2TP (Layer 2 Tunneling Protocol) tunneling packet type.
1048a91d5f47SJeremy Spewock    TUNNEL_L2TP = auto()
1049a91d5f47SJeremy Spewock    #: VXLAN-GPE (VXLAN Generic Protocol Extension) tunneling packet type.
1050a91d5f47SJeremy Spewock    TUNNEL_VXLAN_GPE = auto()
1051a91d5f47SJeremy Spewock    #: MPLS-in-UDP tunneling packet type (RFC 7510).
1052a91d5f47SJeremy Spewock    TUNNEL_MPLS_IN_UDP = auto()
1053a91d5f47SJeremy Spewock    #: MPLS-in-GRE tunneling packet type (RFC 4023).
1054a91d5f47SJeremy Spewock    TUNNEL_MPLS_IN_GRE = auto()
1055a91d5f47SJeremy Spewock    #: No tunnel information found on the packet.
1056a91d5f47SJeremy Spewock    TUNNEL_UNKNOWN = auto()
1057a91d5f47SJeremy Spewock
1058a91d5f47SJeremy Spewock    # Inner L2
1059a91d5f47SJeremy Spewock    #: Ethernet packet type. This is used for inner packet type only.
1060a91d5f47SJeremy Spewock    INNER_L2_ETHER = auto()
1061a91d5f47SJeremy Spewock    #: Ethernet packet type with VLAN (Virtual Local Area Network) tag.
1062a91d5f47SJeremy Spewock    INNER_L2_ETHER_VLAN = auto()
1063a91d5f47SJeremy Spewock    #: QinQ packet type.
1064a91d5f47SJeremy Spewock    INNER_L2_ETHER_QINQ = auto()
1065a91d5f47SJeremy Spewock    #: No inner L2 information found on the packet.
1066a91d5f47SJeremy Spewock    INNER_L2_UNKNOWN = auto()
1067a91d5f47SJeremy Spewock
1068a91d5f47SJeremy Spewock    # Inner L3
1069a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 4 packet type. This is used for inner packet only, and does
1070a91d5f47SJeremy Spewock    #: not contain any header option.
1071a91d5f47SJeremy Spewock    INNER_L3_IPV4 = auto()
1072a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 4 packet type. This is used for inner packet only, and
1073a91d5f47SJeremy Spewock    #: contains header options.
1074a91d5f47SJeremy Spewock    INNER_L3_IPV4_EXT = auto()
1075a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 6 packet type. This is used for inner packet only, and does
1076a91d5f47SJeremy Spewock    #: not contain any extension header.
1077a91d5f47SJeremy Spewock    INNER_L3_IPV6 = auto()
1078a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 4 packet type. This is used for inner packet only, and may or
1079a91d5f47SJeremy Spewock    #: may not contain header options.
1080a91d5f47SJeremy Spewock    INNER_L3_IPV4_EXT_UNKNOWN = auto()
1081a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 6 packet type. This is used for inner packet only, and
1082a91d5f47SJeremy Spewock    #: contains extension headers.
1083a91d5f47SJeremy Spewock    INNER_L3_IPV6_EXT = auto()
1084a91d5f47SJeremy Spewock    #: IP (Internet Protocol) version 6 packet type. This is used for inner packet only, and may or
1085a91d5f47SJeremy Spewock    #: may not contain extension headers.
1086a91d5f47SJeremy Spewock    INNER_L3_IPV6_EXT_UNKNOWN = auto()
1087a91d5f47SJeremy Spewock    #: No inner L3 information found on the packet.
1088a91d5f47SJeremy Spewock    INNER_L3_UNKNOWN = auto()
1089a91d5f47SJeremy Spewock
1090a91d5f47SJeremy Spewock    # Inner L4
1091a91d5f47SJeremy Spewock    #: TCP (Transmission Control Protocol) packet type. This is used for inner packet only.
1092a91d5f47SJeremy Spewock    INNER_L4_TCP = auto()
1093a91d5f47SJeremy Spewock    #: UDP (User Datagram Protocol) packet type. This is used for inner packet only.
1094a91d5f47SJeremy Spewock    INNER_L4_UDP = auto()
1095a91d5f47SJeremy Spewock    #: Fragmented IP (Internet Protocol) packet type. This is used for inner packet only, and may
1096a91d5f47SJeremy Spewock    #: or maynot have a layer 4 packet.
1097a91d5f47SJeremy Spewock    INNER_L4_FRAG = auto()
1098a91d5f47SJeremy Spewock    #: SCTP (Stream Control Transmission Protocol) packet type. This is used for inner packet only.
1099a91d5f47SJeremy Spewock    INNER_L4_SCTP = auto()
1100a91d5f47SJeremy Spewock    #: ICMP (Internet Control Message Protocol) packet type. This is used for inner packet only.
1101a91d5f47SJeremy Spewock    INNER_L4_ICMP = auto()
1102a91d5f47SJeremy Spewock    #: Non-fragmented IP (Internet Protocol) packet type. It is used for inner packet only, and may
1103a91d5f47SJeremy Spewock    #: or may not have other unknown layer 4 packet types.
1104a91d5f47SJeremy Spewock    INNER_L4_NONFRAG = auto()
1105a91d5f47SJeremy Spewock    #: No inner L4 information found on the packet.
1106a91d5f47SJeremy Spewock    INNER_L4_UNKNOWN = auto()
1107a91d5f47SJeremy Spewock
1108a91d5f47SJeremy Spewock    @classmethod
1109a91d5f47SJeremy Spewock    def from_list_string(cls, names: str) -> Self:
1110a91d5f47SJeremy Spewock        """Makes a flag from a whitespace-separated list of names.
1111a91d5f47SJeremy Spewock
1112a91d5f47SJeremy Spewock        Args:
1113a91d5f47SJeremy Spewock            names: a whitespace-separated list containing the members of this flag.
1114a91d5f47SJeremy Spewock
1115a91d5f47SJeremy Spewock        Returns:
1116a91d5f47SJeremy Spewock            An instance of this flag.
1117a91d5f47SJeremy Spewock        """
1118a91d5f47SJeremy Spewock        flag = cls(0)
1119a91d5f47SJeremy Spewock        for name in names.split():
1120a91d5f47SJeremy Spewock            flag |= cls.from_str(name)
1121a91d5f47SJeremy Spewock        return flag
1122a91d5f47SJeremy Spewock
1123a91d5f47SJeremy Spewock    @classmethod
1124a91d5f47SJeremy Spewock    def from_str(cls, name: str) -> Self:
1125a91d5f47SJeremy Spewock        """Makes a flag matching the supplied name.
1126a91d5f47SJeremy Spewock
1127a91d5f47SJeremy Spewock        Args:
1128a91d5f47SJeremy Spewock            name: a valid member of this flag in text
1129a91d5f47SJeremy Spewock        Returns:
1130a91d5f47SJeremy Spewock            An instance of this flag.
1131a91d5f47SJeremy Spewock        """
1132a91d5f47SJeremy Spewock        member_name = name.strip().replace("-", "_")
1133a91d5f47SJeremy Spewock        return cls[member_name]
1134a91d5f47SJeremy Spewock
1135a91d5f47SJeremy Spewock    @classmethod
1136a91d5f47SJeremy Spewock    def make_parser(cls, hw: bool) -> ParserFn:
1137a91d5f47SJeremy Spewock        """Makes a parser function.
1138a91d5f47SJeremy Spewock
1139a91d5f47SJeremy Spewock        Args:
1140a91d5f47SJeremy Spewock            hw: Whether to make a parser for hardware ptypes or software ptypes. If :data:`True`,
1141a91d5f47SJeremy Spewock                hardware ptypes will be collected, otherwise software pytpes will.
1142a91d5f47SJeremy Spewock
1143a91d5f47SJeremy Spewock        Returns:
1144a91d5f47SJeremy Spewock            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
1145a91d5f47SJeremy Spewock                parser function that makes an instance of this flag from text.
1146a91d5f47SJeremy Spewock        """
1147a91d5f47SJeremy Spewock        return TextParser.wrap(
1148a91d5f47SJeremy Spewock            TextParser.find(f"{'hw' if hw else 'sw'} ptype: ([^-]+)"),
1149a91d5f47SJeremy Spewock            cls.from_list_string,
1150a91d5f47SJeremy Spewock        )
1151a91d5f47SJeremy Spewock
1152a91d5f47SJeremy Spewock
1153a91d5f47SJeremy Spewock@dataclass
1154a91d5f47SJeremy Spewockclass TestPmdVerbosePacket(TextParser):
1155a91d5f47SJeremy Spewock    """Packet information provided by verbose output in Testpmd.
1156a91d5f47SJeremy Spewock
1157a91d5f47SJeremy Spewock    This dataclass expects that packet information be prepended with the starting line of packet
1158a91d5f47SJeremy Spewock    bursts. Specifically, the line that reads "port X/queue Y: sent/received Z packets".
1159a91d5f47SJeremy Spewock    """
1160a91d5f47SJeremy Spewock
1161a91d5f47SJeremy Spewock    #: ID of the port that handled the packet.
1162a91d5f47SJeremy Spewock    port_id: int = field(metadata=TextParser.find_int(r"port (\d+)/queue \d+"))
1163a91d5f47SJeremy Spewock    #: ID of the queue that handled the packet.
1164a91d5f47SJeremy Spewock    queue_id: int = field(metadata=TextParser.find_int(r"port \d+/queue (\d+)"))
1165a91d5f47SJeremy Spewock    #: Whether the packet was received or sent by the queue/port.
1166a91d5f47SJeremy Spewock    was_received: bool = field(metadata=TextParser.find(r"received \d+ packets"))
1167a91d5f47SJeremy Spewock    #:
1168a91d5f47SJeremy Spewock    src_mac: str = field(metadata=TextParser.find(f"src=({REGEX_FOR_MAC_ADDRESS})"))
1169a91d5f47SJeremy Spewock    #:
1170a91d5f47SJeremy Spewock    dst_mac: str = field(metadata=TextParser.find(f"dst=({REGEX_FOR_MAC_ADDRESS})"))
1171a91d5f47SJeremy Spewock    #: Memory pool the packet was handled on.
1172a91d5f47SJeremy Spewock    pool: str = field(metadata=TextParser.find(r"pool=(\S+)"))
1173a91d5f47SJeremy Spewock    #: Packet type in hex.
1174a91d5f47SJeremy Spewock    p_type: int = field(metadata=TextParser.find_int(r"type=(0x[a-fA-F\d]+)"))
1175a91d5f47SJeremy Spewock    #:
1176a91d5f47SJeremy Spewock    length: int = field(metadata=TextParser.find_int(r"length=(\d+)"))
1177a91d5f47SJeremy Spewock    #: Number of segments in the packet.
1178a91d5f47SJeremy Spewock    nb_segs: int = field(metadata=TextParser.find_int(r"nb_segs=(\d+)"))
1179a91d5f47SJeremy Spewock    #: Hardware packet type.
1180a91d5f47SJeremy Spewock    hw_ptype: RtePTypes = field(metadata=RtePTypes.make_parser(hw=True))
1181a91d5f47SJeremy Spewock    #: Software packet type.
1182a91d5f47SJeremy Spewock    sw_ptype: RtePTypes = field(metadata=RtePTypes.make_parser(hw=False))
1183a91d5f47SJeremy Spewock    #:
1184a91d5f47SJeremy Spewock    l2_len: int = field(metadata=TextParser.find_int(r"l2_len=(\d+)"))
1185a91d5f47SJeremy Spewock    #:
1186a91d5f47SJeremy Spewock    ol_flags: PacketOffloadFlag = field(metadata=PacketOffloadFlag.make_parser())
1187a91d5f47SJeremy Spewock    #: RSS hash of the packet in hex.
1188a91d5f47SJeremy Spewock    rss_hash: int | None = field(
1189a91d5f47SJeremy Spewock        default=None, metadata=TextParser.find_int(r"RSS hash=(0x[a-fA-F\d]+)")
1190a91d5f47SJeremy Spewock    )
1191a91d5f47SJeremy Spewock    #: RSS queue that handled the packet in hex.
1192a91d5f47SJeremy Spewock    rss_queue: int | None = field(
1193a91d5f47SJeremy Spewock        default=None, metadata=TextParser.find_int(r"RSS queue=(0x[a-fA-F\d]+)")
1194a91d5f47SJeremy Spewock    )
1195a91d5f47SJeremy Spewock    #:
1196a91d5f47SJeremy Spewock    l3_len: int | None = field(default=None, metadata=TextParser.find_int(r"l3_len=(\d+)"))
1197a91d5f47SJeremy Spewock    #:
1198a91d5f47SJeremy Spewock    l4_len: int | None = field(default=None, metadata=TextParser.find_int(r"l4_len=(\d+)"))
1199a91d5f47SJeremy Spewock
1200a91d5f47SJeremy Spewock
1201a79884f9SJuraj Linkešclass RxOffloadCapability(Flag):
1202a79884f9SJuraj Linkeš    """Rx offload capabilities of a device.
1203a79884f9SJuraj Linkeš
1204a79884f9SJuraj Linkeš    The flags are taken from ``lib/ethdev/rte_ethdev.h``.
1205a79884f9SJuraj Linkeš    They're prefixed with ``RTE_ETH_RX_OFFLOAD`` in ``lib/ethdev/rte_ethdev.h``
1206a79884f9SJuraj Linkeš    instead of ``RX_OFFLOAD``, which is what testpmd changes the prefix to.
1207a79884f9SJuraj Linkeš    The values are not contiguous, so the correspondence is preserved
1208a79884f9SJuraj Linkeš    by specifying concrete values interspersed between auto() values.
1209a79884f9SJuraj Linkeš
1210a79884f9SJuraj Linkeš    The ``RX_OFFLOAD`` prefix has been preserved so that the same flag names can be used
1211a79884f9SJuraj Linkeš    in :class:`NicCapability`. The prefix is needed in :class:`NicCapability` since there's
1212a79884f9SJuraj Linkeš    no other qualifier which would sufficiently distinguish it from other capabilities.
1213a79884f9SJuraj Linkeš
1214a79884f9SJuraj Linkeš    References:
1215a79884f9SJuraj Linkeš        DPDK lib: ``lib/ethdev/rte_ethdev.h``
1216a79884f9SJuraj Linkeš        testpmd display function: ``app/test-pmd/cmdline.c:print_rx_offloads()``
1217a79884f9SJuraj Linkeš    """
1218a79884f9SJuraj Linkeš
1219a79884f9SJuraj Linkeš    #:
1220a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN_STRIP = auto()
1221a79884f9SJuraj Linkeš    #: Device supports L3 checksum offload.
1222a79884f9SJuraj Linkeš    RX_OFFLOAD_IPV4_CKSUM = auto()
1223a79884f9SJuraj Linkeš    #: Device supports L4 checksum offload.
1224a79884f9SJuraj Linkeš    RX_OFFLOAD_UDP_CKSUM = auto()
1225a79884f9SJuraj Linkeš    #: Device supports L4 checksum offload.
1226a79884f9SJuraj Linkeš    RX_OFFLOAD_TCP_CKSUM = auto()
1227a79884f9SJuraj Linkeš    #: Device supports Large Receive Offload.
1228a79884f9SJuraj Linkeš    RX_OFFLOAD_TCP_LRO = auto()
1229a79884f9SJuraj Linkeš    #: Device supports QinQ (queue in queue) offload.
1230a79884f9SJuraj Linkeš    RX_OFFLOAD_QINQ_STRIP = auto()
1231a79884f9SJuraj Linkeš    #: Device supports inner packet L3 checksum.
1232a79884f9SJuraj Linkeš    RX_OFFLOAD_OUTER_IPV4_CKSUM = auto()
1233a79884f9SJuraj Linkeš    #: Device supports MACsec.
1234a79884f9SJuraj Linkeš    RX_OFFLOAD_MACSEC_STRIP = auto()
1235a79884f9SJuraj Linkeš    #: Device supports filtering of a VLAN Tag identifier.
1236a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN_FILTER = 1 << 9
1237a79884f9SJuraj Linkeš    #: Device supports VLAN offload.
1238a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN_EXTEND = auto()
1239a79884f9SJuraj Linkeš    #: Device supports receiving segmented mbufs.
1240a79884f9SJuraj Linkeš    RX_OFFLOAD_SCATTER = 1 << 13
1241a79884f9SJuraj Linkeš    #: Device supports Timestamp.
1242a79884f9SJuraj Linkeš    RX_OFFLOAD_TIMESTAMP = auto()
1243a79884f9SJuraj Linkeš    #: Device supports crypto processing while packet is received in NIC.
1244a79884f9SJuraj Linkeš    RX_OFFLOAD_SECURITY = auto()
1245a79884f9SJuraj Linkeš    #: Device supports CRC stripping.
1246a79884f9SJuraj Linkeš    RX_OFFLOAD_KEEP_CRC = auto()
1247a79884f9SJuraj Linkeš    #: Device supports L4 checksum offload.
1248a79884f9SJuraj Linkeš    RX_OFFLOAD_SCTP_CKSUM = auto()
1249a79884f9SJuraj Linkeš    #: Device supports inner packet L4 checksum.
1250a79884f9SJuraj Linkeš    RX_OFFLOAD_OUTER_UDP_CKSUM = auto()
1251a79884f9SJuraj Linkeš    #: Device supports RSS hashing.
1252a79884f9SJuraj Linkeš    RX_OFFLOAD_RSS_HASH = auto()
1253a79884f9SJuraj Linkeš    #: Device supports
1254a79884f9SJuraj Linkeš    RX_OFFLOAD_BUFFER_SPLIT = auto()
1255a79884f9SJuraj Linkeš    #: Device supports all checksum capabilities.
1256a79884f9SJuraj Linkeš    RX_OFFLOAD_CHECKSUM = RX_OFFLOAD_IPV4_CKSUM | RX_OFFLOAD_UDP_CKSUM | RX_OFFLOAD_TCP_CKSUM
1257a79884f9SJuraj Linkeš    #: Device supports all VLAN capabilities.
1258a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN = (
1259a79884f9SJuraj Linkeš        RX_OFFLOAD_VLAN_STRIP
1260a79884f9SJuraj Linkeš        | RX_OFFLOAD_VLAN_FILTER
1261a79884f9SJuraj Linkeš        | RX_OFFLOAD_VLAN_EXTEND
1262a79884f9SJuraj Linkeš        | RX_OFFLOAD_QINQ_STRIP
1263a79884f9SJuraj Linkeš    )
1264a79884f9SJuraj Linkeš
1265a79884f9SJuraj Linkeš    @classmethod
1266a79884f9SJuraj Linkeš    def from_string(cls, line: str) -> Self:
1267a79884f9SJuraj Linkeš        """Make an instance from a string containing the flag names separated with a space.
1268a79884f9SJuraj Linkeš
1269a79884f9SJuraj Linkeš        Args:
1270a79884f9SJuraj Linkeš            line: The line to parse.
1271a79884f9SJuraj Linkeš
1272a79884f9SJuraj Linkeš        Returns:
1273a79884f9SJuraj Linkeš            A new instance containing all found flags.
1274a79884f9SJuraj Linkeš        """
1275a79884f9SJuraj Linkeš        flag = cls(0)
1276a79884f9SJuraj Linkeš        for flag_name in line.split():
1277a79884f9SJuraj Linkeš            flag |= cls[f"RX_OFFLOAD_{flag_name}"]
1278a79884f9SJuraj Linkeš        return flag
1279a79884f9SJuraj Linkeš
1280a79884f9SJuraj Linkeš    @classmethod
1281a79884f9SJuraj Linkeš    def make_parser(cls, per_port: bool) -> ParserFn:
1282a79884f9SJuraj Linkeš        """Make a parser function.
1283a79884f9SJuraj Linkeš
1284a79884f9SJuraj Linkeš        Args:
1285a79884f9SJuraj Linkeš            per_port: If :data:`True`, will return capabilities per port. If :data:`False`,
1286a79884f9SJuraj Linkeš                will return capabilities per queue.
1287a79884f9SJuraj Linkeš
1288a79884f9SJuraj Linkeš        Returns:
1289a79884f9SJuraj Linkeš            ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
1290a79884f9SJuraj Linkeš                parser function that makes an instance of this flag from text.
1291a79884f9SJuraj Linkeš        """
1292a79884f9SJuraj Linkeš        granularity = "Port" if per_port else "Queue"
1293a79884f9SJuraj Linkeš        return TextParser.wrap(
1294a79884f9SJuraj Linkeš            TextParser.find(rf"Per {granularity}\s+:(.*)$", re.MULTILINE),
1295a79884f9SJuraj Linkeš            cls.from_string,
1296a79884f9SJuraj Linkeš        )
1297a79884f9SJuraj Linkeš
1298a79884f9SJuraj Linkeš
1299a79884f9SJuraj Linkeš@dataclass
1300a79884f9SJuraj Linkešclass RxOffloadCapabilities(TextParser):
1301a79884f9SJuraj Linkeš    """The result of testpmd's ``show port <port_id> rx_offload capabilities`` command.
1302a79884f9SJuraj Linkeš
1303a79884f9SJuraj Linkeš    References:
1304a79884f9SJuraj Linkeš        testpmd command function: ``app/test-pmd/cmdline.c:cmd_rx_offload_get_capa()``
1305a79884f9SJuraj Linkeš        testpmd display function: ``app/test-pmd/cmdline.c:cmd_rx_offload_get_capa_parsed()``
1306a79884f9SJuraj Linkeš    """
1307a79884f9SJuraj Linkeš
1308a79884f9SJuraj Linkeš    #:
1309a79884f9SJuraj Linkeš    port_id: int = field(
1310a79884f9SJuraj Linkeš        metadata=TextParser.find_int(r"Rx Offloading Capabilities of port (\d+) :")
1311a79884f9SJuraj Linkeš    )
1312a79884f9SJuraj Linkeš    #: Per-queue Rx offload capabilities.
1313a79884f9SJuraj Linkeš    per_queue: RxOffloadCapability = field(metadata=RxOffloadCapability.make_parser(False))
1314a79884f9SJuraj Linkeš    #: Capabilities other than per-queue Rx offload capabilities.
1315a79884f9SJuraj Linkeš    per_port: RxOffloadCapability = field(metadata=RxOffloadCapability.make_parser(True))
1316a79884f9SJuraj Linkeš
1317a79884f9SJuraj Linkeš
13182ecfd126SLuca Vizzarrodef requires_stopped_ports(func: TestPmdShellMethod) -> TestPmdShellMethod:
13192ecfd126SLuca Vizzarro    """Decorator for :class:`TestPmdShell` commands methods that require stopped ports.
13202ecfd126SLuca Vizzarro
13212ecfd126SLuca Vizzarro    If the decorated method is called while the ports are started, then these are stopped before
13222ecfd126SLuca Vizzarro    continuing.
13232ecfd126SLuca Vizzarro
13242ecfd126SLuca Vizzarro    Args:
13252ecfd126SLuca Vizzarro        func: The :class:`TestPmdShell` method to decorate.
13262ecfd126SLuca Vizzarro    """
13272ecfd126SLuca Vizzarro
13282ecfd126SLuca Vizzarro    @functools.wraps(func)
13292ecfd126SLuca Vizzarro    def _wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs):
13302ecfd126SLuca Vizzarro        if self.ports_started:
13312ecfd126SLuca Vizzarro            self._logger.debug("Ports need to be stopped to continue.")
13322ecfd126SLuca Vizzarro            self.stop_all_ports()
13332ecfd126SLuca Vizzarro
13342ecfd126SLuca Vizzarro        return func(self, *args, **kwargs)
13352ecfd126SLuca Vizzarro
13362ecfd126SLuca Vizzarro    return _wrapper
13372ecfd126SLuca Vizzarro
13382ecfd126SLuca Vizzarro
13392ecfd126SLuca Vizzarrodef requires_started_ports(func: TestPmdShellMethod) -> TestPmdShellMethod:
13402ecfd126SLuca Vizzarro    """Decorator for :class:`TestPmdShell` commands methods that require started ports.
13412ecfd126SLuca Vizzarro
13422ecfd126SLuca Vizzarro    If the decorated method is called while the ports are stopped, then these are started before
13432ecfd126SLuca Vizzarro    continuing.
13442ecfd126SLuca Vizzarro
13452ecfd126SLuca Vizzarro    Args:
13462ecfd126SLuca Vizzarro        func: The :class:`TestPmdShell` method to decorate.
13472ecfd126SLuca Vizzarro    """
13482ecfd126SLuca Vizzarro
13492ecfd126SLuca Vizzarro    @functools.wraps(func)
13502ecfd126SLuca Vizzarro    def _wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs):
13512ecfd126SLuca Vizzarro        if not self.ports_started:
13522ecfd126SLuca Vizzarro            self._logger.debug("Ports need to be started to continue.")
13532ecfd126SLuca Vizzarro            self.start_all_ports()
13542ecfd126SLuca Vizzarro
13552ecfd126SLuca Vizzarro        return func(self, *args, **kwargs)
13562ecfd126SLuca Vizzarro
13572ecfd126SLuca Vizzarro    return _wrapper
13582ecfd126SLuca Vizzarro
13592ecfd126SLuca Vizzarro
1360c0119400SJuraj Linkešdef add_remove_mtu(mtu: int = 1500) -> Callable[[TestPmdShellMethod], TestPmdShellMethod]:
1361c0119400SJuraj Linkeš    """Configure MTU to `mtu` on all ports, run the decorated function, then revert.
1362c0119400SJuraj Linkeš
1363c0119400SJuraj Linkeš    Args:
1364c0119400SJuraj Linkeš        mtu: The MTU to configure all ports on.
1365c0119400SJuraj Linkeš
1366c0119400SJuraj Linkeš    Returns:
1367c0119400SJuraj Linkeš        The method decorated with setting and reverting MTU.
1368c0119400SJuraj Linkeš    """
1369c0119400SJuraj Linkeš
1370c0119400SJuraj Linkeš    def decorator(func: TestPmdShellMethod) -> TestPmdShellMethod:
1371c0119400SJuraj Linkeš        @functools.wraps(func)
1372c0119400SJuraj Linkeš        def wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs):
1373c0119400SJuraj Linkeš            original_mtu = self.ports[0].mtu
1374c0119400SJuraj Linkeš            self.set_port_mtu_all(mtu=mtu, verify=False)
1375c0119400SJuraj Linkeš            retval = func(self, *args, **kwargs)
1376c0119400SJuraj Linkeš            self.set_port_mtu_all(original_mtu if original_mtu else 1500, verify=False)
1377c0119400SJuraj Linkeš            return retval
1378c0119400SJuraj Linkeš
1379c0119400SJuraj Linkeš        return wrapper
1380c0119400SJuraj Linkeš
1381c0119400SJuraj Linkeš    return decorator
1382c0119400SJuraj Linkeš
1383c0119400SJuraj Linkeš
1384bfad0948SLuca Vizzarroclass TestPmdShell(DPDKShell):
13856ef07151SJuraj Linkeš    """Testpmd interactive shell.
13866ef07151SJuraj Linkeš
13876ef07151SJuraj Linkeš    The testpmd shell users should never use
13886ef07151SJuraj Linkeš    the :meth:`~.interactive_shell.InteractiveShell.send_command` method directly, but rather
13896ef07151SJuraj Linkeš    call specialized methods. If there isn't one that satisfies a need, it should be added.
13902ecfd126SLuca Vizzarro
13912ecfd126SLuca Vizzarro    Attributes:
13922ecfd126SLuca Vizzarro        ports_started: Indicates whether the ports are started.
13936ef07151SJuraj Linkeš    """
13946ef07151SJuraj Linkeš
1395bfad0948SLuca Vizzarro    _app_params: TestPmdParams
139685d15c7cSJuraj Linkeš    _ports: list[TestPmdPort] | None
1397369d34b8SJeremy Spewock
13986ef07151SJuraj Linkeš    #: The path to the testpmd executable.
13996ef07151SJuraj Linkeš    path: ClassVar[PurePath] = PurePath("app", "dpdk-testpmd")
14006ef07151SJuraj Linkeš
14016ef07151SJuraj Linkeš    #: The testpmd's prompt.
14026ef07151SJuraj Linkeš    _default_prompt: ClassVar[str] = "testpmd>"
14036ef07151SJuraj Linkeš
14046ef07151SJuraj Linkeš    #: This forces the prompt to appear after sending a command.
14056ef07151SJuraj Linkeš    _command_extra_chars: ClassVar[str] = "\n"
1406840b1e01SJuraj Linkeš
14072ecfd126SLuca Vizzarro    ports_started: bool
14082ecfd126SLuca Vizzarro
1409bfad0948SLuca Vizzarro    def __init__(
1410bfad0948SLuca Vizzarro        self,
1411bfad0948SLuca Vizzarro        node: SutNode,
1412bfad0948SLuca Vizzarro        privileged: bool = True,
1413bfad0948SLuca Vizzarro        timeout: float = SETTINGS.timeout,
1414bfad0948SLuca Vizzarro        lcore_filter_specifier: LogicalCoreCount | LogicalCoreList = LogicalCoreCount(),
1415bfad0948SLuca Vizzarro        ascending_cores: bool = True,
1416bfad0948SLuca Vizzarro        append_prefix_timestamp: bool = True,
141765a1b4e8SJeremy Spewock        name: str | None = None,
141887ba4cdcSLuca Vizzarro        **app_params: Unpack[TestPmdParamsDict],
1419bfad0948SLuca Vizzarro    ) -> None:
1420bfad0948SLuca Vizzarro        """Overrides :meth:`~.dpdk_shell.DPDKShell.__init__`. Changes app_params to kwargs."""
1421bfad0948SLuca Vizzarro        super().__init__(
1422bfad0948SLuca Vizzarro            node,
1423bfad0948SLuca Vizzarro            privileged,
1424bfad0948SLuca Vizzarro            timeout,
1425bfad0948SLuca Vizzarro            lcore_filter_specifier,
1426bfad0948SLuca Vizzarro            ascending_cores,
1427bfad0948SLuca Vizzarro            append_prefix_timestamp,
1428bfad0948SLuca Vizzarro            TestPmdParams(**app_params),
142965a1b4e8SJeremy Spewock            name,
1430fd8cd8eeSLuca Vizzarro        )
14312ecfd126SLuca Vizzarro        self.ports_started = not self._app_params.disable_device_start
143285d15c7cSJuraj Linkeš        self._ports = None
143385d15c7cSJuraj Linkeš
143485d15c7cSJuraj Linkeš    @property
143585d15c7cSJuraj Linkeš    def ports(self) -> list[TestPmdPort]:
143685d15c7cSJuraj Linkeš        """The ports of the instance.
143785d15c7cSJuraj Linkeš
143885d15c7cSJuraj Linkeš        This caches the ports returned by :meth:`show_port_info_all`.
143985d15c7cSJuraj Linkeš        To force an update of port information, execute :meth:`show_port_info_all` or
144085d15c7cSJuraj Linkeš        :meth:`show_port_info`.
144185d15c7cSJuraj Linkeš
144285d15c7cSJuraj Linkeš        Returns: The list of known testpmd ports.
144385d15c7cSJuraj Linkeš        """
144485d15c7cSJuraj Linkeš        if self._ports is None:
144585d15c7cSJuraj Linkeš            return self.show_port_info_all()
144685d15c7cSJuraj Linkeš        return self._ports
14472ecfd126SLuca Vizzarro
14482ecfd126SLuca Vizzarro    @requires_started_ports
1449369d34b8SJeremy Spewock    def start(self, verify: bool = True) -> None:
1450369d34b8SJeremy Spewock        """Start packet forwarding with the current configuration.
1451369d34b8SJeremy Spewock
1452369d34b8SJeremy Spewock        Args:
1453369d34b8SJeremy Spewock            verify: If :data:`True` , a second start command will be sent in an attempt to verify
1454369d34b8SJeremy Spewock                packet forwarding started as expected.
1455369d34b8SJeremy Spewock
1456369d34b8SJeremy Spewock        Raises:
1457369d34b8SJeremy Spewock            InteractiveCommandExecutionError: If `verify` is :data:`True` and forwarding fails to
1458369d34b8SJeremy Spewock                start or ports fail to come up.
1459369d34b8SJeremy Spewock        """
1460369d34b8SJeremy Spewock        self.send_command("start")
1461369d34b8SJeremy Spewock        if verify:
1462369d34b8SJeremy Spewock            # If forwarding was already started, sending "start" again should tell us
1463369d34b8SJeremy Spewock            start_cmd_output = self.send_command("start")
1464369d34b8SJeremy Spewock            if "Packet forwarding already started" not in start_cmd_output:
1465369d34b8SJeremy Spewock                self._logger.debug(f"Failed to start packet forwarding: \n{start_cmd_output}")
1466369d34b8SJeremy Spewock                raise InteractiveCommandExecutionError("Testpmd failed to start packet forwarding.")
1467369d34b8SJeremy Spewock
1468bfad0948SLuca Vizzarro            number_of_ports = len(self._app_params.ports or [])
1469bfad0948SLuca Vizzarro            for port_id in range(number_of_ports):
1470369d34b8SJeremy Spewock                if not self.wait_link_status_up(port_id):
1471369d34b8SJeremy Spewock                    raise InteractiveCommandExecutionError(
1472369d34b8SJeremy Spewock                        "Not all ports came up after starting packet forwarding in testpmd."
1473369d34b8SJeremy Spewock                    )
1474369d34b8SJeremy Spewock
1475a91d5f47SJeremy Spewock    def stop(self, verify: bool = True) -> str:
1476369d34b8SJeremy Spewock        """Stop packet forwarding.
1477369d34b8SJeremy Spewock
1478369d34b8SJeremy Spewock        Args:
1479369d34b8SJeremy Spewock            verify: If :data:`True` , the output of the stop command is scanned to verify that
1480369d34b8SJeremy Spewock                forwarding was stopped successfully or not started. If neither is found, it is
1481369d34b8SJeremy Spewock                considered an error.
1482369d34b8SJeremy Spewock
1483369d34b8SJeremy Spewock        Raises:
1484369d34b8SJeremy Spewock            InteractiveCommandExecutionError: If `verify` is :data:`True` and the command to stop
1485369d34b8SJeremy Spewock                forwarding results in an error.
1486a91d5f47SJeremy Spewock
1487a91d5f47SJeremy Spewock        Returns:
1488a91d5f47SJeremy Spewock            Output gathered from the stop command and all other preceding logs in the buffer. This
1489a91d5f47SJeremy Spewock            output is most often used to view forwarding statistics that are displayed when this
1490a91d5f47SJeremy Spewock            command is sent as well as any verbose packet information that hasn't been consumed
1491a91d5f47SJeremy Spewock            prior to calling this method.
1492369d34b8SJeremy Spewock        """
1493369d34b8SJeremy Spewock        stop_cmd_output = self.send_command("stop")
1494369d34b8SJeremy Spewock        if verify:
1495369d34b8SJeremy Spewock            if (
1496369d34b8SJeremy Spewock                "Done." not in stop_cmd_output
1497369d34b8SJeremy Spewock                and "Packet forwarding not started" not in stop_cmd_output
1498369d34b8SJeremy Spewock            ):
1499369d34b8SJeremy Spewock                self._logger.debug(f"Failed to stop packet forwarding: \n{stop_cmd_output}")
1500369d34b8SJeremy Spewock                raise InteractiveCommandExecutionError("Testpmd failed to stop packet forwarding.")
1501a91d5f47SJeremy Spewock        return stop_cmd_output
1502369d34b8SJeremy Spewock
1503840b1e01SJuraj Linkeš    def get_devices(self) -> list[TestPmdDevice]:
15046ef07151SJuraj Linkeš        """Get a list of device names that are known to testpmd.
1505840b1e01SJuraj Linkeš
15066ef07151SJuraj Linkeš        Uses the device info listed in testpmd and then parses the output.
1507840b1e01SJuraj Linkeš
1508840b1e01SJuraj Linkeš        Returns:
15096ef07151SJuraj Linkeš            A list of devices.
1510840b1e01SJuraj Linkeš        """
1511840b1e01SJuraj Linkeš        dev_info: str = self.send_command("show device info all")
1512840b1e01SJuraj Linkeš        dev_list: list[TestPmdDevice] = []
1513840b1e01SJuraj Linkeš        for line in dev_info.split("\n"):
1514840b1e01SJuraj Linkeš            if "device name:" in line.lower():
1515840b1e01SJuraj Linkeš                dev_list.append(TestPmdDevice(line))
1516840b1e01SJuraj Linkeš        return dev_list
1517369d34b8SJeremy Spewock
1518369d34b8SJeremy Spewock    def wait_link_status_up(self, port_id: int, timeout=SETTINGS.timeout) -> bool:
1519369d34b8SJeremy Spewock        """Wait until the link status on the given port is "up".
1520369d34b8SJeremy Spewock
1521369d34b8SJeremy Spewock        Arguments:
1522369d34b8SJeremy Spewock            port_id: Port to check the link status on.
1523369d34b8SJeremy Spewock            timeout: Time to wait for the link to come up. The default value for this
1524369d34b8SJeremy Spewock                argument may be modified using the :option:`--timeout` command-line argument
1525369d34b8SJeremy Spewock                or the :envvar:`DTS_TIMEOUT` environment variable.
1526369d34b8SJeremy Spewock
1527369d34b8SJeremy Spewock        Returns:
1528369d34b8SJeremy Spewock            Whether the link came up in time or not.
1529369d34b8SJeremy Spewock        """
1530369d34b8SJeremy Spewock        time_to_stop = time.time() + timeout
1531369d34b8SJeremy Spewock        port_info: str = ""
1532369d34b8SJeremy Spewock        while time.time() < time_to_stop:
1533369d34b8SJeremy Spewock            port_info = self.send_command(f"show port info {port_id}")
1534369d34b8SJeremy Spewock            if "Link status: up" in port_info:
1535369d34b8SJeremy Spewock                break
1536369d34b8SJeremy Spewock            time.sleep(0.5)
1537369d34b8SJeremy Spewock        else:
1538369d34b8SJeremy Spewock            self._logger.error(f"The link for port {port_id} did not come up in the given timeout.")
1539369d34b8SJeremy Spewock        return "Link status: up" in port_info
1540369d34b8SJeremy Spewock
1541fc0f7dc4SLuca Vizzarro    def set_forward_mode(self, mode: SimpleForwardingModes, verify: bool = True):
1542369d34b8SJeremy Spewock        """Set packet forwarding mode.
1543369d34b8SJeremy Spewock
1544369d34b8SJeremy Spewock        Args:
1545369d34b8SJeremy Spewock            mode: The forwarding mode to use.
1546369d34b8SJeremy Spewock            verify: If :data:`True` the output of the command will be scanned in an attempt to
1547369d34b8SJeremy Spewock                verify that the forwarding mode was set to `mode` properly.
1548369d34b8SJeremy Spewock
1549369d34b8SJeremy Spewock        Raises:
1550369d34b8SJeremy Spewock            InteractiveCommandExecutionError: If `verify` is :data:`True` and the forwarding mode
1551369d34b8SJeremy Spewock                fails to update.
1552369d34b8SJeremy Spewock        """
1553369d34b8SJeremy Spewock        set_fwd_output = self.send_command(f"set fwd {mode.value}")
1554369d34b8SJeremy Spewock        if f"Set {mode.value} packet forwarding mode" not in set_fwd_output:
1555369d34b8SJeremy Spewock            self._logger.debug(f"Failed to set fwd mode to {mode.value}:\n{set_fwd_output}")
1556369d34b8SJeremy Spewock            raise InteractiveCommandExecutionError(
1557369d34b8SJeremy Spewock                f"Test pmd failed to set fwd mode to {mode.value}"
1558369d34b8SJeremy Spewock            )
1559369d34b8SJeremy Spewock
15602ecfd126SLuca Vizzarro    def stop_all_ports(self, verify: bool = True) -> None:
15612ecfd126SLuca Vizzarro        """Stops all the ports.
15622ecfd126SLuca Vizzarro
15632ecfd126SLuca Vizzarro        Args:
15642ecfd126SLuca Vizzarro            verify: If :data:`True`, the output of the command will be checked for a successful
15652ecfd126SLuca Vizzarro                execution.
15662ecfd126SLuca Vizzarro
15672ecfd126SLuca Vizzarro        Raises:
15682ecfd126SLuca Vizzarro            InteractiveCommandExecutionError: If `verify` is :data:`True` and the ports were not
15692ecfd126SLuca Vizzarro                stopped successfully.
15702ecfd126SLuca Vizzarro        """
15712ecfd126SLuca Vizzarro        self._logger.debug("Stopping all the ports...")
15722ecfd126SLuca Vizzarro        output = self.send_command("port stop all")
15732ecfd126SLuca Vizzarro        if verify and not output.strip().endswith("Done"):
15742ecfd126SLuca Vizzarro            raise InteractiveCommandExecutionError("Ports were not stopped successfully.")
15752ecfd126SLuca Vizzarro
15762ecfd126SLuca Vizzarro        self.ports_started = False
15772ecfd126SLuca Vizzarro
15782ecfd126SLuca Vizzarro    def start_all_ports(self, verify: bool = True) -> None:
15792ecfd126SLuca Vizzarro        """Starts all the ports.
15802ecfd126SLuca Vizzarro
15812ecfd126SLuca Vizzarro        Args:
15822ecfd126SLuca Vizzarro            verify: If :data:`True`, the output of the command will be checked for a successful
15832ecfd126SLuca Vizzarro                execution.
15842ecfd126SLuca Vizzarro
15852ecfd126SLuca Vizzarro        Raises:
15862ecfd126SLuca Vizzarro            InteractiveCommandExecutionError: If `verify` is :data:`True` and the ports were not
15872ecfd126SLuca Vizzarro                started successfully.
15882ecfd126SLuca Vizzarro        """
15892ecfd126SLuca Vizzarro        self._logger.debug("Starting all the ports...")
15902ecfd126SLuca Vizzarro        output = self.send_command("port start all")
15912ecfd126SLuca Vizzarro        if verify and not output.strip().endswith("Done"):
15922ecfd126SLuca Vizzarro            raise InteractiveCommandExecutionError("Ports were not started successfully.")
15932ecfd126SLuca Vizzarro
15942ecfd126SLuca Vizzarro        self.ports_started = True
15952ecfd126SLuca Vizzarro
159607816eadSLuca Vizzarro    @requires_stopped_ports
159707816eadSLuca Vizzarro    def set_ports_queues(self, number_of: int) -> None:
159807816eadSLuca Vizzarro        """Sets the number of queues per port.
159907816eadSLuca Vizzarro
160007816eadSLuca Vizzarro        Args:
160107816eadSLuca Vizzarro            number_of: The number of RX/TX queues to create per port.
160207816eadSLuca Vizzarro
160307816eadSLuca Vizzarro        Raises:
160407816eadSLuca Vizzarro            InternalError: If `number_of` is invalid.
160507816eadSLuca Vizzarro        """
160607816eadSLuca Vizzarro        if number_of < 1:
160707816eadSLuca Vizzarro            raise InternalError("The number of queues must be positive and non-zero.")
160807816eadSLuca Vizzarro
160907816eadSLuca Vizzarro        self.send_command(f"port config all rxq {number_of}")
161007816eadSLuca Vizzarro        self.send_command(f"port config all txq {number_of}")
161107816eadSLuca Vizzarro
161261d5bc9bSLuca Vizzarro    def show_port_info_all(self) -> list[TestPmdPort]:
161361d5bc9bSLuca Vizzarro        """Returns the information of all the ports.
161461d5bc9bSLuca Vizzarro
161561d5bc9bSLuca Vizzarro        Returns:
161661d5bc9bSLuca Vizzarro            list[TestPmdPort]: A list containing all the ports information as `TestPmdPort`.
161761d5bc9bSLuca Vizzarro        """
161861d5bc9bSLuca Vizzarro        output = self.send_command("show port info all")
161961d5bc9bSLuca Vizzarro
162061d5bc9bSLuca Vizzarro        # Sample output of the "all" command looks like:
162161d5bc9bSLuca Vizzarro        #
162261d5bc9bSLuca Vizzarro        # <start>
162361d5bc9bSLuca Vizzarro        #
162461d5bc9bSLuca Vizzarro        #   ********************* Infos for port 0 *********************
162561d5bc9bSLuca Vizzarro        #   Key: value
162661d5bc9bSLuca Vizzarro        #
162761d5bc9bSLuca Vizzarro        #   ********************* Infos for port 1 *********************
162861d5bc9bSLuca Vizzarro        #   Key: value
162961d5bc9bSLuca Vizzarro        # <end>
163061d5bc9bSLuca Vizzarro        #
163161d5bc9bSLuca Vizzarro        # Takes advantage of the double new line in between ports as end delimiter. But we need to
163261d5bc9bSLuca Vizzarro        # artificially add a new line at the end to pick up the last port. Because commands are
163361d5bc9bSLuca Vizzarro        # executed on a pseudo-terminal created by paramiko on the remote node, lines end with CRLF.
163461d5bc9bSLuca Vizzarro        # Therefore we also need to take the carriage return into account.
163561d5bc9bSLuca Vizzarro        iter = re.finditer(r"\*{21}.*?[\r\n]{4}", output + "\r\n", re.S)
163685d15c7cSJuraj Linkeš        self._ports = [TestPmdPort.parse(block.group(0)) for block in iter]
163785d15c7cSJuraj Linkeš        return self._ports
163861d5bc9bSLuca Vizzarro
163961d5bc9bSLuca Vizzarro    def show_port_info(self, port_id: int) -> TestPmdPort:
164061d5bc9bSLuca Vizzarro        """Returns the given port information.
164161d5bc9bSLuca Vizzarro
164261d5bc9bSLuca Vizzarro        Args:
164361d5bc9bSLuca Vizzarro            port_id: The port ID to gather information for.
164461d5bc9bSLuca Vizzarro
164561d5bc9bSLuca Vizzarro        Raises:
164661d5bc9bSLuca Vizzarro            InteractiveCommandExecutionError: If `port_id` is invalid.
164761d5bc9bSLuca Vizzarro
164861d5bc9bSLuca Vizzarro        Returns:
164961d5bc9bSLuca Vizzarro            TestPmdPort: An instance of `TestPmdPort` containing the given port's information.
165061d5bc9bSLuca Vizzarro        """
165161d5bc9bSLuca Vizzarro        output = self.send_command(f"show port info {port_id}", skip_first_line=True)
165261d5bc9bSLuca Vizzarro        if output.startswith("Invalid port"):
165361d5bc9bSLuca Vizzarro            raise InteractiveCommandExecutionError("invalid port given")
165461d5bc9bSLuca Vizzarro
165585d15c7cSJuraj Linkeš        port = TestPmdPort.parse(output)
165685d15c7cSJuraj Linkeš        self._update_port(port)
165785d15c7cSJuraj Linkeš        return port
165885d15c7cSJuraj Linkeš
165985d15c7cSJuraj Linkeš    def _update_port(self, port: TestPmdPort) -> None:
166085d15c7cSJuraj Linkeš        if self._ports:
166185d15c7cSJuraj Linkeš            self._ports = [
166285d15c7cSJuraj Linkeš                existing_port if port.id != existing_port.id else port
166385d15c7cSJuraj Linkeš                for existing_port in self._ports
166485d15c7cSJuraj Linkeš            ]
166561d5bc9bSLuca Vizzarro
166653eacf3dSLuca Vizzarro    def show_port_stats_all(self) -> list[TestPmdPortStats]:
166753eacf3dSLuca Vizzarro        """Returns the statistics of all the ports.
166853eacf3dSLuca Vizzarro
166953eacf3dSLuca Vizzarro        Returns:
167053eacf3dSLuca Vizzarro            list[TestPmdPortStats]: A list containing all the ports stats as `TestPmdPortStats`.
167153eacf3dSLuca Vizzarro        """
167253eacf3dSLuca Vizzarro        output = self.send_command("show port stats all")
167353eacf3dSLuca Vizzarro
167453eacf3dSLuca Vizzarro        # Sample output of the "all" command looks like:
167553eacf3dSLuca Vizzarro        #
167653eacf3dSLuca Vizzarro        #   ########### NIC statistics for port 0 ###########
167753eacf3dSLuca Vizzarro        #   values...
167853eacf3dSLuca Vizzarro        #   #################################################
167953eacf3dSLuca Vizzarro        #
168053eacf3dSLuca Vizzarro        #   ########### NIC statistics for port 1 ###########
168153eacf3dSLuca Vizzarro        #   values...
168253eacf3dSLuca Vizzarro        #   #################################################
168353eacf3dSLuca Vizzarro        #
168453eacf3dSLuca Vizzarro        iter = re.finditer(r"(^  #*.+#*$[^#]+)^  #*\r$", output, re.MULTILINE)
168553eacf3dSLuca Vizzarro        return [TestPmdPortStats.parse(block.group(1)) for block in iter]
168653eacf3dSLuca Vizzarro
168753eacf3dSLuca Vizzarro    def show_port_stats(self, port_id: int) -> TestPmdPortStats:
168853eacf3dSLuca Vizzarro        """Returns the given port statistics.
168953eacf3dSLuca Vizzarro
169053eacf3dSLuca Vizzarro        Args:
169153eacf3dSLuca Vizzarro            port_id: The port ID to gather information for.
169253eacf3dSLuca Vizzarro
169353eacf3dSLuca Vizzarro        Raises:
169453eacf3dSLuca Vizzarro            InteractiveCommandExecutionError: If `port_id` is invalid.
169553eacf3dSLuca Vizzarro
169653eacf3dSLuca Vizzarro        Returns:
169753eacf3dSLuca Vizzarro            TestPmdPortStats: An instance of `TestPmdPortStats` containing the given port's stats.
169853eacf3dSLuca Vizzarro        """
169953eacf3dSLuca Vizzarro        output = self.send_command(f"show port stats {port_id}", skip_first_line=True)
170053eacf3dSLuca Vizzarro        if output.startswith("Invalid port"):
170153eacf3dSLuca Vizzarro            raise InteractiveCommandExecutionError("invalid port given")
170253eacf3dSLuca Vizzarro
170353eacf3dSLuca Vizzarro        return TestPmdPortStats.parse(output)
170453eacf3dSLuca Vizzarro
17059910db35SJeremy Spewock    @requires_stopped_ports
17069910db35SJeremy Spewock    def set_port_mtu(self, port_id: int, mtu: int, verify: bool = True) -> None:
17079910db35SJeremy Spewock        """Change the MTU of a port using testpmd.
17089910db35SJeremy Spewock
17099910db35SJeremy Spewock        Some PMDs require that the port be stopped before changing the MTU, and it does no harm to
17109910db35SJeremy Spewock        stop the port before configuring in cases where it isn't required, so ports are stopped
17119910db35SJeremy Spewock        prior to changing their MTU.
17129910db35SJeremy Spewock
17139910db35SJeremy Spewock        Args:
17149910db35SJeremy Spewock            port_id: ID of the port to adjust the MTU on.
17159910db35SJeremy Spewock            mtu: Desired value for the MTU to be set to.
17169910db35SJeremy Spewock            verify: If `verify` is :data:`True` then the output will be scanned in an attempt to
17179910db35SJeremy Spewock                verify that the mtu was properly set on the port. Defaults to :data:`True`.
17189910db35SJeremy Spewock
17199910db35SJeremy Spewock        Raises:
17209910db35SJeremy Spewock            InteractiveCommandExecutionError: If `verify` is :data:`True` and the MTU was not
17219910db35SJeremy Spewock                properly updated on the port matching `port_id`.
17229910db35SJeremy Spewock        """
17239910db35SJeremy Spewock        set_mtu_output = self.send_command(f"port config mtu {port_id} {mtu}")
17249910db35SJeremy Spewock        if verify and (f"MTU: {mtu}" not in self.send_command(f"show port info {port_id}")):
17259910db35SJeremy Spewock            self._logger.debug(
17269910db35SJeremy Spewock                f"Failed to set mtu to {mtu} on port {port_id}." f" Output was:\n{set_mtu_output}"
17279910db35SJeremy Spewock            )
17289910db35SJeremy Spewock            raise InteractiveCommandExecutionError(
17299910db35SJeremy Spewock                f"Test pmd failed to update mtu of port {port_id} to {mtu}"
17309910db35SJeremy Spewock            )
17319910db35SJeremy Spewock
17329910db35SJeremy Spewock    def set_port_mtu_all(self, mtu: int, verify: bool = True) -> None:
17339910db35SJeremy Spewock        """Change the MTU of all ports using testpmd.
17349910db35SJeremy Spewock
17359910db35SJeremy Spewock        Runs :meth:`set_port_mtu` for every port that testpmd is aware of.
17369910db35SJeremy Spewock
17379910db35SJeremy Spewock        Args:
17389910db35SJeremy Spewock            mtu: Desired value for the MTU to be set to.
17399910db35SJeremy Spewock            verify: Whether to verify that setting the MTU on each port was successful or not.
17409910db35SJeremy Spewock                Defaults to :data:`True`.
17419910db35SJeremy Spewock
17429910db35SJeremy Spewock        Raises:
17439910db35SJeremy Spewock            InteractiveCommandExecutionError: If `verify` is :data:`True` and the MTU was not
17449910db35SJeremy Spewock                properly updated on at least one port.
17459910db35SJeremy Spewock        """
17469910db35SJeremy Spewock        for port in self.ports:
17479910db35SJeremy Spewock            self.set_port_mtu(port.id, mtu, verify)
17489910db35SJeremy Spewock
1749a91d5f47SJeremy Spewock    @staticmethod
1750a91d5f47SJeremy Spewock    def extract_verbose_output(output: str) -> list[TestPmdVerbosePacket]:
1751a91d5f47SJeremy Spewock        """Extract the verbose information present in given testpmd output.
1752a91d5f47SJeremy Spewock
1753a91d5f47SJeremy Spewock        This method extracts sections of verbose output that begin with the line
1754a91d5f47SJeremy Spewock        "port X/queue Y: sent/received Z packets" and end with the ol_flags of a packet.
1755a91d5f47SJeremy Spewock
1756a91d5f47SJeremy Spewock        Args:
1757a91d5f47SJeremy Spewock            output: Testpmd output that contains verbose information
1758a91d5f47SJeremy Spewock
1759a91d5f47SJeremy Spewock        Returns:
1760a91d5f47SJeremy Spewock            List of parsed packet information gathered from verbose information in `output`.
1761a91d5f47SJeremy Spewock        """
1762a91d5f47SJeremy Spewock        out: list[TestPmdVerbosePacket] = []
1763a91d5f47SJeremy Spewock        prev_header: str = ""
1764a91d5f47SJeremy Spewock        iter = re.finditer(
1765a91d5f47SJeremy Spewock            r"(?P<HEADER>(?:port \d+/queue \d+: (?:received|sent) \d+ packets)?)\s*"
1766a91d5f47SJeremy Spewock            r"(?P<PACKET>src=[\w\s=:-]+?ol_flags: [\w ]+)",
1767a91d5f47SJeremy Spewock            output,
1768a91d5f47SJeremy Spewock        )
1769a91d5f47SJeremy Spewock        for match in iter:
1770a91d5f47SJeremy Spewock            if match.group("HEADER"):
1771a91d5f47SJeremy Spewock                prev_header = match.group("HEADER")
1772a91d5f47SJeremy Spewock            out.append(TestPmdVerbosePacket.parse(f"{prev_header}\n{match.group('PACKET')}"))
1773a91d5f47SJeremy Spewock        return out
1774a91d5f47SJeremy Spewock
17752b648cd4SJeremy Spewock    def _close(self) -> None:
1776369d34b8SJeremy Spewock        """Overrides :meth:`~.interactive_shell.close`."""
17772b648cd4SJeremy Spewock        self.stop()
177892439dc9SJeremy Spewock        self.send_command("quit", "Bye...")
17792b648cd4SJeremy Spewock        return super()._close()
1780c89d0038SJuraj Linkeš
1781c0119400SJuraj Linkeš    """
1782c0119400SJuraj Linkeš    ====== Capability retrieval methods ======
1783c0119400SJuraj Linkeš    """
1784c0119400SJuraj Linkeš
1785a79884f9SJuraj Linkeš    def get_capabilities_rx_offload(
1786a79884f9SJuraj Linkeš        self,
1787a79884f9SJuraj Linkeš        supported_capabilities: MutableSet["NicCapability"],
1788a79884f9SJuraj Linkeš        unsupported_capabilities: MutableSet["NicCapability"],
1789a79884f9SJuraj Linkeš    ) -> None:
1790a79884f9SJuraj Linkeš        """Get all rx offload capabilities and divide them into supported and unsupported.
1791a79884f9SJuraj Linkeš
1792a79884f9SJuraj Linkeš        Args:
1793a79884f9SJuraj Linkeš            supported_capabilities: Supported capabilities will be added to this set.
1794a79884f9SJuraj Linkeš            unsupported_capabilities: Unsupported capabilities will be added to this set.
1795a79884f9SJuraj Linkeš        """
1796a79884f9SJuraj Linkeš        self._logger.debug("Getting rx offload capabilities.")
1797a79884f9SJuraj Linkeš        command = f"show port {self.ports[0].id} rx_offload capabilities"
1798a79884f9SJuraj Linkeš        rx_offload_capabilities_out = self.send_command(command)
1799a79884f9SJuraj Linkeš        rx_offload_capabilities = RxOffloadCapabilities.parse(rx_offload_capabilities_out)
1800a79884f9SJuraj Linkeš        self._update_capabilities_from_flag(
1801a79884f9SJuraj Linkeš            supported_capabilities,
1802a79884f9SJuraj Linkeš            unsupported_capabilities,
1803a79884f9SJuraj Linkeš            RxOffloadCapability,
1804a79884f9SJuraj Linkeš            rx_offload_capabilities.per_port | rx_offload_capabilities.per_queue,
1805a79884f9SJuraj Linkeš        )
1806a79884f9SJuraj Linkeš
1807a79884f9SJuraj Linkeš    def _update_capabilities_from_flag(
1808a79884f9SJuraj Linkeš        self,
1809a79884f9SJuraj Linkeš        supported_capabilities: MutableSet["NicCapability"],
1810a79884f9SJuraj Linkeš        unsupported_capabilities: MutableSet["NicCapability"],
1811a79884f9SJuraj Linkeš        flag_class: type[Flag],
1812a79884f9SJuraj Linkeš        supported_flags: Flag,
1813a79884f9SJuraj Linkeš    ) -> None:
1814a79884f9SJuraj Linkeš        """Divide all flags from `flag_class` into supported and unsupported."""
1815a79884f9SJuraj Linkeš        for flag in flag_class:
1816a79884f9SJuraj Linkeš            if flag in supported_flags:
1817a79884f9SJuraj Linkeš                supported_capabilities.add(NicCapability[str(flag.name)])
1818a79884f9SJuraj Linkeš            else:
1819a79884f9SJuraj Linkeš                unsupported_capabilities.add(NicCapability[str(flag.name)])
1820a79884f9SJuraj Linkeš
1821c0119400SJuraj Linkeš    @requires_started_ports
1822c0119400SJuraj Linkeš    def get_capabilities_rxq_info(
1823c0119400SJuraj Linkeš        self,
1824c0119400SJuraj Linkeš        supported_capabilities: MutableSet["NicCapability"],
1825c0119400SJuraj Linkeš        unsupported_capabilities: MutableSet["NicCapability"],
1826c0119400SJuraj Linkeš    ) -> None:
1827c0119400SJuraj Linkeš        """Get all rxq capabilities and divide them into supported and unsupported.
1828c0119400SJuraj Linkeš
1829c0119400SJuraj Linkeš        Args:
1830c0119400SJuraj Linkeš            supported_capabilities: Supported capabilities will be added to this set.
1831c0119400SJuraj Linkeš            unsupported_capabilities: Unsupported capabilities will be added to this set.
1832c0119400SJuraj Linkeš        """
1833c0119400SJuraj Linkeš        self._logger.debug("Getting rxq capabilities.")
1834c0119400SJuraj Linkeš        command = f"show rxq info {self.ports[0].id} 0"
1835c0119400SJuraj Linkeš        rxq_info = TestPmdRxqInfo.parse(self.send_command(command))
1836c0119400SJuraj Linkeš        if rxq_info.rx_scattered_packets:
1837c0119400SJuraj Linkeš            supported_capabilities.add(NicCapability.SCATTERED_RX_ENABLED)
1838c0119400SJuraj Linkeš        else:
1839c0119400SJuraj Linkeš            unsupported_capabilities.add(NicCapability.SCATTERED_RX_ENABLED)
1840c0119400SJuraj Linkeš
1841*d64f6ba5SJuraj Linkeš    def get_capabilities_show_port_info(
1842*d64f6ba5SJuraj Linkeš        self,
1843*d64f6ba5SJuraj Linkeš        supported_capabilities: MutableSet["NicCapability"],
1844*d64f6ba5SJuraj Linkeš        unsupported_capabilities: MutableSet["NicCapability"],
1845*d64f6ba5SJuraj Linkeš    ) -> None:
1846*d64f6ba5SJuraj Linkeš        """Get all capabilities from show port info and divide them into supported and unsupported.
1847*d64f6ba5SJuraj Linkeš
1848*d64f6ba5SJuraj Linkeš        Args:
1849*d64f6ba5SJuraj Linkeš            supported_capabilities: Supported capabilities will be added to this set.
1850*d64f6ba5SJuraj Linkeš            unsupported_capabilities: Unsupported capabilities will be added to this set.
1851*d64f6ba5SJuraj Linkeš        """
1852*d64f6ba5SJuraj Linkeš        self._update_capabilities_from_flag(
1853*d64f6ba5SJuraj Linkeš            supported_capabilities,
1854*d64f6ba5SJuraj Linkeš            unsupported_capabilities,
1855*d64f6ba5SJuraj Linkeš            DeviceCapabilitiesFlag,
1856*d64f6ba5SJuraj Linkeš            self.ports[0].device_capabilities,
1857*d64f6ba5SJuraj Linkeš        )
1858*d64f6ba5SJuraj Linkeš
1859c89d0038SJuraj Linkeš
1860c89d0038SJuraj Linkešclass NicCapability(NoAliasEnum):
1861c89d0038SJuraj Linkeš    """A mapping between capability names and the associated :class:`TestPmdShell` methods.
1862c89d0038SJuraj Linkeš
1863c89d0038SJuraj Linkeš    The :class:`TestPmdShell` capability checking method executes the command that checks
1864c89d0038SJuraj Linkeš    whether the capability is supported.
1865c89d0038SJuraj Linkeš    A decorator may optionally be added to the method that will add and remove configuration
1866c89d0038SJuraj Linkeš    that's necessary to retrieve the capability support status.
1867c89d0038SJuraj Linkeš    The Enum members may be assigned the method itself or a tuple of
1868c89d0038SJuraj Linkeš    (capability_checking_method, decorator_function).
1869c89d0038SJuraj Linkeš
1870c89d0038SJuraj Linkeš    The signature of each :class:`TestPmdShell` capability checking method must be::
1871c89d0038SJuraj Linkeš
1872c89d0038SJuraj Linkeš        fn(self, supported_capabilities: MutableSet, unsupported_capabilities: MutableSet) -> None
1873c89d0038SJuraj Linkeš
1874c89d0038SJuraj Linkeš    The capability checking method must get whether a capability is supported or not
1875c89d0038SJuraj Linkeš    from a testpmd command. If multiple capabilities can be obtained from a testpmd command,
1876c89d0038SJuraj Linkeš    each should be obtained in the method. These capabilities should then
1877c89d0038SJuraj Linkeš    be added to `supported_capabilities` or `unsupported_capabilities` based on their support.
1878c89d0038SJuraj Linkeš
1879c89d0038SJuraj Linkeš    The two dictionaries are shared across all capability discovery function calls in a given
1880c0119400SJuraj Linkeš    test run so that we don't call the same function multiple times. For example, when we find
1881c0119400SJuraj Linkeš    :attr:`SCATTERED_RX_ENABLED` in :meth:`TestPmdShell.get_capabilities_rxq_info`,
1882c0119400SJuraj Linkeš    we don't go looking for it again if a different test case also needs it.
1883c89d0038SJuraj Linkeš    """
1884c89d0038SJuraj Linkeš
1885c0119400SJuraj Linkeš    #: Scattered packets Rx enabled
1886c0119400SJuraj Linkeš    SCATTERED_RX_ENABLED: TestPmdShellNicCapability = (
1887c0119400SJuraj Linkeš        TestPmdShell.get_capabilities_rxq_info,
1888c0119400SJuraj Linkeš        add_remove_mtu(9000),
1889c0119400SJuraj Linkeš    )
1890a79884f9SJuraj Linkeš    #:
1891a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN_STRIP: TestPmdShellCapabilityMethod = functools.partial(
1892a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1893a79884f9SJuraj Linkeš    )
1894a79884f9SJuraj Linkeš    #: Device supports L3 checksum offload.
1895a79884f9SJuraj Linkeš    RX_OFFLOAD_IPV4_CKSUM: TestPmdShellCapabilityMethod = functools.partial(
1896a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1897a79884f9SJuraj Linkeš    )
1898a79884f9SJuraj Linkeš    #: Device supports L4 checksum offload.
1899a79884f9SJuraj Linkeš    RX_OFFLOAD_UDP_CKSUM: TestPmdShellCapabilityMethod = functools.partial(
1900a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1901a79884f9SJuraj Linkeš    )
1902a79884f9SJuraj Linkeš    #: Device supports L4 checksum offload.
1903a79884f9SJuraj Linkeš    RX_OFFLOAD_TCP_CKSUM: TestPmdShellCapabilityMethod = functools.partial(
1904a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1905a79884f9SJuraj Linkeš    )
1906a79884f9SJuraj Linkeš    #: Device supports Large Receive Offload.
1907a79884f9SJuraj Linkeš    RX_OFFLOAD_TCP_LRO: TestPmdShellCapabilityMethod = functools.partial(
1908a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1909a79884f9SJuraj Linkeš    )
1910a79884f9SJuraj Linkeš    #: Device supports QinQ (queue in queue) offload.
1911a79884f9SJuraj Linkeš    RX_OFFLOAD_QINQ_STRIP: TestPmdShellCapabilityMethod = functools.partial(
1912a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1913a79884f9SJuraj Linkeš    )
1914a79884f9SJuraj Linkeš    #: Device supports inner packet L3 checksum.
1915a79884f9SJuraj Linkeš    RX_OFFLOAD_OUTER_IPV4_CKSUM: TestPmdShellCapabilityMethod = functools.partial(
1916a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1917a79884f9SJuraj Linkeš    )
1918a79884f9SJuraj Linkeš    #: Device supports MACsec.
1919a79884f9SJuraj Linkeš    RX_OFFLOAD_MACSEC_STRIP: TestPmdShellCapabilityMethod = functools.partial(
1920a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1921a79884f9SJuraj Linkeš    )
1922a79884f9SJuraj Linkeš    #: Device supports filtering of a VLAN Tag identifier.
1923a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN_FILTER: TestPmdShellCapabilityMethod = functools.partial(
1924a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1925a79884f9SJuraj Linkeš    )
1926a79884f9SJuraj Linkeš    #: Device supports VLAN offload.
1927a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN_EXTEND: TestPmdShellCapabilityMethod = functools.partial(
1928a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1929a79884f9SJuraj Linkeš    )
1930a79884f9SJuraj Linkeš    #: Device supports receiving segmented mbufs.
1931a79884f9SJuraj Linkeš    RX_OFFLOAD_SCATTER: TestPmdShellCapabilityMethod = functools.partial(
1932a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1933a79884f9SJuraj Linkeš    )
1934a79884f9SJuraj Linkeš    #: Device supports Timestamp.
1935a79884f9SJuraj Linkeš    RX_OFFLOAD_TIMESTAMP: TestPmdShellCapabilityMethod = functools.partial(
1936a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1937a79884f9SJuraj Linkeš    )
1938a79884f9SJuraj Linkeš    #: Device supports crypto processing while packet is received in NIC.
1939a79884f9SJuraj Linkeš    RX_OFFLOAD_SECURITY: TestPmdShellCapabilityMethod = functools.partial(
1940a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1941a79884f9SJuraj Linkeš    )
1942a79884f9SJuraj Linkeš    #: Device supports CRC stripping.
1943a79884f9SJuraj Linkeš    RX_OFFLOAD_KEEP_CRC: TestPmdShellCapabilityMethod = functools.partial(
1944a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1945a79884f9SJuraj Linkeš    )
1946a79884f9SJuraj Linkeš    #: Device supports L4 checksum offload.
1947a79884f9SJuraj Linkeš    RX_OFFLOAD_SCTP_CKSUM: TestPmdShellCapabilityMethod = functools.partial(
1948a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1949a79884f9SJuraj Linkeš    )
1950a79884f9SJuraj Linkeš    #: Device supports inner packet L4 checksum.
1951a79884f9SJuraj Linkeš    RX_OFFLOAD_OUTER_UDP_CKSUM: TestPmdShellCapabilityMethod = functools.partial(
1952a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1953a79884f9SJuraj Linkeš    )
1954a79884f9SJuraj Linkeš    #: Device supports RSS hashing.
1955a79884f9SJuraj Linkeš    RX_OFFLOAD_RSS_HASH: TestPmdShellCapabilityMethod = functools.partial(
1956a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1957a79884f9SJuraj Linkeš    )
1958a79884f9SJuraj Linkeš    #: Device supports scatter Rx packets to segmented mbufs.
1959a79884f9SJuraj Linkeš    RX_OFFLOAD_BUFFER_SPLIT: TestPmdShellCapabilityMethod = functools.partial(
1960a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1961a79884f9SJuraj Linkeš    )
1962a79884f9SJuraj Linkeš    #: Device supports all checksum capabilities.
1963a79884f9SJuraj Linkeš    RX_OFFLOAD_CHECKSUM: TestPmdShellCapabilityMethod = functools.partial(
1964a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1965a79884f9SJuraj Linkeš    )
1966a79884f9SJuraj Linkeš    #: Device supports all VLAN capabilities.
1967a79884f9SJuraj Linkeš    RX_OFFLOAD_VLAN: TestPmdShellCapabilityMethod = functools.partial(
1968a79884f9SJuraj Linkeš        TestPmdShell.get_capabilities_rx_offload
1969a79884f9SJuraj Linkeš    )
1970*d64f6ba5SJuraj Linkeš    #: Device supports Rx queue setup after device started.
1971*d64f6ba5SJuraj Linkeš    RUNTIME_RX_QUEUE_SETUP: TestPmdShellCapabilityMethod = functools.partial(
1972*d64f6ba5SJuraj Linkeš        TestPmdShell.get_capabilities_show_port_info
1973*d64f6ba5SJuraj Linkeš    )
1974*d64f6ba5SJuraj Linkeš    #: Device supports Tx queue setup after device started.
1975*d64f6ba5SJuraj Linkeš    RUNTIME_TX_QUEUE_SETUP: TestPmdShellCapabilityMethod = functools.partial(
1976*d64f6ba5SJuraj Linkeš        TestPmdShell.get_capabilities_show_port_info
1977*d64f6ba5SJuraj Linkeš    )
1978*d64f6ba5SJuraj Linkeš    #: Device supports shared Rx queue among ports within Rx domain and switch domain.
1979*d64f6ba5SJuraj Linkeš    RXQ_SHARE: TestPmdShellCapabilityMethod = functools.partial(
1980*d64f6ba5SJuraj Linkeš        TestPmdShell.get_capabilities_show_port_info
1981*d64f6ba5SJuraj Linkeš    )
1982*d64f6ba5SJuraj Linkeš    #: Device supports keeping flow rules across restart.
1983*d64f6ba5SJuraj Linkeš    FLOW_RULE_KEEP: TestPmdShellCapabilityMethod = functools.partial(
1984*d64f6ba5SJuraj Linkeš        TestPmdShell.get_capabilities_show_port_info
1985*d64f6ba5SJuraj Linkeš    )
1986*d64f6ba5SJuraj Linkeš    #: Device supports keeping shared flow objects across restart.
1987*d64f6ba5SJuraj Linkeš    FLOW_SHARED_OBJECT_KEEP: TestPmdShellCapabilityMethod = functools.partial(
1988*d64f6ba5SJuraj Linkeš        TestPmdShell.get_capabilities_show_port_info
1989*d64f6ba5SJuraj Linkeš    )
1990c0119400SJuraj Linkeš
1991c89d0038SJuraj Linkeš    def __call__(
1992c89d0038SJuraj Linkeš        self,
1993c89d0038SJuraj Linkeš        testpmd_shell: TestPmdShell,
1994c89d0038SJuraj Linkeš        supported_capabilities: MutableSet[Self],
1995c89d0038SJuraj Linkeš        unsupported_capabilities: MutableSet[Self],
1996c89d0038SJuraj Linkeš    ) -> None:
1997c89d0038SJuraj Linkeš        """Execute the associated capability retrieval function.
1998c89d0038SJuraj Linkeš
1999c89d0038SJuraj Linkeš        Args:
2000c89d0038SJuraj Linkeš            testpmd_shell: :class:`TestPmdShell` object to which the function will be bound to.
2001c89d0038SJuraj Linkeš            supported_capabilities: The dictionary storing the supported capabilities
2002c89d0038SJuraj Linkeš                of a given test run.
2003c89d0038SJuraj Linkeš            unsupported_capabilities: The dictionary storing the unsupported capabilities
2004c89d0038SJuraj Linkeš                of a given test run.
2005c89d0038SJuraj Linkeš        """
2006c89d0038SJuraj Linkeš        self.value(testpmd_shell, supported_capabilities, unsupported_capabilities)
2007