summaryrefslogtreecommitdiffhomepage
path: root/test/lib/quagga.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/lib/quagga.py')
-rw-r--r--test/lib/quagga.py150
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):