On Thu, Sep 26, 2024 at 4:25 AM Juraj Linkeš <juraj.linkes@pantheon.tech> wrote:
>
>
> > diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
>
> > @@ -581,6 +581,506 @@ class TestPmdPortStats(TextParser):
> > tx_bps: int = field(metadata=TextParser.find_int(r"Tx-bps:\s+(\d+)"))
> >
> >
> > +class PacketOffloadFlag(Flag):
>
> > + #: RX IEEE1588 L2 Ethernet PT Packet.
> > + RTE_MBUF_F_RX_IEEE1588_PTP = 1 << 9
> > + #: RX IEEE1588 L2/L4 timestamped packet.
> > + RTE_MBUF_F_RX_IEEE1588_TMST = 1 << 10
>
> There are a few instances with two or three consecutive bits set
> expliticly instead with auto(). I don't know if it's better to use
> auto() or the explitic value, just wanted to point it out.
>
If it was only two consecutive bits I avoided using auto because I
thought that made it more clear (at least for me, it felt like less
bouncing back and forth). This is a good point though, I also don't
know which is really better.
>
> > +
> > + #: FD id reported if FDIR match.
> > + RTE_MBUF_F_RX_FDIR_ID = 1 << 13
> > + #: Flexible bytes reported if FDIR match.
> > + RTE_MBUF_F_RX_FDIR_FLX = 1 << 14
> > + @classmethod
> > + def from_str(cls, flags: str) -> Self:
>
> Now that we're doing the same thing as the other classes, I think it
> makes sense to just flat out copy-paste the from_list_string method.
Sure, that makes sense to me.
>
> > + """Makes an instance from a string containing whitespace-separated the flag members.
> > +
> > + Args:
> > + arr: A string containing ol_flag values.
> > +
> > + Returns:
> > + A new instance of the flag.
> > + """
> > + flag = cls(0)
> > + for name in flags.split():
> > + if hasattr(cls, name):
>
> This is still different from the other class. I think making these
> exactly the same would make it clear what needs to be put into the base
> class if we ever create one.
Ack.
>
> > + flag |= cls[name]
> > + return flag
>
> > +
> > +class RtePTypes(Flag):
> > + """Flag representing possible packet types in DPDK verbose output.
> > +
> > + Values in this class are derived from definitions in the RTE MBUF ptype library in DPDK located
> > + in lib/mbuf/rte_mbuf_ptype.h. Specifically, the names of values in this class should match the
> > + possible return options from the methods rte_get_ptype_*_name in rte_mbuf_ptype.c.
>
> I think these are functions (rte_get_ptype_*_name), not methods.
>
Ahh, good call. I wasn't thinking of the distinction when I wrote it.
> > + """
>
> You didn't update the docstring here (double backticks (for file and
> function names) and the References: section).
Good catch, I'll fix those as well.
>
>
> > + @classmethod
> > + def from_str(cls, flags: str) -> Self:
>
> The same comments apply here.
Ack.
>
>
@@ -32,7 +32,7 @@
from framework.settings import SETTINGS
from framework.testbed_model.cpu import LogicalCoreCount, LogicalCoreList
from framework.testbed_model.sut_node import SutNode
-from framework.utils import StrEnum
+from framework.utils import REGEX_FOR_MAC_ADDRESS, StrEnum
P = ParamSpec("P")
TestPmdShellMethod = Callable[Concatenate["TestPmdShell", P], Any]
@@ -581,6 +581,506 @@ class TestPmdPortStats(TextParser):
tx_bps: int = field(metadata=TextParser.find_int(r"Tx-bps:\s+(\d+)"))
+class PacketOffloadFlag(Flag):
+ """Flag representing the Packet Offload Features Flags in DPDK.
+
+ Values in this class are taken from the definitions in the RTE MBUF core library in DPDK
+ located in ``lib/mbuf/rte_mbuf_core.h``. It is expected that flag values in this class will
+ match the values they are set to in said DPDK library with one exception; all values must be
+ unique. For example, the definitions for unknown checksum flags in ``rte_mbuf_core.h`` are all
+ set to :data:`0`, but it is valuable to distinguish between them in this framework. For this
+ reason flags that are not unique in the DPDK library are set either to values within the
+ RTE_MBUF_F_FIRST_FREE-RTE_MBUF_F_LAST_FREE range for Rx or shifted 61+ bits for Tx.
+
+ References:
+ DPDK lib: ``lib/mbuf/rte_mbuf_core.h``
+ """
+
+ # RX flags
+
+ #: The RX packet is a 802.1q VLAN packet, and the tci has been saved in mbuf->vlan_tci. If the
+ #: flag RTE_MBUF_F_RX_VLAN_STRIPPED is also present, the VLAN header has been stripped from
+ #: mbuf data, else it is still present.
+ RTE_MBUF_F_RX_VLAN = auto()
+
+ #: RX packet with RSS hash result.
+ RTE_MBUF_F_RX_RSS_HASH = auto()
+
+ #: RX packet with FDIR match indicate.
+ RTE_MBUF_F_RX_FDIR = auto()
+
+ #: This flag is set when the outermost IP header checksum is detected as wrong by the hardware.
+ RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD = 1 << 5
+
+ #: A vlan has been stripped by the hardware and its tci is saved in mbuf->vlan_tci. This can
+ #: only happen if vlan stripping is enabled in the RX configuration of the PMD. When
+ #: RTE_MBUF_F_RX_VLAN_STRIPPED is set, RTE_MBUF_F_RX_VLAN must also be set.
+ RTE_MBUF_F_RX_VLAN_STRIPPED = auto()
+
+ #: No information about the RX IP checksum. Value is 0 in the DPDK library.
+ RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN = 1 << 23
+ #: The IP checksum in the packet is wrong.
+ RTE_MBUF_F_RX_IP_CKSUM_BAD = 1 << 4
+ #: The IP checksum in the packet is valid.
+ RTE_MBUF_F_RX_IP_CKSUM_GOOD = 1 << 7
+ #: The IP checksum is not correct in the packet data, but the integrity of the IP header is
+ #: verified. Value is RTE_MBUF_F_RX_IP_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_GOOD in the DPDK
+ #: library.
+ RTE_MBUF_F_RX_IP_CKSUM_NONE = 1 << 24
+
+ #: No information about the RX L4 checksum. Value is 0 in the DPDK library.
+ RTE_MBUF_F_RX_L4_CKSUM_UNKNOWN = 1 << 25
+ #: The L4 checksum in the packet is wrong.
+ RTE_MBUF_F_RX_L4_CKSUM_BAD = 1 << 3
+ #: The L4 checksum in the packet is valid.
+ RTE_MBUF_F_RX_L4_CKSUM_GOOD = 1 << 8
+ #: The L4 checksum is not correct in the packet data, but the integrity of the L4 data is
+ #: verified. Value is RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD in the DPDK
+ #: library.
+ RTE_MBUF_F_RX_L4_CKSUM_NONE = 1 << 26
+
+ #: RX IEEE1588 L2 Ethernet PT Packet.
+ RTE_MBUF_F_RX_IEEE1588_PTP = 1 << 9
+ #: RX IEEE1588 L2/L4 timestamped packet.
+ RTE_MBUF_F_RX_IEEE1588_TMST = 1 << 10
+
+ #: FD id reported if FDIR match.
+ RTE_MBUF_F_RX_FDIR_ID = 1 << 13
+ #: Flexible bytes reported if FDIR match.
+ RTE_MBUF_F_RX_FDIR_FLX = 1 << 14
+
+ #: If both RTE_MBUF_F_RX_QINQ_STRIPPED and RTE_MBUF_F_RX_VLAN_STRIPPED are set, the 2 VLANs
+ #: have been stripped by the hardware. If RTE_MBUF_F_RX_QINQ_STRIPPED is set and
+ #: RTE_MBUF_F_RX_VLAN_STRIPPED is unset, only the outer VLAN is removed from packet data.
+ RTE_MBUF_F_RX_QINQ_STRIPPED = auto()
+
+ #: When packets are coalesced by a hardware or virtual driver, this flag can be set in the RX
+ #: mbuf, meaning that the m->tso_segsz field is valid and is set to the segment size of
+ #: original packets.
+ RTE_MBUF_F_RX_LRO = auto()
+
+ #: Indicate that security offload processing was applied on the RX packet.
+ RTE_MBUF_F_RX_SEC_OFFLOAD = 1 << 18
+ #: Indicate that security offload processing failed on the RX packet.
+ RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED = auto()
+
+ #: The RX packet is a double VLAN. If this flag is set, RTE_MBUF_F_RX_VLAN must also be set. If
+ #: the flag RTE_MBUF_F_RX_QINQ_STRIPPED is also present, both VLANs headers have been stripped
+ #: from mbuf data, else they are still present.
+ RTE_MBUF_F_RX_QINQ = auto()
+
+ #: No info about the outer RX L4 checksum. Value is 0 in the DPDK library.
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_UNKNOWN = 1 << 27
+ #: The outer L4 checksum in the packet is wrong
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_BAD = 1 << 21
+ #: The outer L4 checksum in the packet is valid
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_GOOD = 1 << 22
+ #: Invalid outer L4 checksum state. Value is
+ #: RTE_MBUF_F_RX_OUTER_L4_CKSUM_BAD | RTE_MBUF_F_RX_OUTER_L4_CKSUM_GOOD in the DPDK library.
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_INVALID = 1 << 28
+
+ # TX flags
+
+ #: Outer UDP checksum offload flag. This flag is used for enabling outer UDP checksum in PMD.
+ #: To use outer UDP checksum, the user either needs to enable the following in mbuf:
+ #:
+ #: a) Fill outer_l2_len and outer_l3_len in mbuf.
+ #: b) Set the RTE_MBUF_F_TX_OUTER_UDP_CKSUM flag.
+ #: c) Set the RTE_MBUF_F_TX_OUTER_IPV4 or RTE_MBUF_F_TX_OUTER_IPV6 flag.
+ #:
+ #: Or configure RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM offload flag.
+ RTE_MBUF_F_TX_OUTER_UDP_CKSUM = 1 << 41
+
+ #: UDP Fragmentation Offload flag. This flag is used for enabling UDP fragmentation in SW or in
+ #: HW.
+ RTE_MBUF_F_TX_UDP_SEG = auto()
+
+ #: Request security offload processing on the TX packet. To use Tx security offload, the user
+ #: needs to fill l2_len in mbuf indicating L2 header size and where L3 header starts.
+ #: Similarly, l3_len should also be filled along with ol_flags reflecting current L3 type.
+ RTE_MBUF_F_TX_SEC_OFFLOAD = auto()
+
+ #: Offload the MACsec. This flag must be set by the application to enable this offload feature
+ #: for a packet to be transmitted.
+ RTE_MBUF_F_TX_MACSEC = auto()
+
+ # Bits 45:48 are used for the tunnel type in ``lib/mbuf/rte_mbuf_core.h``, but some are modified
+ # in this Flag to maintain uniqueness. The tunnel type must be specified for TSO or checksum on
+ # the inner part of tunnel packets. These flags can be used with RTE_MBUF_F_TX_TCP_SEG for TSO,
+ # or RTE_MBUF_F_TX_xxx_CKSUM. The mbuf fields for inner and outer header lengths are required:
+ # outer_l2_len, outer_l3_len, l2_len, l3_len, l4_len and tso_segsz for TSO.
+
+ #:
+ RTE_MBUF_F_TX_TUNNEL_VXLAN = 1 << 45
+ #:
+ RTE_MBUF_F_TX_TUNNEL_GRE = 1 << 46
+ #: Value is 3 << 45 in the DPDK library.
+ RTE_MBUF_F_TX_TUNNEL_IPIP = 1 << 61
+ #:
+ RTE_MBUF_F_TX_TUNNEL_GENEVE = 1 << 47
+ #: TX packet with MPLS-in-UDP RFC 7510 header. Value is 5 << 45 in the DPDK library.
+ RTE_MBUF_F_TX_TUNNEL_MPLSINUDP = 1 << 62
+ #: Value is 6 << 45 in the DPDK library.
+ RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE = 1 << 63
+ #: Value is 7 << 45 in the DPDK library.
+ RTE_MBUF_F_TX_TUNNEL_GTP = 1 << 64
+ #:
+ RTE_MBUF_F_TX_TUNNEL_ESP = 1 << 48
+ #: Generic IP encapsulated tunnel type, used for TSO and checksum offload. This can be used for
+ #: tunnels which are not standards or listed above. It is preferred to use specific tunnel
+ #: flags like RTE_MBUF_F_TX_TUNNEL_GRE or RTE_MBUF_F_TX_TUNNEL_IPIP if possible. The ethdev
+ #: must be configured with RTE_ETH_TX_OFFLOAD_IP_TNL_TSO. Outer and inner checksums are done
+ #: according to the existing flags like RTE_MBUF_F_TX_xxx_CKSUM. Specific tunnel headers that
+ #: contain payload length, sequence id or checksum are not expected to be updated. Value is
+ #: 0xD << 45 in the DPDK library.
+ RTE_MBUF_F_TX_TUNNEL_IP = 1 << 65
+ #: Generic UDP encapsulated tunnel type, used for TSO and checksum offload. UDP tunnel type
+ #: implies outer IP layer. It can be used for tunnels which are not standards or listed above.
+ #: It is preferred to use specific tunnel flags like RTE_MBUF_F_TX_TUNNEL_VXLAN if possible.
+ #: The ethdev must be configured with RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO. Outer and inner checksums
+ #: are done according to the existing flags like RTE_MBUF_F_TX_xxx_CKSUM. Specific tunnel
+ #: headers that contain payload length, sequence id or checksum are not expected to be updated.
+ #: value is 0xE << 45 in the DPDK library.
+ RTE_MBUF_F_TX_TUNNEL_UDP = 1 << 66
+
+ #: Double VLAN insertion (QinQ) request to driver, driver may offload the insertion based on
+ #: device capability. Mbuf 'vlan_tci' & 'vlan_tci_outer' must be valid when this flag is set.
+ RTE_MBUF_F_TX_QINQ = 1 << 49
+
+ #: TCP segmentation offload. To enable this offload feature for a packet to be transmitted on
+ #: hardware supporting TSO:
+ #:
+ #: - set the RTE_MBUF_F_TX_TCP_SEG flag in mbuf->ol_flags (this flag implies
+ #: RTE_MBUF_F_TX_TCP_CKSUM)
+ #: - set the flag RTE_MBUF_F_TX_IPV4 or RTE_MBUF_F_TX_IPV6
+ #: * if it's IPv4, set the RTE_MBUF_F_TX_IP_CKSUM flag
+ #: - fill the mbuf offload information: l2_len, l3_len, l4_len, tso_segsz
+ RTE_MBUF_F_TX_TCP_SEG = auto()
+
+ #: TX IEEE1588 packet to timestamp.
+ RTE_MBUF_F_TX_IEEE1588_TMST = auto()
+
+ # Bits 52+53 used for L4 packet type with checksum enabled in ``lib/mbuf/rte_mbuf_core.h`` but
+ # some values must be modified in this framework to maintain uniqueness. To use hardware
+ # L4 checksum offload, the user needs to:
+ #
+ # - fill l2_len and l3_len in mbuf
+ # - set the flags RTE_MBUF_F_TX_TCP_CKSUM, RTE_MBUF_F_TX_SCTP_CKSUM or
+ # RTE_MBUF_F_TX_UDP_CKSUM
+ # - set the flag RTE_MBUF_F_TX_IPV4 or RTE_MBUF_F_TX_IPV6
+
+ #: Disable L4 cksum of TX pkt. Value is 0 in the DPDK library.
+ RTE_MBUF_F_TX_L4_NO_CKSUM = 1 << 67
+ #: TCP cksum of TX pkt. Computed by NIC.
+ RTE_MBUF_F_TX_TCP_CKSUM = 1 << 52
+ #: SCTP cksum of TX pkt. Computed by NIC.
+ RTE_MBUF_F_TX_SCTP_CKSUM = 1 << 53
+ #: UDP cksum of TX pkt. Computed by NIC. Value is 3 << 52 in the DPDK library.
+ RTE_MBUF_F_TX_UDP_CKSUM = 1 << 68
+
+ #: Offload the IP checksum in the hardware. The flag RTE_MBUF_F_TX_IPV4 should also be set by
+ #: the application, although a PMD will only check RTE_MBUF_F_TX_IP_CKSUM.
+ RTE_MBUF_F_TX_IP_CKSUM = 1 << 54
+
+ #: Packet is IPv4. This flag must be set when using any offload feature (TSO, L3 or L4
+ #: checksum) to tell the NIC that the packet is an IPv4 packet. If the packet is a tunneled
+ #: packet, this flag is related to the inner headers.
+ RTE_MBUF_F_TX_IPV4 = auto()
+ #: Packet is IPv6. This flag must be set when using an offload feature (TSO or L4 checksum) to
+ #: tell the NIC that the packet is an IPv6 packet. If the packet is a tunneled packet, this
+ #: flag is related to the inner headers.
+ RTE_MBUF_F_TX_IPV6 = auto()
+ #: VLAN tag insertion request to driver, driver may offload the insertion based on the device
+ #: capability. mbuf 'vlan_tci' field must be valid when this flag is set.
+ RTE_MBUF_F_TX_VLAN = auto()
+
+ #: Offload the IP checksum of an external header in the hardware. The flag
+ #: RTE_MBUF_F_TX_OUTER_IPV4 should also be set by the application, although a PMD will only
+ #: check RTE_MBUF_F_TX_OUTER_IP_CKSUM.
+ RTE_MBUF_F_TX_OUTER_IP_CKSUM = auto()
+ #: Packet outer header is IPv4. This flag must be set when using any outer offload feature (L3
+ #: or L4 checksum) to tell the NIC that the outer header of the tunneled packet is an IPv4
+ #: packet.
+ RTE_MBUF_F_TX_OUTER_IPV4 = auto()
+ #: Packet outer header is IPv6. This flag must be set when using any outer offload feature (L4
+ #: checksum) to tell the NIC that the outer header of the tunneled packet is an IPv6 packet.
+ RTE_MBUF_F_TX_OUTER_IPV6 = auto()
+
+ @classmethod
+ def from_str(cls, flags: str) -> Self:
+ """Makes an instance from a string containing whitespace-separated the flag members.
+
+ Args:
+ arr: A string containing ol_flag values.
+
+ Returns:
+ A new instance of the flag.
+ """
+ flag = cls(0)
+ for name in flags.split():
+ if hasattr(cls, name):
+ flag |= cls[name]
+ return flag
+
+ @classmethod
+ def make_parser(cls) -> ParserFn:
+ """Makes a parser function.
+
+ Returns:
+ ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
+ parser function that makes an instance of this flag from text.
+ """
+ return TextParser.wrap(
+ TextParser.find(r"ol_flags: ([^\n]+)"),
+ cls.from_str,
+ )
+
+
+class RtePTypes(Flag):
+ """Flag representing possible packet types in DPDK verbose output.
+
+ Values in this class are derived from definitions in the RTE MBUF ptype library in DPDK located
+ in lib/mbuf/rte_mbuf_ptype.h. Specifically, the names of values in this class should match the
+ possible return options from the methods rte_get_ptype_*_name in rte_mbuf_ptype.c.
+ """
+
+ # L2
+ #: Ethernet packet type. This is used for outer packet for tunneling cases.
+ L2_ETHER = auto()
+ #: Ethernet packet type for time sync.
+ L2_ETHER_TIMESYNC = auto()
+ #: ARP (Address Resolution Protocol) packet type.
+ L2_ETHER_ARP = auto()
+ #: LLDP (Link Layer Discovery Protocol) packet type.
+ L2_ETHER_LLDP = auto()
+ #: NSH (Network Service Header) packet type.
+ L2_ETHER_NSH = auto()
+ #: VLAN packet type.
+ L2_ETHER_VLAN = auto()
+ #: QinQ packet type.
+ L2_ETHER_QINQ = auto()
+ #: PPPOE packet type.
+ L2_ETHER_PPPOE = auto()
+ #: FCoE packet type..
+ L2_ETHER_FCOE = auto()
+ #: MPLS packet type.
+ L2_ETHER_MPLS = auto()
+ #: No L2 packet information.
+ L2_UNKNOWN = auto()
+
+ # L3
+ #: IP (Internet Protocol) version 4 packet type. This is used for outer packet for tunneling
+ #: cases, and does not contain any header option.
+ L3_IPV4 = auto()
+ #: IP (Internet Protocol) version 4 packet type. This is used for outer packet for tunneling
+ #: cases, and contains header options.
+ L3_IPV4_EXT = auto()
+ #: IP (Internet Protocol) version 6 packet type. This is used for outer packet for tunneling
+ #: cases, and does not contain any extension header.
+ L3_IPV6 = auto()
+ #: IP (Internet Protocol) version 4 packet type. This is used for outer packet for tunneling
+ #: cases, and may or maynot contain header options.
+ L3_IPV4_EXT_UNKNOWN = auto()
+ #: IP (Internet Protocol) version 6 packet type. This is used for outer packet for tunneling
+ #: cases, and contains extension headers.
+ L3_IPV6_EXT = auto()
+ #: IP (Internet Protocol) version 6 packet type. This is used for outer packet for tunneling
+ #: cases, and may or maynot contain extension headers.
+ L3_IPV6_EXT_UNKNOWN = auto()
+ #: No L3 packet information.
+ L3_UNKNOWN = auto()
+
+ # L4
+ #: TCP (Transmission Control Protocol) packet type. This is used for outer packet for tunneling
+ #: cases.
+ L4_TCP = auto()
+ #: UDP (User Datagram Protocol) packet type. This is used for outer packet for tunneling cases.
+ L4_UDP = auto()
+ #: Fragmented IP (Internet Protocol) packet type. This is used for outer packet for tunneling
+ #: cases and refers to those packets of any IP types which can be recognized as fragmented. A
+ #: fragmented packet cannot be recognized as any other L4 types (RTE_PTYPE_L4_TCP,
+ #: RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP, RTE_PTYPE_L4_NONFRAG).
+ L4_FRAG = auto()
+ #: SCTP (Stream Control Transmission Protocol) packet type. This is used for outer packet for
+ #: tunneling cases.
+ L4_SCTP = auto()
+ #: ICMP (Internet Control Message Protocol) packet type. This is used for outer packet for
+ #: tunneling cases.
+ L4_ICMP = auto()
+ #: Non-fragmented IP (Internet Protocol) packet type. This is used for outer packet for
+ #: tunneling cases and refers to those packets of any IP types, that cannot be recognized as
+ #: any of the above L4 types (RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_FRAG,
+ #: RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP).
+ L4_NONFRAG = auto()
+ #: IGMP (Internet Group Management Protocol) packet type.
+ L4_IGMP = auto()
+ #: No L4 packet information.
+ L4_UNKNOWN = auto()
+
+ # Tunnel
+ #: IP (Internet Protocol) in IP (Internet Protocol) tunneling packet type.
+ TUNNEL_IP = auto()
+ #: GRE (Generic Routing Encapsulation) tunneling packet type.
+ TUNNEL_GRE = auto()
+ #: VXLAN (Virtual eXtensible Local Area Network) tunneling packet type.
+ TUNNEL_VXLAN = auto()
+ #: NVGRE (Network Virtualization using Generic Routing Encapsulation) tunneling packet type.
+ TUNNEL_NVGRE = auto()
+ #: GENEVE (Generic Network Virtualization Encapsulation) tunneling packet type.
+ TUNNEL_GENEVE = auto()
+ #: Tunneling packet type of Teredo, VXLAN (Virtual eXtensible Local Area Network) or GRE
+ #: (Generic Routing Encapsulation) could be recognized as this packet type, if they can not be
+ #: recognized independently as of hardware capability.
+ TUNNEL_GRENAT = auto()
+ #: GTP-C (GPRS Tunnelling Protocol) control tunneling packet type.
+ TUNNEL_GTPC = auto()
+ #: GTP-U (GPRS Tunnelling Protocol) user data tunneling packet type.
+ TUNNEL_GTPU = auto()
+ #: ESP (IP Encapsulating Security Payload) tunneling packet type.
+ TUNNEL_ESP = auto()
+ #: L2TP (Layer 2 Tunneling Protocol) tunneling packet type.
+ TUNNEL_L2TP = auto()
+ #: VXLAN-GPE (VXLAN Generic Protocol Extension) tunneling packet type.
+ TUNNEL_VXLAN_GPE = auto()
+ #: MPLS-in-UDP tunneling packet type (RFC 7510).
+ TUNNEL_MPLS_IN_UDP = auto()
+ #: MPLS-in-GRE tunneling packet type (RFC 4023).
+ TUNNEL_MPLS_IN_GRE = auto()
+ #: No tunnel information found on the packet.
+ TUNNEL_UNKNOWN = auto()
+
+ # Inner L2
+ #: Ethernet packet type. This is used for inner packet type only.
+ INNER_L2_ETHER = auto()
+ #: Ethernet packet type with VLAN (Virtual Local Area Network) tag.
+ INNER_L2_ETHER_VLAN = auto()
+ #: QinQ packet type.
+ INNER_L2_ETHER_QINQ = auto()
+ #: No inner L2 information found on the packet.
+ INNER_L2_UNKNOWN = auto()
+
+ # Inner L3
+ #: IP (Internet Protocol) version 4 packet type. This is used for inner packet only, and does
+ #: not contain any header option.
+ INNER_L3_IPV4 = auto()
+ #: IP (Internet Protocol) version 4 packet type. This is used for inner packet only, and
+ #: contains header options.
+ INNER_L3_IPV4_EXT = auto()
+ #: IP (Internet Protocol) version 6 packet type. This is used for inner packet only, and does
+ #: not contain any extension header.
+ INNER_L3_IPV6 = auto()
+ #: IP (Internet Protocol) version 4 packet type. This is used for inner packet only, and may or
+ #: may not contain header options.
+ INNER_L3_IPV4_EXT_UNKNOWN = auto()
+ #: IP (Internet Protocol) version 6 packet type. This is used for inner packet only, and
+ #: contains extension headers.
+ INNER_L3_IPV6_EXT = auto()
+ #: IP (Internet Protocol) version 6 packet type. This is used for inner packet only, and may or
+ #: may not contain extension headers.
+ INNER_L3_IPV6_EXT_UNKNOWN = auto()
+ #: No inner L3 information found on the packet.
+ INNER_L3_UNKNOWN = auto()
+
+ # Inner L4
+ #: TCP (Transmission Control Protocol) packet type. This is used for inner packet only.
+ INNER_L4_TCP = auto()
+ #: UDP (User Datagram Protocol) packet type. This is used for inner packet only.
+ INNER_L4_UDP = auto()
+ #: Fragmented IP (Internet Protocol) packet type. This is used for inner packet only, and may
+ #: or maynot have a layer 4 packet.
+ INNER_L4_FRAG = auto()
+ #: SCTP (Stream Control Transmission Protocol) packet type. This is used for inner packet only.
+ INNER_L4_SCTP = auto()
+ #: ICMP (Internet Control Message Protocol) packet type. This is used for inner packet only.
+ INNER_L4_ICMP = auto()
+ #: Non-fragmented IP (Internet Protocol) packet type. It is used for inner packet only, and may
+ #: or may not have other unknown layer 4 packet types.
+ INNER_L4_NONFRAG = auto()
+ #: No inner L4 information found on the packet.
+ INNER_L4_UNKNOWN = auto()
+
+ @classmethod
+ def from_str(cls, flags: str) -> Self:
+ """Makes an instance from a string containing whitespace-separated the flag members.
+
+ Args:
+ flags: A string containing the packet types.
+
+ Returns:
+ A new instance of the flag.
+ """
+ flag = cls(0)
+ for name in flags.split():
+ if hasattr(cls, name):
+ flag |= cls[name]
+ return flag
+
+ @classmethod
+ def make_parser(cls, hw: bool) -> ParserFn:
+ """Makes a parser function.
+
+ Args:
+ hw: Whether to make a parser for hardware ptypes or software ptypes. If :data:`True`,
+ hardware ptypes will be collected, otherwise software pytpes will.
+
+ Returns:
+ ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a
+ parser function that makes an instance of this flag from text.
+ """
+ return TextParser.wrap(
+ TextParser.find(f"{'hw' if hw else 'sw'} ptype: ([^-]+)"),
+ cls.from_str,
+ )
+
+
+@dataclass
+class TestPmdVerbosePacket(TextParser):
+ """Packet information provided by verbose output in Testpmd.
+
+ This dataclass expects that packet information be prepended with the starting line of packet
+ bursts. Specifically, the line that reads "port X/queue Y: sent/received Z packets".
+ """
+
+ #: ID of the port that handled the packet.
+ port_id: int = field(metadata=TextParser.find_int(r"port (\d+)/queue \d+"))
+ #: ID of the queue that handled the packet.
+ queue_id: int = field(metadata=TextParser.find_int(r"port \d+/queue (\d+)"))
+ #: Whether the packet was received or sent by the queue/port.
+ was_received: bool = field(metadata=TextParser.find(r"received \d+ packets"))
+ #:
+ src_mac: str = field(metadata=TextParser.find(f"src=({REGEX_FOR_MAC_ADDRESS})"))
+ #:
+ dst_mac: str = field(metadata=TextParser.find(f"dst=({REGEX_FOR_MAC_ADDRESS})"))
+ #: Memory pool the packet was handled on.
+ pool: str = field(metadata=TextParser.find(r"pool=(\S+)"))
+ #: Packet type in hex.
+ p_type: int = field(metadata=TextParser.find_int(r"type=(0x[a-fA-F\d]+)"))
+ #:
+ length: int = field(metadata=TextParser.find_int(r"length=(\d+)"))
+ #: Number of segments in the packet.
+ nb_segs: int = field(metadata=TextParser.find_int(r"nb_segs=(\d+)"))
+ #: Hardware packet type.
+ hw_ptype: RtePTypes = field(metadata=RtePTypes.make_parser(hw=True))
+ #: Software packet type.
+ sw_ptype: RtePTypes = field(metadata=RtePTypes.make_parser(hw=False))
+ #:
+ l2_len: int = field(metadata=TextParser.find_int(r"l2_len=(\d+)"))
+ #:
+ ol_flags: PacketOffloadFlag = field(metadata=PacketOffloadFlag.make_parser())
+ #: RSS hash of the packet in hex.
+ rss_hash: int | None = field(
+ default=None, metadata=TextParser.find_int(r"RSS hash=(0x[a-fA-F\d]+)")
+ )
+ #: RSS queue that handled the packet in hex.
+ rss_queue: int | None = field(
+ default=None, metadata=TextParser.find_int(r"RSS queue=(0x[a-fA-F\d]+)")
+ )
+ #:
+ l3_len: int | None = field(default=None, metadata=TextParser.find_int(r"l3_len=(\d+)"))
+ #:
+ l4_len: int | None = field(default=None, metadata=TextParser.find_int(r"l4_len=(\d+)"))
+
+
def requires_stopped_ports(func: TestPmdShellMethod) -> TestPmdShellMethod:
"""Decorator for :class:`TestPmdShell` commands methods that require stopped ports.
@@ -714,7 +1214,7 @@ def start(self, verify: bool = True) -> None:
"Not all ports came up after starting packet forwarding in testpmd."
)
- def stop(self, verify: bool = True) -> None:
+ def stop(self, verify: bool = True) -> str:
"""Stop packet forwarding.
Args:
@@ -725,6 +1225,12 @@ def stop(self, verify: bool = True) -> None:
Raises:
InteractiveCommandExecutionError: If `verify` is :data:`True` and the command to stop
forwarding results in an error.
+
+ Returns:
+ Output gathered from the stop command and all other preceding logs in the buffer. This
+ output is most often used to view forwarding statistics that are displayed when this
+ command is sent as well as any verbose packet information that hasn't been consumed
+ prior to calling this method.
"""
stop_cmd_output = self.send_command("stop")
if verify:
@@ -734,6 +1240,7 @@ def stop(self, verify: bool = True) -> None:
):
self._logger.debug(f"Failed to stop packet forwarding: \n{stop_cmd_output}")
raise InteractiveCommandExecutionError("Testpmd failed to stop packet forwarding.")
+ return stop_cmd_output
def get_devices(self) -> list[TestPmdDevice]:
"""Get a list of device names that are known to testpmd.
@@ -981,6 +1488,32 @@ def set_port_mtu_all(self, mtu: int, verify: bool = True) -> None:
for port in self.ports:
self.set_port_mtu(port.id, mtu, verify)
+ @staticmethod
+ def extract_verbose_output(output: str) -> list[TestPmdVerbosePacket]:
+ """Extract the verbose information present in given testpmd output.
+
+ This method extracts sections of verbose output that begin with the line
+ "port X/queue Y: sent/received Z packets" and end with the ol_flags of a packet.
+
+ Args:
+ output: Testpmd output that contains verbose information
+
+ Returns:
+ List of parsed packet information gathered from verbose information in `output`.
+ """
+ out: list[TestPmdVerbosePacket] = []
+ prev_header: str = ""
+ iter = re.finditer(
+ r"(?P<HEADER>(?:port \d+/queue \d+: (?:received|sent) \d+ packets)?)\s*"
+ r"(?P<PACKET>src=[\w\s=:-]+?ol_flags: [\w ]+)",
+ output,
+ )
+ for match in iter:
+ if match.group("HEADER"):
+ prev_header = match.group("HEADER")
+ out.append(TestPmdVerbosePacket.parse(f"{prev_header}\n{match.group('PACKET')}"))
+ return out
+
def _close(self) -> None:
"""Overrides :meth:`~.interactive_shell.close`."""
self.stop()
@@ -29,6 +29,9 @@
from .exception import ConfigurationError, InternalError
REGEX_FOR_PCI_ADDRESS: str = "/[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}.[0-9]{1}/"
+_REGEX_FOR_COLON_OR_HYPHEN_SEP_MAC: str = r"(?:[\da-fA-F]{2}[:-]){5}[\da-fA-F]{2}"
+_REGEX_FOR_DOT_SEP_MAC: str = r"(?:[\da-fA-F]{4}.){2}[\da-fA-F]{4}"
+REGEX_FOR_MAC_ADDRESS: str = rf"{_REGEX_FOR_COLON_OR_HYPHEN_SEP_MAC}|{_REGEX_FOR_DOT_SEP_MAC}"
def expand_range(range_str: str) -> list[int]: