summaryrefslogtreecommitdiffhomepage
path: root/test/lib/quagga.py
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2018-01-25 14:42:33 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2018-01-27 20:48:42 +0900
commit5ea3cbdd9dc41e6dcf3c0258455a357e154efdb1 (patch)
tree6f331a98b035cb5d027ee556de6958064e19c25c /test/lib/quagga.py
parent38223f2f512cce3d05c9ae8f29ade983aa723cef (diff)
test/lib/Quagga: Use vtysh to add/del routes
Currently, to advertise or withdraw routes on QuaggaBGPContainer, we need to configure static routes in configure file and restart Quagga daemons. In other words, we can NOT send withdrawing advertisement from Quagga side. Also, restating Quagga daemons frequently can make scenario test unstable, and it should be avoided. This patch fixes to use "vtysh" and reduces the number of restating Quagga daemons. Note: According to this change, adding routes on Quagga should be called after starting daemons. Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
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):