blob: 711f1032d969943864d49a899c359fa83b61a83b [file] [log] [blame]
John DeNisco68b0ee32017-09-27 16:35:23 -04001# Copyright (c) 2016 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
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080014from __future__ import print_function
15
John DeNisco68b0ee32017-09-27 16:35:23 -040016"""VPP util library"""
17import logging
18import re
19import subprocess
jdenisco24010fb2018-11-13 12:40:12 -050020import requests
John DeNisco68b0ee32017-09-27 16:35:23 -040021
22from collections import Counter
23
Paul Vinciguerraef1ae3a2019-04-30 21:15:18 -070024import distro
25
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020026ubuntu_pkgs = {
27 "release": [
28 "vpp",
29 "vpp-plugin-core",
30 "vpp-plugin-dpdk",
31 "vpp-api-python",
32 "python3-vpp-api",
33 "vpp-dbg",
34 "vpp-dev",
35 "vpp-ext-deps",
36 ],
37 "master": [
38 "vpp",
39 "vpp-plugin-core",
40 "vpp-plugin-dpdk",
41 "vpp-api-python",
42 "python3-vpp-api",
43 "vpp-dbg",
44 "vpp-dev",
45 "vpp-ext-deps",
46 ],
47}
jdenisco2cefb062019-02-19 16:25:05 -050048
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020049centos_pkgs = {
50 "release": [
51 "vpp",
52 "vpp-selinux-policy",
53 "vpp-plugins",
54 "vpp-api-lua",
55 "vpp-api-python",
56 "vpp-debuginfo",
57 "vpp-devel",
58 "libvpp0",
59 "vpp-ext-deps",
60 ],
61 "master": [
62 "vpp",
63 "vpp-selinux-policy",
64 "vpp-plugins",
65 "vpp-api-lua",
66 "vpp-api-python",
67 "vpp-debuginfo",
68 "vpp-devel",
69 "libvpp0",
70 "vpp-ext-deps",
71 ],
72}
jdenisco2cefb062019-02-19 16:25:05 -050073
John DeNisco68b0ee32017-09-27 16:35:23 -040074
75class VPPUtil(object):
76 """General class for any VPP related methods/functions."""
77
78 @staticmethod
79 def exec_command(cmd, timeout=None):
80 """Execute a command on the local node.
81
82 :param cmd: Command to run locally.
83 :param timeout: Timeout value
84 :type cmd: str
85 :type timeout: int
86 :return return_code, stdout, stderr
87 :rtype: tuple(int, str, str)
88 """
89
90 logging.info(" Local Command: {}".format(cmd))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020091 out = ""
92 err = ""
93 prc = subprocess.Popen(
94 cmd,
95 shell=True,
96 bufsize=1,
97 stdin=subprocess.PIPE,
98 stdout=subprocess.PIPE,
99 stderr=subprocess.PIPE,
100 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400101
102 with prc.stdout:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800103 lines = prc.stdout.readlines()
104 for line in lines:
105 if type(line) != str:
106 line = line.decode()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200107 logging.info(" {}".format(line.strip("\n")))
John DeNisco68b0ee32017-09-27 16:35:23 -0400108 out += line
109
110 with prc.stderr:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800111 lines = prc.stderr.readlines()
112 for line in lines:
113 if type(line) != str:
114 line = line.decode()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200115 logging.warning(" {}".format(line.strip("\n")))
John DeNisco68b0ee32017-09-27 16:35:23 -0400116 err += line
117
118 ret = prc.wait()
119
120 return ret, out, err
121
122 def _autoconfig_backup_file(self, filename):
123 """
124 Create a backup file.
125
126 :param filename: The file to backup
127 :type filename: str
128 """
129
130 # Does a copy of the file exist, if not create one
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200131 ofile = filename + ".orig"
132 (ret, stdout, stderr) = self.exec_command("ls {}".format(ofile))
John DeNisco68b0ee32017-09-27 16:35:23 -0400133 if ret != 0:
134 logging.debug(stderr)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200135 if stdout.strip("\n") != ofile:
136 cmd = "sudo cp {} {}".format(filename, ofile)
John DeNisco68b0ee32017-09-27 16:35:23 -0400137 (ret, stdout, stderr) = self.exec_command(cmd)
138 if ret != 0:
139 logging.debug(stderr)
140
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200141 def _install_vpp_ubuntu(self, node, branch, ubuntu_version="xenial"):
John DeNisco68b0ee32017-09-27 16:35:23 -0400142 """
143 Install the VPP packages
144
145 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500146 :param branch: VPP branch
John DeNisco68b0ee32017-09-27 16:35:23 -0400147 :param ubuntu_version: Ubuntu Version
148 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500149 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400150 :type ubuntu_version: string
151 """
152
153 # Modify the sources list
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200154 sfile = "/etc/apt/sources.list.d/99fd.io.list"
John DeNisco68b0ee32017-09-27 16:35:23 -0400155
156 # Backup the sources list
157 self._autoconfig_backup_file(sfile)
158
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200159 reps = "deb [trusted=yes] https://packagecloud.io/fdio/"
160 reps += "{}/ubuntu {} main\n".format(branch, ubuntu_version)
John DeNisco68b0ee32017-09-27 16:35:23 -0400161
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200162 with open(sfile, "w") as sfd:
jdenisco24010fb2018-11-13 12:40:12 -0500163 sfd.write(reps)
164 sfd.close()
165
166 # Add the key
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800167
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200168 key = requests.get("https://packagecloud.io/fdio/{}/gpgkey".format(branch))
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800169 cmd = 'echo "{}" | apt-key add -'.format(key.content.decode(key.encoding))
John DeNisco68b0ee32017-09-27 16:35:23 -0400170 (ret, stdout, stderr) = self.exec_command(cmd)
171 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200172 raise RuntimeError(
173 "{} failed on node {} {}".format(cmd, node["host"], stderr)
174 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400175
176 # Install the package
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200177 cmd = "apt-get -y update"
John DeNisco68b0ee32017-09-27 16:35:23 -0400178 (ret, stdout, stderr) = self.exec_command(cmd)
179 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200180 raise RuntimeError(
181 "{} apt-get update failed on node {} {}".format(
182 cmd, node["host"], stderr
183 )
184 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400185
jdenisco2cefb062019-02-19 16:25:05 -0500186 # Get the package list
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200187 pkgstr = ""
jdenisco2cefb062019-02-19 16:25:05 -0500188 for ps in ubuntu_pkgs[branch]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200189 pkgstr += ps + " "
jdenisco2cefb062019-02-19 16:25:05 -0500190
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200191 cmd = "apt-get -y install {}".format(pkgstr)
jdenisco2cefb062019-02-19 16:25:05 -0500192 (ret, stdout, stderr) = self.exec_command(cmd)
193 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200194 raise RuntimeError(
195 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
196 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400197
jdeniscob0b9dad2018-12-18 15:29:45 -0500198 def _install_vpp_centos(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400199 """
200 Install the VPP packages
201
202 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500203 :param branch: The branch name release or master
John DeNisco68b0ee32017-09-27 16:35:23 -0400204 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500205 :type branch: string
John DeNisco68b0ee32017-09-27 16:35:23 -0400206 """
207
jdenisco24010fb2018-11-13 12:40:12 -0500208 # Be sure the correct system packages are installed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200209 cmd = "yum -y update"
jdenisco24010fb2018-11-13 12:40:12 -0500210 (ret, stdout, stderr) = self.exec_command(cmd)
211 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200212 logging.debug("{} failed on node {} {}".format(cmd, node["host"], stderr))
jdenisco24010fb2018-11-13 12:40:12 -0500213
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 cmd = "yum -y install pygpgme yum-utils"
jdenisco24010fb2018-11-13 12:40:12 -0500215 (ret, stdout, stderr) = self.exec_command(cmd)
216 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200217 logging.debug("{} failed on node {} {}".format(cmd, node["host"], stderr))
jdenisco24010fb2018-11-13 12:40:12 -0500218
John DeNisco68b0ee32017-09-27 16:35:23 -0400219 # Modify the sources list
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200220 sfile = "/etc/yum.repos.d/fdio-release.repo"
John DeNisco68b0ee32017-09-27 16:35:23 -0400221
222 # Backup the sources list
223 self._autoconfig_backup_file(sfile)
224
225 # Remove the current file
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200226 cmd = "rm {}".format(sfile)
John DeNisco68b0ee32017-09-27 16:35:23 -0400227 (ret, stdout, stderr) = self.exec_command(cmd)
228 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200229 logging.debug("{} failed on node {} {}".format(cmd, node["host"], stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400230
jdenisco24010fb2018-11-13 12:40:12 -0500231 # Get the file contents
jdenisco24010fb2018-11-13 12:40:12 -0500232
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200233 reps = "\n".join(
234 [
235 "[fdio_{}]".format(branch),
236 "name=fdio_{}".format(branch),
237 "baseurl=https://packagecloud.io/fdio/{}/el/7/$basearch".format(branch),
238 "repo_gpgcheck=1",
239 "gpgcheck=0",
240 "enabled=1",
241 "gpgkey=https://packagecloud.io/fdio/{}/gpgkey".format(branch),
242 "sslverify=1",
243 "sslcacert=/etc/pki/tls/certs/ca-bundle.crt",
244 "metadata_expire=300\n",
245 "[fdio_{}-source]".format(branch),
246 "name=fdio_release-{}".format(branch),
247 "baseurl=https://packagecloud.io/fdio/{}/el/7/SRPMS".format(branch),
248 "repo_gpgcheck=1",
249 "gpgcheck=0",
250 "enabled=1",
251 "gpgkey=https://packagecloud.io/fdio/{}/gpgkey".format(branch),
252 "sslverify =1",
253 "sslcacert=/etc/pki/tls/certs/ca-bundle.crt",
254 "metadata_expire=300\n",
255 ]
256 )
257 with open(sfile, "w") as sfd:
jdenisco24010fb2018-11-13 12:40:12 -0500258 sfd.write(reps)
259 sfd.close()
260
261 # Update the fdio repo
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200262 cmd = "yum clean all"
John DeNisco68b0ee32017-09-27 16:35:23 -0400263 (ret, stdout, stderr) = self.exec_command(cmd)
264 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200265 logging.debug("{} failed on node {} {}".format(cmd, node["host"], stderr))
jdenisco24010fb2018-11-13 12:40:12 -0500266
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200267 cmd = "yum -q makecache -y --disablerepo='*' " "--enablerepo='fdio_{}'".format(
268 branch
269 )
jdenisco24010fb2018-11-13 12:40:12 -0500270 (ret, stdout, stderr) = self.exec_command(cmd)
271 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200272 logging.debug("{} failed on node {} {}".format(cmd, node["host"], stderr))
John DeNisco68b0ee32017-09-27 16:35:23 -0400273
jdenisco2cefb062019-02-19 16:25:05 -0500274 # Get the package list
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200275 pkgstr = ""
jdenisco2cefb062019-02-19 16:25:05 -0500276 for ps in centos_pkgs[branch]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200277 pkgstr += ps + " "
jdenisco2cefb062019-02-19 16:25:05 -0500278
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200279 cmd = "yum -y install {}".format(pkgstr)
jdenisco2cefb062019-02-19 16:25:05 -0500280 (ret, stdout, stderr) = self.exec_command(cmd)
281 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200282 raise RuntimeError(
283 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
284 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400285
jdeniscob0b9dad2018-12-18 15:29:45 -0500286 def install_vpp(self, node, branch):
John DeNisco68b0ee32017-09-27 16:35:23 -0400287 """
288 Install the VPP packages
289
290 :param node: Node dictionary with cpuinfo.
jdeniscob0b9dad2018-12-18 15:29:45 -0500291 :param branch: The branch name
John DeNisco68b0ee32017-09-27 16:35:23 -0400292 :type node: dict
jdeniscob0b9dad2018-12-18 15:29:45 -0500293 :type branch: string
294
John DeNisco68b0ee32017-09-27 16:35:23 -0400295 """
296 distro = self.get_linux_distro()
John DeNisco4dc83972018-03-30 10:50:19 -0400297 logging.info(" {}".format(distro[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200298 if distro[0] == "Ubuntu":
John DeNisco4dc83972018-03-30 10:50:19 -0400299 logging.info("Install Ubuntu")
jdeniscob0b9dad2018-12-18 15:29:45 -0500300 self._install_vpp_ubuntu(node, branch, ubuntu_version=distro[2])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200301 elif distro[0] == "CentOS Linux":
John DeNisco68b0ee32017-09-27 16:35:23 -0400302 logging.info("Install CentOS")
jdeniscob0b9dad2018-12-18 15:29:45 -0500303 self._install_vpp_centos(node, branch)
John DeNisco68b0ee32017-09-27 16:35:23 -0400304 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400305 logging.info("Install CentOS (default)")
jdeniscob0b9dad2018-12-18 15:29:45 -0500306 self._install_vpp_centos(node, branch)
John DeNisco4dc83972018-03-30 10:50:19 -0400307 return
John DeNisco68b0ee32017-09-27 16:35:23 -0400308
John DeNisco68b0ee32017-09-27 16:35:23 -0400309 def _uninstall_vpp_ubuntu(self, node):
310 """
311 Uninstall the VPP packages
312
313 :param node: Node dictionary with cpuinfo.
314 :type node: dict
315 """
John DeNisco68b0ee32017-09-27 16:35:23 -0400316
jdenisco2cefb062019-02-19 16:25:05 -0500317 # get the package list
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200318 pkgstr = ""
jdenisco2cefb062019-02-19 16:25:05 -0500319 pkgs = self.get_installed_vpp_pkgs()
320 for pkg in pkgs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200321 pkgname = pkg["name"]
322 pkgstr += pkgname + " "
jdenisco2cefb062019-02-19 16:25:05 -0500323
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200324 cmd = "dpkg --purge {}".format(pkgstr)
jdenisco2cefb062019-02-19 16:25:05 -0500325 (ret, stdout, stderr) = self.exec_command(cmd)
326 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200327 raise RuntimeError(
328 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
329 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400330
331 def _uninstall_vpp_centos(self, node):
332 """
333 Uninstall the VPP packages
334
335 :param node: Node dictionary with cpuinfo.
336 :type node: dict
jdenisco2cefb062019-02-19 16:25:05 -0500337 """
John DeNisco68b0ee32017-09-27 16:35:23 -0400338
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200339 pkgstr = ""
John DeNisco68b0ee32017-09-27 16:35:23 -0400340 pkgs = self.get_installed_vpp_pkgs()
jdenisco2cefb062019-02-19 16:25:05 -0500341 for pkg in pkgs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200342 pkgname = pkg["name"]
343 pkgstr += pkgname + " "
John DeNisco68b0ee32017-09-27 16:35:23 -0400344
jdenisco2cefb062019-02-19 16:25:05 -0500345 logging.info("Uninstalling {}".format(pkgstr))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200346 cmd = "yum -y remove {}".format(pkgstr)
jdenisco2cefb062019-02-19 16:25:05 -0500347 (ret, stdout, stderr) = self.exec_command(cmd)
348 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200349 raise RuntimeError(
350 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
351 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400352
353 def uninstall_vpp(self, node):
354 """
355 Uninstall the VPP packages
356
357 :param node: Node dictionary with cpuinfo.
358 :type node: dict
359 """
John DeNiscoc6b2a202017-11-01 12:37:47 -0400360
361 # First stop VPP
362 self.stop(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400363 distro = self.get_linux_distro()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200364 if distro[0] == "Ubuntu":
John DeNisco4dc83972018-03-30 10:50:19 -0400365 logging.info("Uninstall Ubuntu")
John DeNisco68b0ee32017-09-27 16:35:23 -0400366 self._uninstall_vpp_ubuntu(node)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200367 elif distro[0] == "CentOS Linux":
John DeNisco68b0ee32017-09-27 16:35:23 -0400368 logging.info("Uninstall CentOS")
369 self._uninstall_vpp_centos(node)
370 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400371 logging.info("Uninstall CentOS (Default)")
372 self._uninstall_vpp_centos(node)
John DeNisco68b0ee32017-09-27 16:35:23 -0400373 return
374
375 def show_vpp_settings(self, *additional_cmds):
376 """
377 Print default VPP settings. In case others are needed, can be
378 accepted as next parameters (each setting one parameter), preferably
379 in form of a string.
380
381 :param additional_cmds: Additional commands that the vpp should print
382 settings for.
383 :type additional_cmds: tuple
384 """
385 def_setting_tb_displayed = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200386 "IPv6 FIB": "ip6 fib",
387 "IPv4 FIB": "ip fib",
388 "Interface IP": "int addr",
389 "Interfaces": "int",
390 "ARP": "ip arp",
391 "Errors": "err",
John DeNisco68b0ee32017-09-27 16:35:23 -0400392 }
393
394 if additional_cmds:
395 for cmd in additional_cmds:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200396 def_setting_tb_displayed["Custom Setting: {}".format(cmd)] = cmd
John DeNisco68b0ee32017-09-27 16:35:23 -0400397
398 for _, value in def_setting_tb_displayed.items():
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200399 self.exec_command("vppctl sh {}".format(value))
John DeNisco68b0ee32017-09-27 16:35:23 -0400400
401 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400402 def get_vms(node):
403 """
404 Get a list of VMs that are connected to VPP interfaces
405
406 :param node: VPP node.
407 :type node: dict
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800408 :returns: Dictionary containing a list of VMs and the interfaces
409 that are connected to VPP
John DeNiscoc6b2a202017-11-01 12:37:47 -0400410 :rtype: dictionary
411 """
412
413 vmdict = {}
414
jdenisco2cefb062019-02-19 16:25:05 -0500415 print("Need to implement get vms")
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800416
John DeNiscoc6b2a202017-11-01 12:37:47 -0400417 return vmdict
418
419 @staticmethod
John DeNiscoa3db0782017-10-17 11:07:22 -0400420 def get_int_ip(node):
421 """
422 Get the VPP interfaces and IP addresses
423
424 :param node: VPP node.
425 :type node: dict
426 :returns: Dictionary containing VPP interfaces and IP addresses
427 :rtype: dictionary
428 """
429 interfaces = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200430 cmd = "vppctl show int addr"
John DeNiscoa3db0782017-10-17 11:07:22 -0400431 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
432 if ret != 0:
433 return interfaces
434
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200435 lines = stdout.split("\n")
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700436 if len(lines[0]) != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200437 if lines[0].split(" ")[0] == "FileNotFoundError":
John DeNiscoa3db0782017-10-17 11:07:22 -0400438 return interfaces
439
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200440 name = ""
John DeNiscoa3db0782017-10-17 11:07:22 -0400441 for line in lines:
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700442 if len(line) == 0:
John DeNiscoa3db0782017-10-17 11:07:22 -0400443 continue
444
445 # If the first character is not whitespace
446 # create a new interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200447 if len(re.findall(r"\s", line[0])) == 0:
John DeNiscoa3db0782017-10-17 11:07:22 -0400448 spl = line.split()
449 name = spl[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200450 if name == "local0":
John DeNiscoa3db0782017-10-17 11:07:22 -0400451 continue
452 interfaces[name] = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200453 interfaces[name]["state"] = spl[1].lstrip("(").rstrip("):\r")
John DeNiscoa3db0782017-10-17 11:07:22 -0400454 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200455 interfaces[name]["address"] = line.lstrip(" ").rstrip("\r")
John DeNiscoa3db0782017-10-17 11:07:22 -0400456
457 return interfaces
458
459 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400460 def get_hardware(node):
461 """
462 Get the VPP hardware information and return it in a
463 dictionary
464
465 :param node: VPP node.
466 :type node: dict
John DeNiscoa3db0782017-10-17 11:07:22 -0400467 :returns: Dictionary containing VPP hardware information
John DeNisco68b0ee32017-09-27 16:35:23 -0400468 :rtype: dictionary
469 """
470
471 interfaces = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200472 cmd = "vppctl show hard"
John DeNisco68b0ee32017-09-27 16:35:23 -0400473 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
474 if ret != 0:
475 return interfaces
476
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200477 lines = stdout.split("\n")
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700478 if len(lines[0]) != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200479 if lines[0].split(" ")[0] == "FileNotFoundError":
John DeNisco68b0ee32017-09-27 16:35:23 -0400480 return interfaces
481
482 for line in lines:
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700483 if len(line) == 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400484 continue
485
486 # If the first character is not whitespace
487 # create a new interface
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200488 if len(re.findall(r"\s", line[0])) == 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400489 spl = line.split()
490 name = spl[0]
491 interfaces[name] = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200492 interfaces[name]["index"] = spl[1]
493 interfaces[name]["state"] = spl[2]
John DeNisco68b0ee32017-09-27 16:35:23 -0400494
495 # Ethernet address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200496 rfall = re.findall(r"Ethernet address", line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400497 if rfall:
498 spl = line.split()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200499 interfaces[name]["mac"] = spl[2]
John DeNisco68b0ee32017-09-27 16:35:23 -0400500
501 # Carrier
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200502 rfall = re.findall(r"carrier", line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400503 if rfall:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200504 spl = line.split("carrier ")
505 interfaces[name]["carrier"] = spl[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400506
507 # Socket
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200508 spl = ""
509 rfall = re.findall(r"numa \d+", line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400510 if rfall:
jdenisco7c37a672018-11-20 11:25:17 -0500511 spl = rfall[0].split()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200512 interfaces[name]["numa"] = rfall[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400513
514 # Queues and Descriptors
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200515 rfall = re.findall(r"rx\: queues \d+", line)
John DeNisco68b0ee32017-09-27 16:35:23 -0400516 if rfall:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200517 interfaces[name]["rx queues"] = rfall[0].split()[2]
518 rdesc = re.findall(r"desc \d+", line)
jdenisco7c37a672018-11-20 11:25:17 -0500519 if rdesc:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200520 interfaces[name]["rx descs"] = rdesc[0].split()[1]
jdenisco7c37a672018-11-20 11:25:17 -0500521
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200522 rfall = re.findall(r"tx\: queues \d+", line)
jdenisco7c37a672018-11-20 11:25:17 -0500523 if rfall:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200524 interfaces[name]["tx queues"] = rfall[0].split()[2]
525 rdesc = re.findall(r"desc \d+", line)
jdenisco7c37a672018-11-20 11:25:17 -0500526 if rdesc:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200527 interfaces[name]["tx descs"] = rdesc[0].split()[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400528
529 return interfaces
530
jdenisco2cefb062019-02-19 16:25:05 -0500531 def _get_installed_vpp_pkgs_ubuntu(self):
John DeNisco68b0ee32017-09-27 16:35:23 -0400532 """
533 Get the VPP hardware information and return it in a
534 dictionary
535
536 :returns: List of the packages installed
537 :rtype: list
538 """
539
540 pkgs = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200541 cmd = "dpkg -l | grep vpp"
John DeNisco68b0ee32017-09-27 16:35:23 -0400542 (ret, stdout, stderr) = self.exec_command(cmd)
543 if ret != 0:
544 return pkgs
545
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200546 lines = stdout.split("\n")
John DeNisco68b0ee32017-09-27 16:35:23 -0400547 for line in lines:
548 items = line.split()
549 if len(items) < 2:
550 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200551 pkg = {"name": items[1], "version": items[2]}
John DeNisco68b0ee32017-09-27 16:35:23 -0400552 pkgs.append(pkg)
553
554 return pkgs
555
556 def _get_installed_vpp_pkgs_centos(self):
557 """
558 Get the VPP hardware information and return it in a
559 dictionary
560
561 :returns: List of the packages installed
562 :rtype: list
563 """
564
565 pkgs = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200566 cmd = "rpm -qa | grep vpp"
John DeNisco68b0ee32017-09-27 16:35:23 -0400567 (ret, stdout, stderr) = self.exec_command(cmd)
568 if ret != 0:
569 return pkgs
570
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200571 lines = stdout.split("\n")
John DeNisco68b0ee32017-09-27 16:35:23 -0400572 for line in lines:
573 if len(line) == 0:
574 continue
575
576 items = line.split()
577 if len(items) < 2:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200578 pkg = {"name": items[0]}
John DeNisco68b0ee32017-09-27 16:35:23 -0400579 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200580 pkg = {"name": items[1], "version": items[2]}
John DeNisco68b0ee32017-09-27 16:35:23 -0400581
582 pkgs.append(pkg)
583
584 return pkgs
585
586 def get_installed_vpp_pkgs(self):
587 """
588 Get the VPP hardware information and return it in a
589 dictionary
590
591 :returns: List of the packages installed
592 :rtype: list
593 """
594
595 distro = self.get_linux_distro()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200596 if distro[0] == "Ubuntu":
jdenisco2cefb062019-02-19 16:25:05 -0500597 pkgs = self._get_installed_vpp_pkgs_ubuntu()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200598 elif distro[0] == "CentOS Linux":
John DeNisco68b0ee32017-09-27 16:35:23 -0400599 pkgs = self._get_installed_vpp_pkgs_centos()
600 else:
John DeNisco4dc83972018-03-30 10:50:19 -0400601 pkgs = self._get_installed_vpp_pkgs_centos()
John DeNisco68b0ee32017-09-27 16:35:23 -0400602 return []
603
604 return pkgs
605
606 @staticmethod
607 def get_interfaces_numa_node(node, *iface_keys):
608 """Get numa node on which are located most of the interfaces.
609
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800610 Return numa node with highest count of interfaces provided as
611 arguments.
612 Return 0 if the interface does not have numa_node information
613 available.
John DeNisco68b0ee32017-09-27 16:35:23 -0400614 If all interfaces have unknown location (-1), then return 0.
615 If most of interfaces have unknown location (-1), but there are
616 some interfaces with known location, then return the second most
617 location of the provided interfaces.
618
619 :param node: Node from DICT__nodes.
620 :param iface_keys: Interface keys for lookup.
621 :type node: dict
622 :type iface_keys: strings
623 """
624 numa_list = []
625 for if_key in iface_keys:
626 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200627 numa_list.append(node["interfaces"][if_key].get("numa_node"))
John DeNisco68b0ee32017-09-27 16:35:23 -0400628 except KeyError:
629 pass
630
631 numa_cnt_mc = Counter(numa_list).most_common()
632 numa_cnt_mc_len = len(numa_cnt_mc)
633 if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
634 return numa_cnt_mc[0][0]
635 elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
636 return numa_cnt_mc[1][0]
637
638 return 0
639
640 @staticmethod
John DeNiscoc6b2a202017-11-01 12:37:47 -0400641 def restart(node):
642 """
643
644 Starts vpp for a given node
645
646 :param node: VPP node.
647 :type node: dict
648 """
649
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200650 cmd = "service vpp restart"
John DeNiscoc6b2a202017-11-01 12:37:47 -0400651 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
652 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 raise RuntimeError(
654 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
655 )
John DeNiscoc6b2a202017-11-01 12:37:47 -0400656
657 @staticmethod
John DeNisco68b0ee32017-09-27 16:35:23 -0400658 def start(node):
659 """
660
661 Starts vpp for a given node
662
663 :param node: VPP node.
664 :type node: dict
665 """
666
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200667 cmd = "service vpp start"
John DeNisco68b0ee32017-09-27 16:35:23 -0400668 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
669 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200670 raise RuntimeError(
671 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
672 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400673
674 @staticmethod
675 def stop(node):
676 """
677
678 Stops vpp for a given node
679
680 :param node: VPP node.
681 :type node: dict
682 """
683
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200684 cmd = "service vpp stop"
John DeNisco68b0ee32017-09-27 16:35:23 -0400685 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
686 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200687 logging.debug(
688 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
689 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400690
John DeNiscoa7da67f2018-01-26 14:55:33 -0500691 # noinspection RegExpRedundantEscape
John DeNisco68b0ee32017-09-27 16:35:23 -0400692 @staticmethod
693 def status(node):
694 """
695
696 Gets VPP status
697
698 :param: node
699 :type node: dict
700 :returns: status, errors
701 :rtype: tuple(str, list)
702 """
703 errors = []
704 vutil = VPPUtil()
705 pkgs = vutil.get_installed_vpp_pkgs()
706 if len(pkgs) == 0:
707 return "Not Installed", errors
708
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200709 cmd = "service vpp status"
John DeNisco68b0ee32017-09-27 16:35:23 -0400710 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
711
712 # Get the active status
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200713 state = re.findall(r"Active:[\w (\)]+", stdout)[0].split(" ")
John DeNisco68b0ee32017-09-27 16:35:23 -0400714 if len(state) > 2:
715 statestr = "{} {}".format(state[1], state[2])
716 else:
717 statestr = "Invalid"
718
719 # For now we won't look for DPDK errors
720 # lines = stdout.split('\n')
721 # for line in lines:
722 # if 'EAL' in line or \
723 # 'FAILURE' in line or \
724 # 'failed' in line or \
725 # 'Failed' in line:
726 # errors.append(line.lstrip(' '))
727
728 return statestr, errors
729
730 @staticmethod
731 def get_linux_distro():
732 """
733 Get the linux distribution and check if it is supported
734
735 :returns: linux distro, None if the distro is not supported
736 :rtype: list
737 """
738
Paul Vinciguerraef1ae3a2019-04-30 21:15:18 -0700739 dist = distro.linux_distribution()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200740 if dist[0] == "Ubuntu" or dist[0] == "CentOS Linux" or dist[:7] == "Red Hat":
Paul Vinciguerraef1ae3a2019-04-30 21:15:18 -0700741 return dist
John DeNisco68b0ee32017-09-27 16:35:23 -0400742 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200743 raise RuntimeError("Linux Distribution {} is not supported".format(dist[0]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400744
745 @staticmethod
746 def version():
747 """
748
749 Gets VPP Version information
750
751 :returns: version
752 :rtype: dict
753 """
754
755 version = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200756 cmd = "vppctl show version verbose"
John DeNisco68b0ee32017-09-27 16:35:23 -0400757 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
758 if ret != 0:
759 return version
760
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200761 lines = stdout.split("\n")
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700762 if len(lines[0]) != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200763 if lines[0].split(" ")[0] == "FileNotFoundError":
John DeNisco68b0ee32017-09-27 16:35:23 -0400764 return version
765
766 for line in lines:
Paul Vinciguerrab11c2882019-04-30 20:57:04 -0700767 if len(line) == 0:
John DeNisco68b0ee32017-09-27 16:35:23 -0400768 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200769 dct = line.split(":")
770 version[dct[0]] = dct[1].lstrip(" ")
John DeNisco68b0ee32017-09-27 16:35:23 -0400771
772 return version
John DeNiscoc6b2a202017-11-01 12:37:47 -0400773
774 @staticmethod
775 def show_bridge(node):
776 """
777 Shows the current bridge configuration
778
779 :param node: VPP node.
780 :type node: dict
John DeNisco9fa5cf42018-02-06 15:23:05 -0500781 :returns: A list of interfaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400782 """
783
John DeNisco9fa5cf42018-02-06 15:23:05 -0500784 ifaces = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200785 cmd = "vppctl show bridge"
John DeNiscoc6b2a202017-11-01 12:37:47 -0400786 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
787 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200788 raise RuntimeError(
789 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
790 )
791 lines = stdout.split("\r\n")
John DeNiscoc6b2a202017-11-01 12:37:47 -0400792 bridges = []
793 for line in lines:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200794 if line == "no bridge-domains in use":
jdenisco2cefb062019-02-19 16:25:05 -0500795 print(line)
John DeNisco9fa5cf42018-02-06 15:23:05 -0500796 return ifaces
John DeNiscoc6b2a202017-11-01 12:37:47 -0400797 if len(line) == 0:
798 continue
799
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200800 lspl = line.lstrip(" ").split()
801 if lspl[0] != "BD-ID":
John DeNiscoc6b2a202017-11-01 12:37:47 -0400802 bridges.append(lspl[0])
803
804 for bridge in bridges:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200805 cmd = "vppctl show bridge {} detail".format(bridge)
John DeNiscoc6b2a202017-11-01 12:37:47 -0400806 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
807 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200808 raise RuntimeError(
809 "{} failed on node {} {} {}".format(
810 cmd, node["host"], stdout, stderr
811 )
812 )
John DeNisco9fa5cf42018-02-06 15:23:05 -0500813
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200814 lines = stdout.split("\r\n")
John DeNisco9fa5cf42018-02-06 15:23:05 -0500815 for line in lines:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200816 iface = re.findall(r"[a-zA-z]+\d+/\d+/\d+", line)
John DeNisco9fa5cf42018-02-06 15:23:05 -0500817 if len(iface):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200818 ifcidx = {"name": iface[0], "index": line.split()[1]}
John DeNisco9fa5cf42018-02-06 15:23:05 -0500819 ifaces.append(ifcidx)
820
jdenisco2cefb062019-02-19 16:25:05 -0500821 print(stdout)
John DeNisco4dc83972018-03-30 10:50:19 -0400822 return ifaces