xref: /dpdk/dts/framework/remote_session/testpmd_shell.py (revision 3da59f30a23f2e795d2315f3d949e1b3e0ce0c3d)
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright(c) 2023 University of New Hampshire
3# Copyright(c) 2023 PANTHEON.tech s.r.o.
4
5"""Testpmd interactive shell.
6
7Typical usage example in a TestSuite::
8
9    testpmd_shell = self.sut_node.create_interactive_shell(
10            TestPmdShell, privileged=True
11        )
12    devices = testpmd_shell.get_devices()
13    for device in devices:
14        print(device)
15    testpmd_shell.close()
16"""
17
18from pathlib import PurePath
19from typing import Callable, ClassVar
20
21from .interactive_shell import InteractiveShell
22
23
24class TestPmdDevice(object):
25    """The data of a device that testpmd can recognize.
26
27    Attributes:
28        pci_address: The PCI address of the device.
29    """
30
31    pci_address: str
32
33    def __init__(self, pci_address_line: str):
34        """Initialize the device from the testpmd output line string.
35
36        Args:
37            pci_address_line: A line of testpmd output that contains a device.
38        """
39        self.pci_address = pci_address_line.strip().split(": ")[1].strip()
40
41    def __str__(self) -> str:
42        """The PCI address captures what the device is."""
43        return self.pci_address
44
45
46class TestPmdShell(InteractiveShell):
47    """Testpmd interactive shell.
48
49    The testpmd shell users should never use
50    the :meth:`~.interactive_shell.InteractiveShell.send_command` method directly, but rather
51    call specialized methods. If there isn't one that satisfies a need, it should be added.
52    """
53
54    #: The path to the testpmd executable.
55    path: ClassVar[PurePath] = PurePath("app", "dpdk-testpmd")
56
57    #: Flag this as a DPDK app so that it's clear this is not a system app and
58    #: needs to be looked in a specific path.
59    dpdk_app: ClassVar[bool] = True
60
61    #: The testpmd's prompt.
62    _default_prompt: ClassVar[str] = "testpmd>"
63
64    #: This forces the prompt to appear after sending a command.
65    _command_extra_chars: ClassVar[str] = "\n"
66
67    def _start_application(self, get_privileged_command: Callable[[str], str] | None) -> None:
68        self._app_args += " -- -i"
69        super()._start_application(get_privileged_command)
70
71    def get_devices(self) -> list[TestPmdDevice]:
72        """Get a list of device names that are known to testpmd.
73
74        Uses the device info listed in testpmd and then parses the output.
75
76        Returns:
77            A list of devices.
78        """
79        dev_info: str = self.send_command("show device info all")
80        dev_list: list[TestPmdDevice] = []
81        for line in dev_info.split("\n"):
82            if "device name:" in line.lower():
83                dev_list.append(TestPmdDevice(line))
84        return dev_list
85