diff options
-rw-r--r-- | test/lib/quagga.py | 150 | ||||
-rw-r--r-- | test/scenario_test/bgp_router_test.py | 20 | ||||
-rw-r--r-- | test/scenario_test/ibgp_router_test.py | 25 | ||||
-rw-r--r-- | test/scenario_test/route_reflector_test.py | 11 | ||||
-rw-r--r-- | test/scenario_test/route_server_ipv4_v6_test.py | 17 | ||||
-rw-r--r-- | test/scenario_test/route_server_test.py | 23 |
6 files changed, 177 insertions, 69 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): diff --git a/test/scenario_test/bgp_router_test.py b/test/scenario_test/bgp_router_test.py index 1a92a1b3..7d93ba53 100644 --- a/test/scenario_test/bgp_router_test.py +++ b/test/scenario_test/bgp_router_test.py @@ -59,21 +59,17 @@ class GoBGPTestBase(unittest.TestCase): qs = [q1, q2, q3] ctns = [g1, q1, q2, q3] - # advertise a route from q1, q2, q3 - for idx, q in enumerate(qs): - route = '10.0.{0}.0/24'.format(idx + 1) - q.add_route(route) - initial_wait_time = max(ctn.run() for ctn in ctns) - time.sleep(initial_wait_time) for q in qs: - g1.add_peer(q, reload_config=False, passwd='passwd') + g1.add_peer(q, passwd='passwd') q.add_peer(g1, passwd='passwd', passive=True) - g1.create_config() - g1.reload_config() + # advertise a route from q1, q2, q3 + for idx, q in enumerate(qs): + route = '10.0.{0}.0/24'.format(idx + 1) + q.add_route(route) cls.gobgp = g1 cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3} @@ -145,14 +141,14 @@ class GoBGPTestBase(unittest.TestCase): def test_05_add_quagga(self): q4 = QuaggaBGPContainer(name='q4', asn=65004, router_id='192.168.0.5') self.quaggas['q4'] = q4 - - q4.add_route('10.0.4.0/24') - initial_wait_time = q4.run() time.sleep(initial_wait_time) + self.gobgp.add_peer(q4) q4.add_peer(self.gobgp) + q4.add_route('10.0.4.0/24') + self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q4) def test_06_check_global_rib(self): diff --git a/test/scenario_test/ibgp_router_test.py b/test/scenario_test/ibgp_router_test.py index ed476122..59815e6e 100644 --- a/test/scenario_test/ibgp_router_test.py +++ b/test/scenario_test/ibgp_router_test.py @@ -51,13 +51,7 @@ class GoBGPTestBase(unittest.TestCase): qs = [q1, q2] ctns = [g1, q1, q2] - # advertise a route from q1, q2 - for idx, c in enumerate(qs): - route = '10.0.{0}.0/24'.format(idx + 1) - c.add_route(route) - initial_wait_time = max(ctn.run() for ctn in ctns) - time.sleep(initial_wait_time) # ibgp peer. loop topology @@ -65,6 +59,11 @@ class GoBGPTestBase(unittest.TestCase): a.add_peer(b) b.add_peer(a) + # advertise a route from q1, q2 + for idx, c in enumerate(qs): + route = '10.0.{0}.0/24'.format(idx + 1) + c.add_route(route) + cls.gobgp = g1 cls.quaggas = {'q1': q1, 'q2': q2} @@ -163,14 +162,14 @@ class GoBGPTestBase(unittest.TestCase): def test_07_add_ebgp_peer(self): q3 = QuaggaBGPContainer(name='q3', asn=65001, router_id='192.168.0.4') self.quaggas['q3'] = q3 - - q3.add_route('10.0.3.0/24') - initial_wait_time = q3.run() time.sleep(initial_wait_time) + self.gobgp.add_peer(q3) q3.add_peer(self.gobgp) + q3.add_route('10.0.3.0/24') + self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q3) def test_08_check_global_rib(self): @@ -246,15 +245,15 @@ class GoBGPTestBase(unittest.TestCase): def test_15_add_ebgp_peer(self): q4 = QuaggaBGPContainer(name='q4', asn=65001, router_id='192.168.0.5') self.quaggas['q4'] = q4 - - prefix = '10.0.4.0/24' - q4.add_route(prefix) - initial_wait_time = q4.run() time.sleep(initial_wait_time) + self.gobgp.add_peer(q4) q4.add_peer(self.gobgp) + prefix = '10.0.4.0/24' + q4.add_route(prefix) + self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q4) q1 = self.quaggas['q1'] diff --git a/test/scenario_test/route_reflector_test.py b/test/scenario_test/route_reflector_test.py index a5516dec..29846d53 100644 --- a/test/scenario_test/route_reflector_test.py +++ b/test/scenario_test/route_reflector_test.py @@ -61,13 +61,7 @@ class GoBGPTestBase(unittest.TestCase): qs = [q1, q2, q3, q4] ctns = [g1, q1, q2, q3, q4] - # advertise a route from q1, q2 - for idx, c in enumerate(qs): - route = '10.0.{0}.0/24'.format(idx + 1) - c.add_route(route) - initial_wait_time = max(ctn.run() for ctn in ctns) - time.sleep(initial_wait_time) # g1 as a route reflector @@ -80,6 +74,11 @@ class GoBGPTestBase(unittest.TestCase): g1.add_peer(q4) q4.add_peer(g1) + # advertise a route from q1, q2 + for idx, c in enumerate(qs): + route = '10.0.{0}.0/24'.format(idx + 1) + c.add_route(route) + cls.gobgp = g1 cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3, 'q4': q4} diff --git a/test/scenario_test/route_server_ipv4_v6_test.py b/test/scenario_test/route_server_ipv4_v6_test.py index 9d7e15a7..07f77e4a 100644 --- a/test/scenario_test/route_server_ipv4_v6_test.py +++ b/test/scenario_test/route_server_ipv4_v6_test.py @@ -52,16 +52,7 @@ class GoBGPIPv6Test(unittest.TestCase): v4 = [q1, q2] v6 = [q3, q4] - for idx, q in enumerate(v4): - route = '10.0.{0}.0/24'.format(idx + 1) - q.add_route(route) - - for idx, q in enumerate(v6): - route = '2001:{0}::/96'.format(idx + 1) - q.add_route(route, rf='ipv6') - initial_wait_time = max(ctn.run() for ctn in ctns) - time.sleep(initial_wait_time) for ctn in v4: @@ -72,6 +63,14 @@ class GoBGPIPv6Test(unittest.TestCase): g1.add_peer(ctn, is_rs_client=True, v6=True) ctn.add_peer(g1, v6=True) + for idx, q in enumerate(v4): + route = '10.0.{0}.0/24'.format(idx + 1) + q.add_route(route) + + for idx, q in enumerate(v6): + route = '2001:{0}::/96'.format(idx + 1) + q.add_route(route, rf='ipv6') + cls.gobgp = g1 cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3, 'q4': q4} cls.ipv4s = {'q1': q1, 'q2': q2} diff --git a/test/scenario_test/route_server_test.py b/test/scenario_test/route_server_test.py index a99f1f8b..149adfd2 100644 --- a/test/scenario_test/route_server_test.py +++ b/test/scenario_test/route_server_test.py @@ -56,21 +56,20 @@ class GoBGPTestBase(unittest.TestCase): q2 = rs_clients[1] q3 = rs_clients[2] - # advertise a route from route-server-clients - routes = [] - for idx, rs_client in enumerate(rs_clients): - route = '10.0.{0}.0/24'.format(idx + 1) - rs_client.add_route(route) - routes.append(route) - initial_wait_time = max(ctn.run() for ctn in ctns) - time.sleep(initial_wait_time) for rs_client in rs_clients: g1.add_peer(rs_client, is_rs_client=True, passwd='passwd', passive=True, prefix_limit=10) rs_client.add_peer(g1, passwd='passwd') + # advertise a route from route-server-clients + routes = [] + for idx, rs_client in enumerate(rs_clients): + route = '10.0.{0}.0/24'.format(idx + 1) + rs_client.add_route(route) + routes.append(route) + cls.gobgp = g1 cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3} @@ -148,15 +147,15 @@ class GoBGPTestBase(unittest.TestCase): def test_05_add_rs_client(self): q4 = QuaggaBGPContainer(name='q4', asn=65004, router_id='192.168.0.5') self.quaggas['q4'] = q4 - - route = '10.0.4.0/24' - q4.add_route(route) - initial_wait_time = q4.run() time.sleep(initial_wait_time) + self.gobgp.add_peer(q4, is_rs_client=True) q4.add_peer(self.gobgp) + route = '10.0.4.0/24' + q4.add_route(route) + self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q4) # check advertised routes are stored in gobgp's local-rib |