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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """TRex Configuration File Generator library."""
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
26 __all__ = ["TrexConfigGenerator", "TrexInitConfig"]
28 def pci_dev_check(pci_dev):
29 """Check if provided PCI address is in correct format.
31 :param pci_dev: PCI address (expected format: xxxx:xx:xx.x).
33 :returns: True if PCI address is in correct format.
35 :raises ValueError: If PCI address is in incorrect format.
38 r"^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}\.[0-9A-Fa-f]$"
40 if not re.match(pattern, pci_dev):
42 f"PCI address {pci_dev} is not in valid format xxxx:xx:xx.x"
47 class TrexConfigGenerator:
48 """TRex Startup Configuration File Generator."""
51 """Initialize library.
55 self._node_config = dict()
56 self._node_serialized_config = ""
57 self._startup_configuration_path = "/etc/trex_cfg.yaml"
59 def set_node(self, node, node_key=None):
62 :param node: Node to store configuration on.
63 :param node_key: Topology node key.
66 :raises RuntimeError: If Node type is not TG and subtype is not TREX.
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"
78 self._node_key = node_key
80 raise RuntimeError(msg)
82 def get_serialized_config(self):
83 """Get serialized startup configuration in YAML format.
85 :returns: Startup configuration in YAML format.
88 self.serialize_config(self._node_config)
89 return self._node_serialized_config
91 def serialize_config(self, obj):
92 """Serialize the startup configuration in YAML format.
94 :param obj: Python Object to print.
97 self._node_serialized_config = yaml.dump([obj], default_style=None)
99 def add_config_item(self, config, value, path):
100 """Add startup configuration item.
102 :param config: Startup configuration of node.
103 :param value: Value to insert.
104 :param path: Path where to insert item.
110 config[path[0]] = value
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:])
119 def add_version(self, value=2):
120 """Add config file version.
122 :param value: Version of configuration file.
126 self.add_config_item(self._node_config, value, path)
128 def add_c(self, value):
131 :param value: Core count.
135 self.add_config_item(self._node_config, value, path)
137 def add_limit_memory(self, value):
140 :param value: Memory limit.
143 path = ["limit_memory"]
144 self.add_config_item(self._node_config, value, path)
146 def add_interfaces(self, devices):
147 """Add PCI device configuration.
149 :param devices: PCI device(s) (format xxxx:xx:xx.x).
150 :type devices: list(str)
152 for device in devices:
153 pci_dev_check(device)
155 path = ["interfaces"]
156 self.add_config_item(self._node_config, devices, path)
158 def add_rx_desc(self, value):
159 """Add RX descriptors.
161 :param value: RX descriptors count.
165 self.add_config_item(self._node_config, value, path)
167 def add_tx_desc(self, value):
168 """Add TX descriptors.
170 :param value: TX descriptors count.
174 self.add_config_item(self._node_config, value, path)
176 def add_port_info(self, value):
177 """Add port information configuration.
179 :param value: Port information configuration.
180 :type value: list(dict)
183 self.add_config_item(self._node_config, value, path)
185 def add_platform_master_thread_id(self, value):
186 """Add platform master thread ID.
188 :param value: Master thread ID.
191 path = ["platform", "master_thread_id"]
192 self.add_config_item(self._node_config, value, path)
194 def add_platform_latency_thread_id(self, value):
195 """Add platform latency thread ID.
197 :param value: Latency thread ID.
200 path = ["platform", "latency_thread_id"]
201 self.add_config_item(self._node_config, value, path)
203 def add_platform_dual_if(self, value):
204 """Add platform dual interface configuration.
206 :param value: Dual interface configuration.
207 :type value: list(dict)
209 path = ["platform", "dual_if"]
210 self.add_config_item(self._node_config, value, path)
212 def write_config(self, path=None):
213 """Generate and write TRex startup configuration to file.
215 :param path: Override startup configuration path.
218 self.serialize_config(self._node_config)
221 path = self._startup_configuration_path
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)
228 class TrexInitConfig:
229 """TRex Initial Configuration.
232 def init_trex_startup_configuration(node, tg_topology):
233 """Apply initial TRex startup configuration.
235 :param node: TRex node in the topology.
236 :param tg_topology: Ordered TRex links.
238 :type tg_topology: list(dict)
240 pci_addresses = list()
243 master_thread_id = None
244 latency_thread_id = None
246 limit_memory = f"{Constants.TREX_LIMIT_MEMORY}"
249 for link in tg_topology:
250 pci_addresses.append(
251 Topology().get_interface_pci_addr(node, link["interface"])
253 master_thread_id, latency_thread_id, socket, threads = \
254 CpuUtils.get_affinity_trex(
255 node, link["interface"], tg_dtc=Constants.TREX_CORE_COUNT
257 dual_if.append(dict(socket=socket, threads=threads))
261 src_mac=Topology().get_interface_mac(
262 node, link["interface"]
264 dest_mac=link["dst_mac"]
267 sockets.append(socket)
268 if 0 in sockets and 1 in sockets:
270 f"{Constants.TREX_LIMIT_MEMORY},{Constants.TREX_LIMIT_MEMORY}"
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()