xref: /dpdk/dts/framework/testbed_model/traffic_generator/traffic_generator.py (revision b935bdc3da26ab86ec775dfad3aa63a1a61f5667)
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright(c) 2022 University of New Hampshire
3# Copyright(c) 2023 PANTHEON.tech s.r.o.
4
5"""The base traffic generator.
6
7These traffic generators can't capture received traffic,
8only count the number of received packets.
9"""
10
11from abc import ABC, abstractmethod
12
13from scapy.packet import Packet  # type: ignore[import-untyped]
14
15from framework.config import TrafficGeneratorConfig
16from framework.logger import DTSLogger, get_dts_logger
17from framework.testbed_model.node import Node
18from framework.testbed_model.port import Port
19from framework.utils import MultiInheritanceBaseClass, get_packet_summaries
20
21
22class TrafficGenerator(MultiInheritanceBaseClass, ABC):
23    """The base traffic generator.
24
25    Exposes the common public methods of all traffic generators and defines private methods
26    that must implement the traffic generation logic in subclasses. This class also extends from
27    :class:`framework.utils.MultiInheritanceBaseClass` to allow subclasses the ability to inherit
28    from multiple classes to fulfil the traffic generating functionality without breaking
29    single inheritance.
30    """
31
32    _config: TrafficGeneratorConfig
33    _tg_node: Node
34    _logger: DTSLogger
35
36    def __init__(self, tg_node: Node, config: TrafficGeneratorConfig, **kwargs):
37        """Initialize the traffic generator.
38
39        Additional keyword arguments can be passed through `kwargs` if needed for fulfilling other
40        constructors in the case of multiple inheritance.
41
42        Args:
43            tg_node: The traffic generator node where the created traffic generator will be running.
44            config: The traffic generator's test run configuration.
45        """
46        self._config = config
47        self._tg_node = tg_node
48        self._logger = get_dts_logger(f"{self._tg_node.name} {self._config.type}")
49        super().__init__(tg_node, **kwargs)
50
51    def send_packet(self, packet: Packet, port: Port) -> None:
52        """Send `packet` and block until it is fully sent.
53
54        Send `packet` on `port`, then wait until `packet` is fully sent.
55
56        Args:
57            packet: The packet to send.
58            port: The egress port on the TG node.
59        """
60        self.send_packets([packet], port)
61
62    def send_packets(self, packets: list[Packet], port: Port) -> None:
63        """Send `packets` and block until they are fully sent.
64
65        Send `packets` on `port`, then wait until `packets` are fully sent.
66
67        Args:
68            packets: The packets to send.
69            port: The egress port on the TG node.
70        """
71        self._logger.info(f"Sending packet{'s' if len(packets) > 1 else ''}.")
72        self._logger.debug(get_packet_summaries(packets))
73        self._send_packets(packets, port)
74
75    @abstractmethod
76    def _send_packets(self, packets: list[Packet], port: Port) -> None:
77        """The implementation of :method:`send_packets`.
78
79        The subclasses must implement this method which sends `packets` on `port`.
80        The method should block until all `packets` are fully sent.
81
82        What fully sent means is defined by the traffic generator.
83        """
84
85    @property
86    def is_capturing(self) -> bool:
87        """This traffic generator can't capture traffic."""
88        return False
89
90    @abstractmethod
91    def close(self) -> None:
92        """Free all resources used by the traffic generator."""
93