fix(core): Trex typo
[csit.git] / resources / libraries / python / TRexConfigGenerator.py
1 # Copyright (c) 2023 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """TRex Configuration File Generator library."""
15
16 import re
17 import yaml
18
19 from resources.libraries.python.Constants import Constants
20 from resources.libraries.python.CpuUtils import CpuUtils
21 from resources.libraries.python.ssh import exec_cmd_no_error
22 from resources.libraries.python.topology import NodeType, NodeSubTypeTG
23 from resources.libraries.python.topology import Topology
24
25
26 __all__ = ["TrexConfigGenerator", "TrexInitConfig"]
27
28 def pci_dev_check(pci_dev):
29     """Check if provided PCI address is in correct format.
30
31     :param pci_dev: PCI address (expected format: xxxx:xx:xx.x).
32     :type pci_dev: str
33     :returns: True if PCI address is in correct format.
34     :rtype: bool
35     :raises ValueError: If PCI address is in incorrect format.
36     """
37     pattern = re.compile(
38         r"^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}\.[0-9A-Fa-f]$"
39     )
40     if not re.match(pattern, pci_dev):
41         raise ValueError(
42             f"PCI address {pci_dev} is not in valid format xxxx:xx:xx.x"
43         )
44     return True
45
46
47 class TrexConfigGenerator:
48     """TRex Startup Configuration File Generator."""
49
50     def __init__(self):
51         """Initialize library.
52         """
53         self._node = ""
54         self._node_key = ""
55         self._node_config = dict()
56         self._node_serialized_config = ""
57         self._startup_configuration_path = "/etc/trex_cfg.yaml"
58
59     def set_node(self, node, node_key=None):
60         """Set topology node.
61
62         :param node: Node to store configuration on.
63         :param node_key: Topology node key.
64         :type node: dict
65         :type node_key: str
66         :raises RuntimeError: If Node type is not TG and subtype is not TREX.
67         """
68         if node.get("type") is None:
69             msg = "Node type is not defined!"
70         elif node["type"] != NodeType.TG:
71             msg = f"Node type is {node['type']!r}, not a TG!"
72         elif node.get("subtype") is None:
73             msg = "TG subtype is not defined"
74         elif node["subtype"] != NodeSubTypeTG.TREX:
75             msg = f"TG subtype {node['subtype']!r} is not supported"
76         else:
77             self._node = node
78             self._node_key = node_key
79             return
80         raise RuntimeError(msg)
81
82     def get_serialized_config(self):
83         """Get serialized startup configuration in YAML format.
84
85         :returns: Startup configuration in YAML format.
86         :rtype: str
87         """
88         self.serialize_config(self._node_config)
89         return self._node_serialized_config
90
91     def serialize_config(self, obj):
92         """Serialize the startup configuration in YAML format.
93
94         :param obj: Python Object to print.
95         :type obj: Obj
96         """
97         self._node_serialized_config = yaml.dump([obj], default_style=None)
98
99     def add_config_item(self, config, value, path):
100         """Add startup configuration item.
101
102         :param config: Startup configuration of node.
103         :param value: Value to insert.
104         :param path: Path where to insert item.
105         :type config: dict
106         :type value: str
107         :type path: list
108         """
109         if len(path) == 1:
110             config[path[0]] = value
111             return
112         if path[0] not in config:
113             config[path[0]] = dict()
114         elif isinstance(config[path[0]], str):
115             config[path[0]] = dict() if config[path[0]] == "" \
116                 else {config[path[0]]: ""}
117         self.add_config_item(config[path[0]], value, path[1:])
118
119     def add_version(self, value=2):
120         """Add config file version.
121
122         :param value: Version of configuration file.
123         :type value: int
124         """
125         path = ["version"]
126         self.add_config_item(self._node_config, value, path)
127
128     def add_c(self, value):
129         """Add core count.
130
131         :param value: Core count.
132         :type value: int
133         """
134         path = ["c"]
135         self.add_config_item(self._node_config, value, path)
136
137     def add_limit_memory(self, value):
138         """Add memory limit.
139
140         :param value: Memory limit.
141         :type value: str
142         """
143         path = ["limit_memory"]
144         self.add_config_item(self._node_config, value, path)
145
146     def add_interfaces(self, devices):
147         """Add PCI device configuration.
148
149         :param devices: PCI device(s) (format xxxx:xx:xx.x).
150         :type devices: list(str)
151         """
152         for device in devices:
153             pci_dev_check(device)
154
155         path = ["interfaces"]
156         self.add_config_item(self._node_config, devices, path)
157
158     def add_rx_desc(self, value):
159         """Add RX descriptors.
160
161         :param value: RX descriptors count.
162         :type value: int
163         """
164         path = ["rx_desc"]
165         self.add_config_item(self._node_config, value, path)
166
167     def add_tx_desc(self, value):
168         """Add TX descriptors.
169
170         :param value: TX descriptors count.
171         :type value: int
172         """
173         path = ["tx_desc"]
174         self.add_config_item(self._node_config, value, path)
175
176     def add_port_info(self, value):
177         """Add port information configuration.
178
179         :param value: Port information configuration.
180         :type value: list(dict)
181         """
182         path = ["port_info"]
183         self.add_config_item(self._node_config, value, path)
184
185     def add_platform_master_thread_id(self, value):
186         """Add platform master thread ID.
187
188         :param value: Master thread ID.
189         :type value: int
190         """
191         path = ["platform", "master_thread_id"]
192         self.add_config_item(self._node_config, value, path)
193
194     def add_platform_latency_thread_id(self, value):
195         """Add platform latency thread ID.
196
197         :param value: Latency thread ID.
198         :type value: int
199         """
200         path = ["platform", "latency_thread_id"]
201         self.add_config_item(self._node_config, value, path)
202
203     def add_platform_dual_if(self, value):
204         """Add platform dual interface configuration.
205
206         :param value: Dual interface configuration.
207         :type value: list(dict)
208         """
209         path = ["platform", "dual_if"]
210         self.add_config_item(self._node_config, value, path)
211
212     def write_config(self, path=None):
213         """Generate and write TRex startup configuration to file.
214
215         :param path: Override startup configuration path.
216         :type path: str
217         """
218         self.serialize_config(self._node_config)
219
220         if path is None:
221             path = self._startup_configuration_path
222
223         command = f"echo \"{self._node_serialized_config}\" | sudo tee {path}"
224         message = "Writing TRex startup configuration failed!"
225         exec_cmd_no_error(self._node, command, message=message)
226
227
228 class TrexInitConfig:
229     """TRex Initial Configuration.
230     """
231     @staticmethod
232     def init_trex_startup_configuration(node, tg_topology):
233         """Apply initial TRex startup configuration.
234
235         :param node: TRex node in the topology.
236         :param tg_topology: Ordered TRex links.
237         :type node: dict
238         :type tg_topology: list(dict)
239         """
240         pci_addresses = list()
241         dual_if = list()
242         port_info = list()
243         master_thread_id = None
244         latency_thread_id = None
245         cores = None
246         limit_memory = f"{Constants.TREX_LIMIT_MEMORY}"
247         sockets = list()
248
249         for link in tg_topology:
250             pci_addresses.append(
251                 Topology().get_interface_pci_addr(node, link["interface"])
252             )
253             master_thread_id, latency_thread_id, socket, threads = \
254                 CpuUtils.get_affinity_trex(
255                     node, link["interface"], tg_dtc=Constants.TREX_CORE_COUNT
256                 )
257             dual_if.append(dict(socket=socket, threads=threads))
258             cores = len(threads)
259             port_info.append(
260                 dict(
261                     src_mac=Topology().get_interface_mac(
262                         node, link["interface"]
263                     ),
264                     dest_mac=link["dst_mac"]
265                 )
266             )
267             sockets.append(socket)
268         if 0 in sockets and 1 in sockets:
269             limit_memory = (
270                 f"{Constants.TREX_LIMIT_MEMORY},{Constants.TREX_LIMIT_MEMORY}"
271             )
272
273         trex_config = TrexConfigGenerator()
274         trex_config.set_node(node)
275         trex_config.add_version()
276         trex_config.add_interfaces(pci_addresses)
277         trex_config.add_c(cores)
278         trex_config.add_limit_memory(limit_memory)
279         trex_config.add_port_info(port_info)
280         if Constants.TREX_RX_DESCRIPTORS_COUNT != 0:
281             trex_config.add_rx_desc(Constants.TREX_RX_DESCRIPTORS_COUNT)
282         if Constants.TREX_TX_DESCRIPTORS_COUNT != 0:
283             trex_config.add_rx_desc(Constants.TREX_TX_DESCRIPTORS_COUNT)
284         trex_config.add_platform_master_thread_id(int(master_thread_id))
285         trex_config.add_platform_latency_thread_id(int(latency_thread_id))
286         trex_config.add_platform_dual_if(dual_if)
287         trex_config.write_config()