File: blocking_app.py

package info (click to toggle)
dpdk 25.11-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 127,892 kB
  • sloc: ansic: 2,358,479; python: 16,426; sh: 4,474; makefile: 1,713; awk: 70
file content (139 lines) | stat: -rw-r--r-- 4,356 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2025 Arm Limited

"""Class to run blocking apps in the background.

The class won't automatically start the app. The start-up is done as part of the
:meth:`BlockingApp.wait_until_ready` method, which will return execution to the caller only
when the desired stdout has been returned by the app. Usually this is used to detect when the app
has been loaded and ready to be used.

This module also provides the class :class:`BlockingDPDKApp` useful to run any DPDK app from the
DPDK build dir.

Example:
    ..code:: python

        pdump = BlockingDPDKApp(
            PurePath("app/dpdk-pdump"),
            app_params="--pdump 'port=0,queue=*,rx-dev=/tmp/rx-dev.pcap'"
        )
        pdump.wait_until_ready("65535") # start app

        # pdump is now ready to capture

        pdump.close() # stop/close app
"""

from pathlib import PurePath
from typing import Generic, TypeVar, cast

from typing_extensions import Self

from framework.context import get_ctx
from framework.params import Params
from framework.params.eal import EalParams
from framework.remote_session.dpdk_shell import compute_eal_params
from framework.remote_session.interactive_shell import InteractiveShell
from framework.testbed_model.node import Node

P = TypeVar("P", bound=Params)


class BlockingApp(InteractiveShell, Generic[P]):
    """Class to manage generic blocking apps."""

    _app_params: P

    def __init__(
        self,
        node: Node,
        path: str | PurePath,
        name: str | None = None,
        privileged: bool = False,
        app_params: P | str = "",
        add_to_shell_pool: bool = True,
    ) -> None:
        """Constructor.

        Args:
            node: The node to run the app on.
            path: Path to the application on the node.s
            name: Name to identify this application.
            privileged: Run as privileged user.
            app_params: The application parameters. Can be of any type inheriting :class:`Params` or
                a plain string.
            add_to_shell_pool: If :data:`True`, the blocking app's shell will be added to the
                shell pool.
        """
        if isinstance(app_params, str):
            params = Params()
            params.append_str(app_params)
            app_params = cast(P, params)

        self._path = path
        self._add_to_shell_pool = add_to_shell_pool

        super().__init__(node, name, privileged, app_params)

    @property
    def path(self) -> str | PurePath:
        """The path of the DPDK app relative to the DPDK build folder."""
        return self._path

    def wait_until_ready(self, end_token: str) -> Self:
        """Start app and wait until ready.

        Args:
            end_token: The string at the end of a line that indicates the app is ready.

        Returns:
            Itself.
        """
        self.start_application(end_token, self._add_to_shell_pool)
        return self

    def close(self) -> None:
        """Close the application.

        Sends a SIGINT to close the application.
        """
        self.send_command("\x03")
        super().close()


PE = TypeVar("PE", bound=EalParams)


class BlockingDPDKApp(BlockingApp, Generic[PE]):
    """Class to manage blocking DPDK apps on the SUT."""

    _app_params: PE

    def __init__(
        self,
        path: PurePath,
        name: str | None = None,
        privileged: bool = True,
        app_params: PE | str = "",
    ) -> None:
        """Constructor.

        Args:
            path: Path relative to the DPDK build to the executable.
            name: Name to identify this application.
            privileged: Run as privileged user.
            app_params: The application parameters. If a string or an incomplete :class:`EalParams`
                object are passed, the EAL params are computed based on the current context.
        """
        if isinstance(app_params, str):
            eal_params = compute_eal_params()
            eal_params.append_str(app_params)
            app_params = cast(PE, eal_params)
        else:
            app_params = cast(PE, compute_eal_params(app_params))

        node = get_ctx().sut_node
        path = PurePath(get_ctx().dpdk_build.remote_dpdk_build_dir).joinpath(self.path)

        super().__init__(node, path, name, privileged, app_params)