diff options
Diffstat (limited to 'test/lib')
-rw-r--r-- | test/lib/quagga.py | 150 |
1 files changed, 133 insertions, 17 deletions
diff --git a/test/lib/quagga.py b/test/lib/quagga.py index e657b439..0b5ecdd1 100644 --- a/test/lib/quagga.py +++ b/test/lib/quagga.py @@ -14,11 +14,11 @@ # limitations under the License. from __future__ import absolute_import + import re from fabric import colors from fabric.utils import indent -from itertools import chain import netaddr from lib.base import ( @@ -63,13 +63,16 @@ class QuaggaBGPContainer(BGPContainer): daemons.append('zebra') return daemons - def _wait_for_boot(self): - for daemon in self._get_enabled_daemons(): - def _f(): - ret = self.local("vtysh -d {0} -c 'show run' > /dev/null 2>&1; echo $?".format(daemon), capture=True) - return ret == '0' + def _is_running(self): + def f(d): + return self.local( + 'vtysh -d {0} -c "show version"' + ' > /dev/null 2>&1; echo $?'.format(d), capture=True) == '0' - wait_for_completion(_f) + return all([f(d) for d in self._get_enabled_daemons()]) + + def _wait_for_boot(self): + wait_for_completion(self._is_running) def run(self): super(QuaggaBGPContainer, self).run() @@ -215,16 +218,6 @@ class QuaggaBGPContainer(BGPContainer): c << 'neighbor {0} activate'.format(n_addr) c << 'exit-address-family' - for route in chain.from_iterable(self.routes.itervalues()): - if route['rf'] == 'ipv4': - c << 'network {0}'.format(route['prefix']) - elif route['rf'] == 'ipv6': - c << 'address-family ipv6 unicast' - c << 'network {0}'.format(route['prefix']) - c << 'exit-address-family' - else: - raise Exception('unsupported route faily: {0}'.format(route['rf'])) - if self.zebra: if version == 6: c << 'address-family ipv6 unicast' @@ -281,6 +274,129 @@ class QuaggaBGPContainer(BGPContainer): self.local('pkill {0} -SIGHUP'.format(daemon), capture=True) self._wait_for_boot() + def _vtysh_add_route_map(self, path): + supported_attributes = ( + 'next-hop', + 'as-path', + 'community', + 'med', + 'local-pref', + 'extended-community', + ) + if not any([path[k] for k in supported_attributes]): + return '' + + c = CmdBuffer(' ') + route_map_name = 'RM-{0}'.format(path['prefix']) + c << "vtysh -c 'configure terminal'" + c << "-c 'route-map {0} permit 10'".format(route_map_name) + if path['next-hop']: + if path['rf'] == 'ipv4': + c << "-c 'set ip next-hop {0}'".format(path['next-hop']) + elif path['rf'] == 'ipv6': + c << "-c 'set ipv6 next-hop {0}'".format(path['next-hop']) + else: + raise ValueError('Unsupported address family: {0}'.format(path['rf'])) + if path['as-path']: + as_path = ' '.join([str(n) for n in path['as-path']]) + c << "-c 'set as-path prepend {0}'".format(as_path) + if path['community']: + comm = ' '.join(path['community']) + c << "-c 'set community {0}'".format(comm) + if path['med']: + c << "-c 'set metric {0}'".format(path['med']) + if path['local-pref']: + c << "-c 'set local-preference {0}'".format(path['local-pref']) + if path['extended-community']: + # Note: Currently only RT is supported. + extcomm = ' '.join(path['extended-community']) + c << "-c 'set extcommunity rt {0}'".format(extcomm) + self.local(str(c), capture=True) + + return route_map_name + + def add_route(self, route, rf='ipv4', attribute=None, aspath=None, + community=None, med=None, extendedcommunity=None, + nexthop=None, matchs=None, thens=None, + local_pref=None, identifier=None, reload_config=False): + if not self._is_running(): + raise RuntimeError('Quagga/Zebra is not yet running') + + if rf not in ('ipv4', 'ipv6'): + raise ValueError('Unsupported address family: {0}'.format(rf)) + + self.routes.setdefault(route, []) + path = { + 'prefix': route, + 'rf': rf, + 'next-hop': nexthop, + 'as-path': aspath, + 'community': community, + 'med': med, + 'local-pref': local_pref, + 'extended-community': extendedcommunity, + # Note: The following settings are not yet supported on this + # implementation. + 'attr': None, + 'identifier': None, + 'matchs': None, + 'thens': None, + } + + # Prepare route-map before adding prefix + route_map_name = self._vtysh_add_route_map(path) + path['route_map'] = route_map_name + + c = CmdBuffer(' ') + c << "vtysh -c 'configure terminal'" + c << "-c 'router bgp {0}'".format(self.asn) + if rf == 'ipv6': + c << "-c 'address-family ipv6'" + if route_map_name: + c << "-c 'network {0} route-map {1}'".format(route, route_map_name) + else: + c << "-c 'network {0}'".format(route) + self.local(str(c), capture=True) + + self.routes[route].append(path) + + def _vtysh_del_route_map(self, path): + route_map_name = path.get('route_map', '') + if not route_map_name: + return + + c = CmdBuffer(' ') + c << "vtysh -c 'configure terminal'" + c << "-c 'no route-map {0}'".format(route_map_name) + self.local(str(c), capture=True) + + def del_route(self, route, identifier=None, reload_config=False): + if not self._is_running(): + raise RuntimeError('Quagga/Zebra is not yet running') + + path = None + new_paths = [] + for p in self.routes.get(route, []): + if p['identifier'] != identifier: + new_paths.append(p) + else: + path = p + if not path: + return + + rf = path['rf'] + c = CmdBuffer(' ') + c << "vtysh -c 'configure terminal'" + c << "-c 'router bgp {0}'".format(self.asn) + c << "-c 'address-family {0} unicast'".format(rf) + c << "-c 'no network {0}'".format(route) + self.local(str(c), capture=True) + + # Delete route-map after deleting prefix + self._vtysh_del_route_map(path) + + self.routes[route] = new_paths + class RawQuaggaBGPContainer(QuaggaBGPContainer): def __init__(self, name, config, ctn_image_name='osrg/quagga', zebra=False): |