Fix minor issues.
[vpp.git] / extras / vpp_config / vpplib / VPPUtil.py
1 # 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
14 """VPP util library"""
15 import logging
16 import re
17 import subprocess
18 import platform
19
20 from collections import Counter
21
22 # VPP_VERSION = '1707'
23 # VPP_VERSION = '1710'
24 VPP_VERSION = '1801'
25
26
27 class VPPUtil(object):
28     """General class for any VPP related methods/functions."""
29
30     @staticmethod
31     def exec_command(cmd, timeout=None):
32         """Execute a command on the local node.
33
34         :param cmd: Command to run locally.
35         :param timeout: Timeout value
36         :type cmd: str
37         :type timeout: int
38         :return return_code, stdout, stderr
39         :rtype: tuple(int, str, str)
40         """
41
42         logging.info(" Local Command: {}".format(cmd))
43         out = ''
44         err = ''
45         prc = subprocess.Popen(cmd, shell=True, bufsize=1,
46                                stdin=subprocess.PIPE,
47                                stdout=subprocess.PIPE,
48                                stderr=subprocess.PIPE)
49
50         with prc.stdout:
51             for line in iter(prc.stdout.readline, b''):
52                 logging.info("  {}".format(line.strip('\n')))
53                 out += line
54
55         with prc.stderr:
56             for line in iter(prc.stderr.readline, b''):
57                 logging.warn("  {}".format(line.strip('\n')))
58                 err += line
59
60         ret = prc.wait()
61
62         return ret, out, err
63
64     def _autoconfig_backup_file(self, filename):
65         """
66         Create a backup file.
67
68         :param filename: The file to backup
69         :type filename: str
70         """
71
72         # Does a copy of the file exist, if not create one
73         ofile = filename + '.orig'
74         (ret, stdout, stderr) = self.exec_command('ls {}'.format(ofile))
75         if ret != 0:
76             logging.debug(stderr)
77             if stdout.strip('\n') != ofile:
78                 cmd = 'sudo cp {} {}'.format(filename, ofile)
79                 (ret, stdout, stderr) = self.exec_command(cmd)
80                 if ret != 0:
81                     logging.debug(stderr)
82
83     def _install_vpp_pkg_ubuntu(self, node, pkg):
84         """
85         Install the VPP packages
86
87         :param node: Node dictionary
88         :param pkg: The vpp packages
89         :type node: dict
90         :type pkg: string
91         """
92
93         cmd = 'apt-get -y install {}'.format(pkg)
94         (ret, stdout, stderr) = self.exec_command(cmd)
95         if ret != 0:
96             raise RuntimeError('{} failed on node {} {} {}'.format(
97                 cmd, node['host'], stdout, stderr))
98
99     def _install_vpp_pkg_centos(self, node, pkg):
100         """
101         Install the VPP packages
102
103         :param node: Node dictionary
104         :param pkg: The vpp packages
105         :type node: dict
106         :type pkg: string
107         """
108
109         cmd = 'yum -y install {}'.format(pkg)
110         (ret, stdout, stderr) = self.exec_command(cmd)
111         if ret != 0:
112             raise RuntimeError('{} failed on node {} {} {}'.format(
113                 cmd, node['host'], stdout, stderr))
114
115     def _install_vpp_ubuntu(self, node, fdio_release=VPP_VERSION,
116                             ubuntu_version='xenial'):
117         """
118         Install the VPP packages
119
120         :param node: Node dictionary with cpuinfo.
121         :param fdio_release: VPP release number
122         :param ubuntu_version: Ubuntu Version
123         :type node: dict
124         :type fdio_release: string
125         :type ubuntu_version: string
126         """
127
128         # Modify the sources list
129         sfile = '/etc/apt/sources.list.d/99fd.io.list'
130
131         # Backup the sources list
132         self._autoconfig_backup_file(sfile)
133
134         # Remove the current file
135         cmd = 'rm {}'.format(sfile)
136         (ret, stdout, stderr) = self.exec_command(cmd)
137         if ret != 0:
138             logging.debug('{} failed on node {} {}'.format(
139                 cmd,
140                 node['host'],
141                 stderr))
142
143         reps = 'deb [trusted=yes] https://nexus.fd.io/content/'
144         # When using a stable branch
145         # reps += 'repositories/fd.io.stable.{}.ubuntu.{}.main/ ./\n'.format(fdio_release, ubuntu_version)
146         # When using release
147         reps += 'repositories/fd.io.ubuntu.{}.main/ ./\n'.format(ubuntu_version)
148         # When using master
149         # reps += 'repositories/fd.io.master.ubuntu.{}.main/ ./\n'.format(ubuntu_version)
150
151         cmd = 'echo "{0}" | sudo tee {1}'.format(reps, sfile)
152         (ret, stdout, stderr) = self.exec_command(cmd)
153         if ret != 0:
154             raise RuntimeError('{} failed on node {} {}'.format(
155                 cmd,
156                 node['host'],
157                 stderr))
158
159         # Install the package
160         cmd = 'apt-get -y update'
161         (ret, stdout, stderr) = self.exec_command(cmd)
162         if ret != 0:
163             raise RuntimeError('{} apt-get update failed on node {} {}'.format(
164                 cmd,
165                 node['host'],
166                 stderr))
167
168         self._install_vpp_pkg_ubuntu(node, 'vpp-lib')
169         self._install_vpp_pkg_ubuntu(node, 'vpp')
170         self._install_vpp_pkg_ubuntu(node, 'vpp-plugins')
171         self._install_vpp_pkg_ubuntu(node, 'vpp-dpdk-dkms')
172         self._install_vpp_pkg_ubuntu(node, 'vpp-dpdk-dev')
173         self._install_vpp_pkg_ubuntu(node, 'vpp-api-python')
174         self._install_vpp_pkg_ubuntu(node, 'vpp-api-java')
175         self._install_vpp_pkg_ubuntu(node, 'vpp-api-lua')
176         self._install_vpp_pkg_ubuntu(node, 'vpp-dev')
177         self._install_vpp_pkg_ubuntu(node, 'vpp-dbg')
178
179     def _install_vpp_centos(self, node, fdio_release=VPP_VERSION,
180                             centos_version='centos7'):
181         """
182         Install the VPP packages
183
184         :param node: Node dictionary with cpuinfo.
185         :param fdio_release: VPP release number
186         :param centos_version: Ubuntu Version
187         :type node: dict
188         :type fdio_release: string
189         :type centos_version: string
190         """
191
192         # Modify the sources list
193         sfile = '/etc/yum.repos.d/fdio-release.repo'
194
195         # Backup the sources list
196         self._autoconfig_backup_file(sfile)
197
198         # Remove the current file
199         cmd = 'rm {}'.format(sfile)
200         (ret, stdout, stderr) = self.exec_command(cmd)
201         if ret != 0:
202             logging.debug('{} failed on node {} {}'.format(
203                 cmd,
204                 node['host'],
205                 stderr))
206
207         # Latest
208         # reps = '[fdio-master]\n'
209         # reps += 'name=fd.io master branch latest merge\n'
210         # reps += 'baseurl=https://nexus.fd.io/content/repositories/fd.io.master.{}/\n'.format(centos_version)
211         # reps = '[fdio-stable-{}]\n'.format(fdio_release)
212         # reps += 'name=fd.io stable/{} branch latest merge\n'.format(fdio_release)
213         # When using stable
214         # reps += 'baseurl=https://nexus.fd.io/content/repositories/fd.io.stable.{}.{}/\n'.\
215         #     format(fdio_release, centos_version)
216         # When using release
217         reps = '[fdio-release]\n'
218         reps += 'name=fd.io release branch latest merge\n'
219         reps += 'baseurl=https://nexus.fd.io/content/repositories/fd.io.{}/\n'.format(centos_version)
220         reps += 'enabled=1\n'
221         reps += 'gpgcheck=0'
222
223         cmd = 'echo "{0}" | sudo tee {1}'.format(reps, sfile)
224         (ret, stdout, stderr) = self.exec_command(cmd)
225         if ret != 0:
226             raise RuntimeError('{} failed on node {} {}'.format(
227                 cmd,
228                 node['host'],
229                 stderr))
230
231         # Install the packages
232  
233         self._install_vpp_pkg_centos(node, 'vpp-lib')
234         self._install_vpp_pkg_centos(node, 'vpp')
235         self._install_vpp_pkg_centos(node, 'vpp-plugins')
236         # jadfix Check with Ole
237         # self._install_vpp_pkg_centos(node, 'vpp-dpdk-devel')
238         self._install_vpp_pkg_centos(node, 'vpp-api-python')
239         self._install_vpp_pkg_centos(node, 'vpp-api-java')
240         self._install_vpp_pkg_centos(node, 'vpp-api-lua')
241         self._install_vpp_pkg_centos(node, 'vpp-devel')
242
243     def install_vpp(self, node):
244         """
245         Install the VPP packages
246
247         :param node: Node dictionary with cpuinfo.
248         :type node: dict
249         """
250         distro = self.get_linux_distro()
251         logging.info("  {}".format(distro[0]))
252         if distro[0] == 'Ubuntu':
253             logging.info("Install Ubuntu")
254             self._install_vpp_ubuntu(node)
255         elif distro[0] == 'CentOS Linux':
256             logging.info("Install CentOS")
257             self._install_vpp_centos(node)
258         else:
259             logging.info("Install CentOS (default)")
260             self._install_vpp_centos(node)
261         return
262
263     def _uninstall_vpp_pkg_ubuntu(self, node, pkg):
264         """
265         Uninstall the VPP packages
266
267         :param node: Node dictionary
268         :param pkg: The vpp packages
269         :type node: dict
270         :type pkg: string
271         """
272         cmd = 'dpkg --purge {}'.format(pkg)
273         (ret, stdout, stderr) = self.exec_command(cmd)
274         if ret != 0:
275             raise RuntimeError('{} failed on node {} {} {}'.format(
276                 cmd, node['host'], stdout, stderr))
277
278     def _uninstall_vpp_pkg_centos(self, node, pkg):
279         """
280         Uninstall the VPP packages
281
282         :param node: Node dictionary
283         :param pkg: The vpp packages
284         :type node: dict
285         :type pkg: string
286         """
287         cmd = 'yum -y remove {}'.format(pkg)
288         (ret, stdout, stderr) = self.exec_command(cmd)
289         if ret != 0:
290             raise RuntimeError('{} failed on node {} {} {}'.format(
291                 cmd, node['host'], stdout, stderr))
292
293     def _uninstall_vpp_ubuntu(self, node):
294         """
295         Uninstall the VPP packages
296
297         :param node: Node dictionary with cpuinfo.
298         :type node: dict
299         """
300         pkgs = self.get_installed_vpp_pkgs()
301
302         if len(pkgs) > 0:
303             if 'version' in pkgs[0]:
304                 logging.info("Uninstall Ubuntu Packages")
305                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-python')
306                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-java')
307                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-api-lua')
308                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-plugins')
309                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dpdk-dev')
310                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dpdk-dkms')
311                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dev')
312                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-dbg')
313                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp')
314                 self._uninstall_vpp_pkg_ubuntu(node, 'vpp-lib')
315             else:
316                 logging.info("Uninstall locally installed Ubuntu Packages")
317                 for pkg in pkgs:
318                     self._uninstall_vpp_pkg_ubuntu(node, pkg['name'])
319         else:
320             logging.error("There are no Ubuntu packages installed")
321
322     def _uninstall_vpp_centos(self, node):
323         """
324         Uninstall the VPP packages
325
326         :param node: Node dictionary with cpuinfo.
327         :type node: dict
328             """
329
330         pkgs = self.get_installed_vpp_pkgs()
331
332         if len(pkgs) > 0:
333             if 'version' in pkgs[0]:
334                 logging.info("Uninstall CentOS Packages")
335                 self._uninstall_vpp_pkg_centos(node, 'vpp-api-python')
336                 self._uninstall_vpp_pkg_centos(node, 'vpp-api-java')
337                 self._uninstall_vpp_pkg_centos(node, 'vpp-api-lua')
338                 self._uninstall_vpp_pkg_centos(node, 'vpp-plugins')
339                 self._uninstall_vpp_pkg_centos(node, 'vpp-dpdk-devel')
340                 self._uninstall_vpp_pkg_centos(node, 'vpp-devel')
341                 self._uninstall_vpp_pkg_centos(node, 'vpp')
342                 self._uninstall_vpp_pkg_centos(node, 'vpp-lib')
343             else:
344                 logging.info("Uninstall locally installed CentOS Packages")
345                 for pkg in pkgs:
346                     self._uninstall_vpp_pkg_centos(node, pkg['name'])
347         else:
348             logging.error("There are no CentOS packages installed")
349
350     def uninstall_vpp(self, node):
351         """
352         Uninstall the VPP packages
353
354         :param node: Node dictionary with cpuinfo.
355         :type node: dict
356         """
357
358         # First stop VPP
359         self.stop(node)
360
361         distro = self.get_linux_distro()
362         if distro[0] == 'Ubuntu':
363             logging.info("Uninstall Ubuntu")
364             self._uninstall_vpp_ubuntu(node)
365         elif distro[0] == 'CentOS Linux':
366             logging.info("Uninstall CentOS")
367             self._uninstall_vpp_centos(node)
368         else:
369             logging.info("Uninstall CentOS (Default)")
370             self._uninstall_vpp_centos(node)
371             return
372
373     def show_vpp_settings(self, *additional_cmds):
374         """
375         Print default VPP settings. In case others are needed, can be
376         accepted as next parameters (each setting one parameter), preferably
377         in form of a string.
378
379         :param additional_cmds: Additional commands that the vpp should print
380         settings for.
381         :type additional_cmds: tuple
382         """
383         def_setting_tb_displayed = {
384             'IPv6 FIB': 'ip6 fib',
385             'IPv4 FIB': 'ip fib',
386             'Interface IP': 'int addr',
387             'Interfaces': 'int',
388             'ARP': 'ip arp',
389             'Errors': 'err'
390         }
391
392         if additional_cmds:
393             for cmd in additional_cmds:
394                 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] \
395                     = cmd
396
397                 for _, value in def_setting_tb_displayed.items():
398                     self.exec_command('vppctl sh {}'.format(value))
399
400     @staticmethod
401     def get_vms(node):
402         """
403         Get a list of VMs that are connected to VPP interfaces
404
405         :param node: VPP node.
406         :type node: dict
407         :returns: Dictionary containing a list of VMs and the interfaces that are connected to VPP
408         :rtype: dictionary
409         """
410
411         vmdict = {}
412
413         print "Need to implement get vms"
414         
415         return vmdict
416
417     @staticmethod
418     def get_int_ip(node):
419         """
420         Get the VPP interfaces and IP addresses
421
422         :param node: VPP node.
423         :type node: dict
424         :returns: Dictionary containing VPP interfaces and IP addresses
425         :rtype: dictionary
426         """
427         interfaces = {}
428         cmd = 'vppctl show int addr'
429         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
430         if ret != 0:
431             return interfaces
432
433         lines = stdout.split('\n')
434         if len(lines[0]) is not 0:
435             if lines[0].split(' ')[0] == 'FileNotFoundError':
436                 return interfaces
437
438         name = ''
439         for line in lines:
440             if len(line) is 0:
441                 continue
442
443             # If the first character is not whitespace
444             # create a new interface
445             if len(re.findall(r'\s', line[0])) is 0:
446                 spl = line.split()
447                 name = spl[0]
448                 if name == 'local0':
449                     continue
450                 interfaces[name] = {}
451                 interfaces[name]['state'] = spl[1].lstrip('(').rstrip('):\r')
452             else:
453                 interfaces[name]['address'] = line.lstrip(' ').rstrip('\r')
454
455         return interfaces
456
457     @staticmethod
458     def get_hardware(node):
459         """
460         Get the VPP hardware information and return it in a
461         dictionary
462
463         :param node: VPP node.
464         :type node: dict
465         :returns: Dictionary containing VPP hardware information
466         :rtype: dictionary
467         """
468
469         interfaces = {}
470         cmd = 'vppctl show hard'
471         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
472         if ret != 0:
473             return interfaces
474
475         lines = stdout.split('\n')
476         if len(lines[0]) is not 0:
477             if lines[0].split(' ')[0] == 'FileNotFoundError':
478                 return interfaces
479
480         for line in lines:
481             if len(line) is 0:
482                 continue
483
484             # If the first character is not whitespace
485             # create a new interface
486             if len(re.findall(r'\s', line[0])) is 0:
487                 spl = line.split()
488                 name = spl[0]
489                 interfaces[name] = {}
490                 interfaces[name]['index'] = spl[1]
491                 interfaces[name]['state'] = spl[2]
492
493             # Ethernet address
494             rfall = re.findall(r'Ethernet address', line)
495             if rfall:
496                 spl = line.split()
497                 interfaces[name]['mac'] = spl[2]
498
499             # Carrier
500             rfall = re.findall(r'carrier', line)
501             if rfall:
502                 spl = line.split('carrier ')
503                 interfaces[name]['carrier'] = spl[1]
504
505             # Socket
506             rfall = re.findall(r'cpu socket', line)
507             if rfall:
508                 spl = line.split('cpu socket ')
509                 interfaces[name]['cpu socket'] = spl[1]
510
511             # Queues and Descriptors
512             rfall = re.findall(r'rx queues', line)
513             if rfall:
514                 spl = line.split(',')
515                 interfaces[name]['rx queues'] = spl[0].lstrip(' ').split(' ')[2]
516                 interfaces[name]['rx descs'] = spl[1].split(' ')[3]
517                 interfaces[name]['tx queues'] = spl[2].split(' ')[3]
518                 interfaces[name]['tx descs'] = spl[3].split(' ')[3]
519
520         return interfaces
521
522     def _get_installed_vpp_pkgs_ubuntu(self):
523         """
524         Get the VPP hardware information and return it in a
525         dictionary
526
527         :returns: List of the packages installed
528         :rtype: list
529         """
530
531         pkgs = []
532         cmd = 'dpkg -l | grep vpp'
533         (ret, stdout, stderr) = self.exec_command(cmd)
534         if ret != 0:
535             return pkgs
536
537         lines = stdout.split('\n')
538         for line in lines:
539             items = line.split()
540             if len(items) < 2:
541                 continue
542             pkg = {'name': items[1], 'version': items[2]}
543             pkgs.append(pkg)
544
545         return pkgs
546
547     def _get_installed_vpp_pkgs_centos(self):
548         """
549         Get the VPP hardware information and return it in a
550         dictionary
551
552         :returns: List of the packages installed
553         :rtype: list
554         """
555
556         pkgs = []
557         cmd = 'rpm -qa | grep vpp'
558         (ret, stdout, stderr) = self.exec_command(cmd)
559         if ret != 0:
560             return pkgs
561
562         lines = stdout.split('\n')
563         for line in lines:
564             if len(line) == 0:
565                 continue
566
567             items = line.split()
568             if len(items) < 2:
569                 pkg = {'name': items[0]}
570             else:
571                 pkg = {'name': items[1], 'version': items[2]}
572
573             pkgs.append(pkg)
574
575         return pkgs
576
577     def get_installed_vpp_pkgs(self):
578         """
579         Get the VPP hardware information and return it in a
580         dictionary
581
582         :returns: List of the packages installed
583         :rtype: list
584         """
585
586         distro = self.get_linux_distro()
587         if distro[0] == 'Ubuntu':
588             pkgs = self._get_installed_vpp_pkgs_ubuntu()
589         elif distro[0] == 'CentOS Linux':
590             pkgs = self._get_installed_vpp_pkgs_centos()
591         else:
592             pkgs = self._get_installed_vpp_pkgs_centos()
593             return []
594
595         return pkgs
596
597     @staticmethod
598     def get_interfaces_numa_node(node, *iface_keys):
599         """Get numa node on which are located most of the interfaces.
600
601         Return numa node with highest count of interfaces provided as arguments.
602         Return 0 if the interface does not have numa_node information available.
603         If all interfaces have unknown location (-1), then return 0.
604         If most of interfaces have unknown location (-1), but there are
605         some interfaces with known location, then return the second most
606         location of the provided interfaces.
607
608         :param node: Node from DICT__nodes.
609         :param iface_keys: Interface keys for lookup.
610         :type node: dict
611         :type iface_keys: strings
612         """
613         numa_list = []
614         for if_key in iface_keys:
615             try:
616                 numa_list.append(node['interfaces'][if_key].get('numa_node'))
617             except KeyError:
618                 pass
619
620         numa_cnt_mc = Counter(numa_list).most_common()
621         numa_cnt_mc_len = len(numa_cnt_mc)
622         if numa_cnt_mc_len > 0 and numa_cnt_mc[0][0] != -1:
623             return numa_cnt_mc[0][0]
624         elif numa_cnt_mc_len > 1 and numa_cnt_mc[0][0] == -1:
625             return numa_cnt_mc[1][0]
626
627         return 0
628
629     @staticmethod
630     def restart(node):
631         """
632
633         Starts vpp for a given node
634
635         :param node: VPP node.
636         :type node: dict
637         """
638
639         cmd = 'service vpp restart'
640         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
641         if ret != 0:
642             raise RuntimeError('{} failed on node {} {} {}'.
643                                format(cmd, node['host'],
644                                       stdout, stderr))
645
646     @staticmethod
647     def start(node):
648         """
649
650         Starts vpp for a given node
651
652         :param node: VPP node.
653         :type node: dict
654         """
655
656         cmd = 'service vpp start'
657         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
658         if ret != 0:
659             raise RuntimeError('{} failed on node {} {} {}'.
660                                format(cmd, node['host'],
661                                       stdout, stderr))
662
663     @staticmethod
664     def stop(node):
665         """
666
667         Stops vpp for a given node
668
669         :param node: VPP node.
670         :type node: dict
671         """
672
673         cmd = 'service vpp stop'
674         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
675         if ret != 0:
676             raise RuntimeError('{} failed on node {} {} {}'.
677                                format(cmd, node['host'],
678                                       stdout, stderr))
679
680     # noinspection RegExpRedundantEscape
681     @staticmethod
682     def status(node):
683         """
684
685         Gets VPP status
686
687         :param: node
688         :type node: dict
689         :returns: status, errors
690         :rtype: tuple(str, list)
691         """
692         errors = []
693         vutil = VPPUtil()
694         pkgs = vutil.get_installed_vpp_pkgs()
695         if len(pkgs) == 0:
696             return "Not Installed", errors
697
698         cmd = 'service vpp status'
699         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
700
701         # Get the active status
702         state = re.findall(r'Active:[\w (\)]+', stdout)[0].split(' ')
703         if len(state) > 2:
704             statestr = "{} {}".format(state[1], state[2])
705         else:
706             statestr = "Invalid"
707
708         # For now we won't look for DPDK errors
709         # lines = stdout.split('\n')
710         # for line in lines:
711         #    if 'EAL' in line or \
712         #                     'FAILURE' in line or \
713         #                     'failed' in line or \
714         #                     'Failed' in line:
715         #         errors.append(line.lstrip(' '))
716
717         return statestr, errors
718
719     @staticmethod
720     def get_linux_distro():
721         """
722         Get the linux distribution and check if it is supported
723
724         :returns: linux distro, None if the distro is not supported
725         :rtype: list
726         """
727
728         distro = platform.linux_distribution()
729         if distro[0] == 'Ubuntu' or \
730                         distro[0] == 'CentOS Linux' or \
731                         distro[:7] == 'Red Hat':
732             return distro
733         else:
734             raise RuntimeError('Linux Distribution {} is not supported'.format(distro[0]))
735
736     @staticmethod
737     def version():
738         """
739
740         Gets VPP Version information
741
742         :returns: version
743         :rtype: dict
744         """
745
746         version = {}
747         cmd = 'vppctl show version verbose'
748         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
749         if ret != 0:
750             return version
751
752         lines = stdout.split('\n')
753         if len(lines[0]) is not 0:
754             if lines[0].split(' ')[0] == 'FileNotFoundError':
755                 return version
756
757         for line in lines:
758             if len(line) is 0:
759                 continue
760             dct = line.split(':')
761             version[dct[0]] = dct[1].lstrip(' ')
762
763         return version
764
765     @staticmethod
766     def show_bridge(node):
767         """
768         Shows the current bridge configuration
769
770         :param node: VPP node.
771         :type node: dict
772         :returns: A list of interfaces
773         """
774
775         ifaces = []
776         cmd = 'vppctl show bridge'
777         (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
778         if ret != 0:
779             raise RuntimeError('{} failed on node {} {} {}'.
780                                format(cmd, node['host'],
781                                       stdout, stderr))
782         lines = stdout.split('\r\n')
783         bridges = []
784         for line in lines:
785             if line == 'no bridge-domains in use':
786                 print line
787                 return ifaces
788             if len(line) == 0:
789                 continue
790
791             lspl = line.lstrip(' ').split()
792             if lspl[0] != 'BD-ID':
793                 bridges.append(lspl[0])
794
795         for bridge in bridges:
796             cmd = 'vppctl show bridge {} detail'.format(bridge)
797             (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
798             if ret != 0:
799                 raise RuntimeError('{} failed on node {} {} {}'.
800                                    format(cmd, node['host'],
801                                           stdout, stderr))
802
803         lines = stdout.split('\r\n')
804         for line in lines:
805             iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
806             if len(iface):
807                 ifcidx ={'name': iface[0], 'index': line.split()[1] }
808                 ifaces.append(ifcidx)
809
810         print stdout
811         return ifaces