summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2015-07-02 15:29:05 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-07-03 06:29:07 +0900
commit34c88c4771a5dd4fb687fe225cebfc6fc99381f0 (patch)
treeb6144f582473b2aea9127cbbcb113d1b16b57a77
parent64f5846bc6e1a12b0a9bf3fb8d56d33ebe46b811 (diff)
test: introduce modular test library
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
-rw-r--r--test/scenario_test/bgp_router_test.py453
-rw-r--r--test/scenario_test/lib/__init__.py0
-rw-r--r--test/scenario_test/lib/bagpipe.py73
-rw-r--r--test/scenario_test/lib/base.py266
-rw-r--r--test/scenario_test/lib/exabgp.py99
-rw-r--r--test/scenario_test/lib/gobgp.py175
-rw-r--r--test/scenario_test/lib/quagga.py193
-rw-r--r--test/scenario_test/noseplugin.py5
-rw-r--r--test/scenario_test/route_server_ipv4_v6_test.py2
-rw-r--r--test/scenario_test/route_server_malformed_test.py2
-rw-r--r--test/scenario_test/route_server_policy_test.py2
-rw-r--r--test/scenario_test/route_server_test.py2
12 files changed, 1015 insertions, 257 deletions
diff --git a/test/scenario_test/bgp_router_test.py b/test/scenario_test/bgp_router_test.py
index f965d224..a424d625 100644
--- a/test/scenario_test/bgp_router_test.py
+++ b/test/scenario_test/bgp_router_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
+# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,273 +13,224 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
+import unittest
+from fabric.api import local
+from lib.gobgp import *
+from lib.quagga import *
import sys
+import os
+import time
import nose
-import quagga_access as qaccess
-import docker_control as fab
-from gobgp_test import GoBGPTestBase
-from gobgp_test import ADJ_RIB_OUT, GLOBAL_RIB
-from gobgp_test import NEIGHBOR
-from noseplugin import OptionParser
-from noseplugin import parser_option
-
-class GoBGPTest(GoBGPTestBase):
- quagga_num = 3
- append_quagga = 10
- remove_quagga = 10
- append_quagga_best = 20
-
- def __init__(self, *args, **kwargs):
- super(GoBGPTest, self).__init__(*args, **kwargs)
+from noseplugin import OptionParser, parser_option
+
+
+class GoBGPTestBase(unittest.TestCase):
+
+ wait_per_retry = 5
+ retry_limit = 15
+
+ @classmethod
+ def setUpClass(cls):
+ gobgp_ctn_image_name = 'osrg/gobgp'
+ if parser_option.use_local:
+ make_gobgp_ctn()
+ gobgp_ctn_image_name = 'gobgp'
+
+ g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
+ ctn_image_name=gobgp_ctn_image_name,
+ log_level=parser_option.gobgp_log_level)
+ q1 = QuaggaBGPContainer(name='q1', asn=65001, router_id='192.168.0.2')
+ q2 = QuaggaBGPContainer(name='q2', asn=65002, router_id='192.168.0.3')
+ q3 = QuaggaBGPContainer(name='q3', asn=65003, router_id='192.168.0.4')
+
+ 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)
+
+ br01 = Bridge(name='br01', subnet='192.168.10.0/24')
+ [br01.addif(ctn) for ctn in ctns]
+
+ for q in qs:
+ g1.add_peer(q)
+ q.add_peer(g1)
+
+ cls.gobgp = g1
+ cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3}
+ cls.bridges = {'br01': br01}
# test each neighbor state is turned establish
def test_01_neighbor_established(self):
- print "test_neighbor_established"
-
- use_local = parser_option.use_local
- go_path = parser_option.go_path
- log_debug = parser_option.gobgp_log_debug
- fab.init_test_env_executor(self.quagga_num, use_local, go_path, log_debug, is_route_server=False)
-
- print "please wait " + str(self.initial_wait_time) + " second"
- time.sleep(self.initial_wait_time)
- if self.check_load_config() is False:
- return
-
- addresses = self.get_neighbor_address(self.gobgp_config)
- self.retry_routine_for_state(addresses, "BGP_FSM_ESTABLISHED")
-
- for address in addresses:
- # get neighbor state and remote ip from gobgp connections
- print "check of [ " + address + " ]"
- neighbor = self.ask_gobgp(NEIGHBOR, address)
- state = neighbor['info']['bgp_state']
- remote_ip = neighbor['conf']['remote_ip']
- self.assertEqual(address, remote_ip)
- self.assertEqual(state, "BGP_FSM_ESTABLISHED")
-
- # Test of advertised route gobgp from each quagga
-
-
- def test_02_received_route(self):
- print "test_received_route"
- if self.check_load_config() is False:
- return
-
- self.assert_global_rib()
-
- # Test of advertising route to each quagga form gobgp
- def test_03_advertising_route(self):
- print "test_advertising_route"
- if self.check_load_config() is False:
- return
-
- for address in self.get_neighbor_address(self.gobgp_config):
- print "check of [ " + address + " ]"
- rib = self.ask_gobgp(ADJ_RIB_OUT, address)
- print rib
- self.assert_quagga_rib(address)
-
- # check if quagga that is appended can establish connection with gobgp
- def test_04_established_with_appended_quagga(self):
- print "test_established_with_appended_quagga"
- if self.check_load_config() is False:
- return
-
- go_path = parser_option.go_path
- # append new quagga container
- fab.docker_container_quagga_append_executor(self.append_quagga, go_path, is_route_server=False)
- print "please wait " + str(self.initial_wait_time) + " second"
- time.sleep(self.initial_wait_time)
- append_quagga_address = "10.0.0." + str(self.append_quagga)
- self.retry_routine_for_state([append_quagga_address], "BGP_FSM_ESTABLISHED")
-
- # get neighbor state and remote ip of new quagga
- print "check of [" + append_quagga_address + " ]"
- neighbor = self.ask_gobgp(NEIGHBOR, append_quagga_address)
- state = neighbor['info']['bgp_state']
- remote_ip = neighbor['conf']['remote_ip']
- self.assertEqual(append_quagga_address, remote_ip)
- self.assertEqual(state, "BGP_FSM_ESTABLISHED")
-
- # Test of advertised route gobgp from each quagga when append quagga container
- def test_05_received_route_when_appended_quagga(self):
- print "test_received_route_by_appended_quagga"
- if self.check_load_config() is False:
- return
-
- self.assert_global_rib()
-
- # Test of advertising route to each quagga form gobgp when append quagga container
- def test_06_advertising_route_when_appended_quagga(self):
- print "test_advertising_route_to_appended_quagga"
- if self.check_load_config() is False:
- return
-
- for address in self.get_neighbor_address(self.gobgp_config):
- print "check of [ " + address + " ]"
- self.assert_quagga_rib(address)
-
- def test_07_active_when_quagga_removed(self):
- print "test_active_when_removed_quagga"
- if self.check_load_config() is False:
- return
-
- # remove quagga container
- fab.docker_container_quagga_removed_executor(self.remove_quagga)
- print "please wait " + str(self.initial_wait_time) + " second"
- time.sleep(self.initial_wait_time)
- removed_quagga_address = "10.0.0." + str(self.remove_quagga)
- self.retry_routine_for_state([removed_quagga_address], "BGP_FSM_ACTIVE")
-
- # get neighbor state and remote ip of removed quagga
- print "check of [" + removed_quagga_address + " ]"
- neighbor = self.ask_gobgp(NEIGHBOR, removed_quagga_address)
- state = neighbor['info']['bgp_state']
- remote_ip = neighbor['conf']['remote_ip']
- self.assertEqual(removed_quagga_address, remote_ip)
- self.assertEqual(state, "BGP_FSM_ACTIVE")
-
- def test_08_received_route_when_quagga_removed(self):
- print "test_received_route_when_removed_quagga"
- if self.check_load_config() is False:
- return
-
- retry_count = 0
- still_exists = False
- while retry_count < self.dest_check_limit:
-
- rib = self.ask_gobgp(GLOBAL_RIB)
-
- removed_prefix = "10.0.0.%d/24" % self.remove_quagga
- still_exists = False
- for dst in rib:
- for path in dst['paths']:
- if path['nlri']['prefix'] == removed_prefix:
- still_exists = True
-
- if not still_exists:
- print "compare OK"
- break
- else:
- retry_count += 1
- print "compare NG -> retry ( %d / %d )" % (retry_count, self.dest_check_limit)
- time.sleep(self.wait_per_retry)
-
- self.assertEqual(still_exists, False)
-
- def test_09_advertising_route_when_quagga_removed(self):
- print "test_advertising_route_when_removed_quagga"
- if self.check_load_config() is False:
- return
-
- remove_quagga_address = "10.0.0." + str(self.remove_quagga)
- removed_prefix = "10.0.0.%d/24" % self.remove_quagga
- for address in self.get_neighbor_address(self.gobgp_config):
- if remove_quagga_address == address:
+ for q in self.quaggas.itervalues():
+ self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q)
+
+ def test_02_check_gobgp_global_rib(self):
+ for q in self.quaggas.itervalues():
+ # paths expected to exist in gobgp's global rib
+ routes = q.routes.keys()
+ # gobgp's global rib
+ global_rib = [p['prefix'] for p in self.gobgp.get_global_rib()]
+
+ for p in global_rib:
+ if p in routes:
+ routes.remove(p)
+
+ if len(routes) == 0:
continue
- print "check of [ " + address + " ]"
+ gobgp = '/go/bin/gobgp'
+ cmd = 'docker exec {0} {1}' \
+ ' monitor global rib -j'.format(self.gobgp.name, gobgp)
+
+ process = subprocess.Popen(cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ poll = select.epoll()
+ poll.register(process.stdout, select.POLLIN)
- retry_count = 0
- cmp_result = False
- while retry_count < self.dest_check_limit:
+ timeout = 10.0
- tn = qaccess.login(address)
- q_rib = qaccess.show_rib(tn)
- still_exists = False
- for q_path in q_rib:
- if q_path['Network'] == removed_prefix:
- still_exists = True
- #self.assertEqual(still_exists, False)
+ while True:
+ result = poll.poll(timeout)
+ if result:
+ line = process.stdout.readline()
+ path = json.loads(line)['nlri']['prefix']
+ if path in routes:
+ routes.remove(path)
- cmp_result = self.compare_route_with_quagga_configs(address, q_rib, route_server=False)
+ if len(routes) == 0:
+ return
+ continue
+ raise Exception('timeout')
- if cmp_result and not still_exists:
- print "compare OK"
+
+ # check routes are properly advertised to all BGP speaker
+ def test_03_check_quagga_global_rib(self):
+ for q in self.quaggas.itervalues():
+ done = False
+ for _ in range(self.retry_limit):
+ if done:
break
- else:
- retry_count += 1
- print "compare NG -> retry ( %d / %d )" % (retry_count, self.dest_check_limit)
+ global_rib = q.get_global_rib()
+ global_rib = [p['prefix'] for p in global_rib]
+ if len(global_rib) < len(self.quaggas):
time.sleep(self.wait_per_retry)
+ continue
+
+ self.assertTrue(len(global_rib) == len(self.quaggas))
+
+ for c in self.quaggas.itervalues():
+ for r in c.routes:
+ self.assertTrue(r in global_rib)
+ done = True
+ if done:
+ continue
+ # should not reach here
+ self.assertTrue(False)
+
+ def test_04_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.bridges['br01'].addif(q4)
+ self.gobgp.add_peer(q4)
+ q4.add_peer(self.gobgp)
+
+ self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q4)
+
+ def test_05_check_global_rib(self):
+ self.test_02_check_gobgp_global_rib()
+ self.test_03_check_quagga_global_rib()
+
+ def test_06_stop_one_quagga(self):
+ q4 = self.quaggas['q4']
+ q4.stop()
+ self.gobgp.wait_for(expected_state=BGP_FSM_ACTIVE, peer=q4)
+ del self.quaggas['q4']
+
+ # check gobgp properly send withdrawal message with q4's route
+ def test_07_check_global_rib(self):
+ self.test_02_check_gobgp_global_rib()
+ self.test_03_check_quagga_global_rib()
+
+ def test_08_add_distant_relative(self):
+ q1 = self.quaggas['q1']
+ q2 = self.quaggas['q2']
+ q3 = self.quaggas['q3']
+ q5 = QuaggaBGPContainer(name='q5', asn=65005, router_id='192.168.0.6')
+
+ initial_wait_time = q5.run()
+ time.sleep(initial_wait_time)
+
+ br02 = Bridge(name='br02', subnet='192.168.20.0/24')
+ br02.addif(q5)
+ br02.addif(q2)
+
+ br03 = Bridge(name='br03', subnet='192.168.30.0/24')
+ br03.addif(q5)
+ br03.addif(q3)
+
+ for q in [q2, q3]:
+ q5.add_peer(q)
+ q.add_peer(q5)
+
+ med200 = {'name': 'med200',
+ 'type': 'permit',
+ 'match': '0.0.0.0/0',
+ 'direction': 'out',
+ 'med': 200}
+ q2.add_policy(med200, self.gobgp)
+ med100 = {'name': 'med100',
+ 'type': 'permit',
+ 'match': '0.0.0.0/0',
+ 'direction': 'out',
+ 'med': 100}
+ q3.add_policy(med100, self.gobgp)
+
+ q5.add_route('10.0.6.0/24')
+
+ self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q2)
+ self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q3)
+ q2.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q5)
+ q3.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q5)
+
+ done = False
+ for _ in range(self.retry_limit):
+ paths = q1.get_global_rib('10.0.6.0/24')
+ if len(paths) > 0:
+ path = paths[0]
+ print "{0}'s nexthop is {1}".format(path['prefix'],
+ path['nexthop'])
+ n_addrs = [i[1].split('/')[0] for i in self.gobgp.ip_addrs]
+ if path['nexthop'] in n_addrs:
+ done = True
+ break
+ time.sleep(self.wait_per_retry)
+
+ if not done:
+ self.assertTrue(False)
- self.assertEqual(still_exists, False)
- self.assertEqual(cmp_result, True)
-
- def test_10_bestpath_selection_of_received_route(self):
- print "test_bestpath_selection_of_received_route"
- if self.check_load_config() is False:
- return
-
- go_path = parser_option.go_path
- fab.docker_container_make_bestpath_env_executor(self.append_quagga_best, go_path, is_route_server=False)
- print "please wait " + str(self.initial_wait_time) + " second"
- time.sleep(self.initial_wait_time)
-
- print "add neighbor setting"
- tn = qaccess.login("11.0.0.20")
- qaccess.add_neighbor(tn, "65020", "11.0.0.2", "65002")
- qaccess.add_neighbor(tn, "65020", "12.0.0.3", "65003")
-
- tn = qaccess.login("11.0.0.2")
- tn = qaccess.add_metric(tn, "200", "192.168.20.0")
- qaccess.add_neighbor(tn, "65002", "11.0.0.20", "65020")
- qaccess.add_neighbor_metric(tn, "65002", "10.0.255.1", "200")
-
- tn = qaccess.login("10.0.0.3")
- tn = qaccess.add_metric(tn, "100", "192.168.20.0")
- qaccess.add_neighbor(tn, "65003", "12.0.0.20", "65020")
- qaccess.add_neighbor_metric(tn, "65003", "10.0.255.1", "100")
-
- print "please wait " + str(self.initial_wait_time) + " second"
- time.sleep(self.initial_wait_time)
-
- target_network = "192.168.20.0/24"
- ans_nexthop = "10.0.0.3"
-
- print "check whether target network %s 's nexthop is %s" % (target_network, ans_nexthop)
- self.retry_routine_for_bestpath("", target_network, ans_nexthop)
-
- def assert_quagga_rib(self, address):
- retry_count = 0
- cmp_result = False
- while retry_count < self.dest_check_limit:
- tn = qaccess.login(address)
- q_rib = qaccess.show_rib(tn)
- cmp_result = self.compare_route_with_quagga_configs(address, q_rib, route_server=False)
-
- if cmp_result:
- print "compare OK"
- break
- else:
- retry_count += 1
- print "compare NG -> retry ( %d / %d )" % (retry_count, self.dest_check_limit)
- time.sleep(self.wait_per_retry)
- self.assertTrue(cmp_result)
-
- def assert_global_rib(self):
- retry_count = 0
- cmp_result = False
- while retry_count < self.dest_check_limit:
- rib = self.ask_gobgp(GLOBAL_RIB)
- cmp_result = self.compare_global_rib_with_quagga_configs(rib)
-
- if cmp_result:
- print "compare OK"
- break
- else:
- retry_count += 1
- print "compare NG -> retry ( %d / %d )" % (retry_count, self.dest_check_limit)
- time.sleep(self.wait_per_retry)
- self.assertTrue(cmp_result)
if __name__ == '__main__':
- if fab.test_user_check() is False:
+ if os.geteuid() is not 0:
print "you are not root."
sys.exit(1)
- if fab.docker_pkg_check() is False:
- print "not install docker package."
+ output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True)
+ if int(output) is not 0:
+ print "docker not found"
sys.exit(1)
- nose.main(argv=sys.argv, addplugins=[OptionParser()], defaultTest=sys.argv[0])
+ nose.main(argv=sys.argv, addplugins=[OptionParser()],
+ defaultTest=sys.argv[0])
diff --git a/test/scenario_test/lib/__init__.py b/test/scenario_test/lib/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/scenario_test/lib/__init__.py
diff --git a/test/scenario_test/lib/bagpipe.py b/test/scenario_test/lib/bagpipe.py
new file mode 100644
index 00000000..c73b6472
--- /dev/null
+++ b/test/scenario_test/lib/bagpipe.py
@@ -0,0 +1,73 @@
+# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from base import *
+
+
+class BagpipeContainer(BGPContainer):
+
+ SHARED_VOLUME = '/root/shared_volume'
+
+ def __init__(self, name, asn, router_id,
+ ctn_image_name='yoshima/bagpipe-bgp'):
+ super(BagpipeContainer, self).__init__(name, asn, router_id,
+ ctn_image_name)
+ self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME))
+
+ def run(self):
+ super(BagpipeContainer, self).run()
+ cmd = CmdBuffer(' ')
+ cmd << 'docker exec'
+ cmd << '{0} cp {1}/bgp.conf'.format(self.name, self.SHARED_VOLUME)
+ cmd << '/etc/bagpipe-bgp/'
+ local(str(cmd), capture=True)
+ cmd = 'docker exec {0} service bagpipe-bgp start'.format(self.name)
+ local(cmd, capture=True)
+
+ def create_config(self):
+ c = CmdBuffer()
+ c << '[BGP]'
+ if len(self.ip_addrs) > 0:
+ c << 'local_address={0}'.format(self.ip_addrs[0][1].split('/')[0])
+ for peer, info in self.peers.iteritems():
+ c << 'peers={0}'.format(info['neigh_addr'].split('/')[0])
+ c << 'my_as={0}'.format(self.asn)
+ c << 'enable_rtc=True'
+ c << '[API]'
+ c << 'api_host=localhost'
+ c << 'api_port=8082'
+ c << '[DATAPLANE_DRIVER_IPVPN]'
+ c << 'dataplane_driver = DummyDataplaneDriver'
+ c << '[DATAPLANE_DRIVER_EVPN]'
+ c << 'dataplane_driver = DummyDataplaneDriver'
+
+ with open('{0}/bgp.conf'.format(self.config_dir), 'w') as f:
+ print colors.yellow(str(c))
+ f.writelines(str(c))
+
+ def reload_config(self):
+ cmd = CmdBuffer(' ')
+ cmd << 'docker exec'
+ cmd << '{0} cp {1}/bgp.conf'.format(self.name, self.SHARED_VOLUME)
+ cmd << '/etc/bagpipe-bgp/'
+ local(str(cmd), capture=True)
+ cmd = 'docker exec {0} service bagpipe-bgp restart'.format(self.name)
+ local(cmd, capture=True)
+
+ def pipework(self, bridge, ip_addr, intf_name=""):
+ super(BagpipeContainer, self).pipework(bridge, ip_addr, intf_name)
+ self.create_config()
+ if self.is_running:
+ self.reload_config()
diff --git a/test/scenario_test/lib/base.py b/test/scenario_test/lib/base.py
new file mode 100644
index 00000000..35686973
--- /dev/null
+++ b/test/scenario_test/lib/base.py
@@ -0,0 +1,266 @@
+# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from fabric.api import local, lcd
+from fabric import colors
+from fabric.utils import indent
+
+import netaddr
+import os
+import time
+import itertools
+
+DEFAULT_TEST_BASE_DIR = '/tmp/gobgp'
+TEST_BASE_DIR = DEFAULT_TEST_BASE_DIR
+
+BGP_FSM_IDLE = 'BGP_FSM_IDLE'
+BGP_FSM_ACTIVE = 'BGP_FSM_ACTIVE'
+BGP_FSM_ESTABLISHED = 'BGP_FSM_ESTABLISHED'
+
+
+def get_bridges():
+ return local("brctl show | awk 'NR > 1{print $1}'",
+ capture=True).split('\n')
+
+
+def get_containers():
+ return local("docker ps -a | awk 'NR > 1 {print $NF}'",
+ capture=True).split('\n')
+
+
+class CmdBuffer(list):
+ def __init__(self, delim='\n'):
+ super(CmdBuffer, self).__init__()
+ self.delim = delim
+
+ def __lshift__(self, value):
+ self.append(value)
+
+ def __str__(self):
+ return self.delim.join(self)
+
+
+def make_gobgp_ctn(tag='gobgp', local_gobgp_path=''):
+ if local_gobgp_path == '':
+ local_gobgp_path = os.getcwd()
+
+ c = CmdBuffer()
+ c << 'FROM osrg/gobgp'
+ c << 'COPY gobgp /go/src/github.com/osrg/gobgp/'
+ c << 'RUN go get github.com/osrg/gobgp/gobgpd'
+ c << 'RUN go install -a github.com/osrg/gobgp/gobgpd'
+ c << 'RUN go get github.com/osrg/gobgp/gobgp'
+ c << 'RUN go install -a github.com/osrg/gobgp/gobgp'
+
+ rindex = local_gobgp_path.rindex('gobgp')
+ if rindex < 0:
+ raise Exception('{0} seems not gobgp dir'.format(local_gobgp_path))
+
+ workdir = local_gobgp_path[:rindex]
+ with lcd(workdir):
+ local('echo \'{0}\' > Dockerfile'.format(str(c)))
+ local('docker build -t {0} .'.format(tag))
+ local('rm Dockerfile')
+
+
+class Bridge(object):
+ def __init__(self, name, subnet='', with_ip=True):
+ self.name = name
+ self.with_ip = with_ip
+ if with_ip:
+ self.subnet = netaddr.IPNetwork(subnet)
+
+ def f():
+ for host in self.subnet:
+ yield host
+ self._ip_generator = f()
+ # throw away first network address
+ self.next_ip_address()
+
+ if self.name in get_bridges():
+ self.delete()
+
+ local("ip link add {0} type bridge".format(self.name), capture=True)
+ local("ip link set up dev {0}".format(self.name), capture=True)
+
+ if with_ip:
+ self.ip_addr = self.next_ip_address()
+ local("ip addr add {0} dev {1}".format(self.ip_addr, self.name),
+ capture=True)
+
+ self.ctns = []
+
+ def next_ip_address(self):
+ return "{0}/{1}".format(self._ip_generator.next(),
+ self.subnet.prefixlen)
+
+ def addif(self, ctn, name=''):
+ if name == '':
+ name = self.name
+ self.ctns.append(ctn)
+ if self.with_ip:
+ ctn.pipework(self, self.next_ip_address(), name)
+ else:
+ ctn.pipework(self, '0/0', name)
+
+ def delete(self):
+ local("ip link set down dev {0}".format(self.name), capture=True)
+ local("ip link delete {0} type bridge".format(self.name), capture=True)
+
+
+class Container(object):
+ def __init__(self, name, image):
+ self.name = name
+ self.image = image
+ self.shared_volumes = []
+ self.ip_addrs = []
+ self.is_running = False
+
+ if self.name in get_containers():
+ self.stop()
+
+ def run(self):
+ c = CmdBuffer(' ')
+ c << "docker run --privileged=true"
+ for sv in self.shared_volumes:
+ c << "-v {0}:{1}".format(sv[0], sv[1])
+ c << "--name {0} -id {1}".format(self.name, self.image)
+ self.id = local(str(c), capture=True)
+ self.is_running = True
+ self.local("ip li set up dev lo")
+ return 0
+
+ def stop(self):
+ ret = local("docker rm -f " + self.name, capture=True)
+ self.is_running = False
+ return ret
+
+ def pipework(self, bridge, ip_addr, intf_name=""):
+ if not self.is_running:
+ print colors.yellow('call run() before pipeworking')
+ return
+ c = CmdBuffer(' ')
+ c << "pipework {0}".format(bridge.name)
+
+ if intf_name != "":
+ c << "-i {0}".format(intf_name)
+ else:
+ intf_name = "eth1"
+ c << "{0} {1}".format(self.name, ip_addr)
+ self.ip_addrs.append((intf_name, ip_addr, bridge))
+ return local(str(c), capture=True)
+
+ def local(self, cmd):
+ return local("docker exec -it {0} {1}".format(self.name, cmd))
+
+
+class BGPContainer(Container):
+
+ WAIT_FOR_BOOT = 0
+ RETRY_INTERVAL = 5
+
+ def __init__(self, name, asn, router_id, ctn_image_name):
+ self.config_dir = "{0}/{1}".format(TEST_BASE_DIR, name)
+ local('if [ -e {0} ]; then rm -r {0}; fi'.format(self.config_dir))
+ local('mkdir -p {0}'.format(self.config_dir))
+ self.asn = asn
+ self.router_id = router_id
+ self.peers = {}
+ self.routes = {}
+ self.policies = {}
+ super(BGPContainer, self).__init__(name, ctn_image_name)
+
+ def run(self):
+ self.create_config()
+ super(BGPContainer, self).run()
+ return self.WAIT_FOR_BOOT
+
+ def add_peer(self, peer, passwd='', evpn=False, is_rs_client=False,
+ policies=None, passive=False,
+ is_rr_client=False, cluster_id=''):
+ neigh_addr = ''
+ for me, you in itertools.product(self.ip_addrs, peer.ip_addrs):
+ if me[2] == you[2]:
+ neigh_addr = you[1]
+
+ if neigh_addr == '':
+ raise Exception('peer {0} seems not ip reachable'.format(peer))
+
+ if not policies:
+ policies = []
+
+ self.peers[peer] = {'neigh_addr': neigh_addr,
+ 'passwd': passwd,
+ 'evpn': evpn,
+ 'is_rs_client': is_rs_client,
+ 'is_rr_client': is_rr_client,
+ 'cluster_id': cluster_id,
+ 'policies': policies,
+ 'passive': passive}
+ if self.is_running:
+ self.create_config()
+ self.reload_config()
+
+ def del_peer(self, peer):
+ del self.peers[peer]
+ if self.is_running:
+ self.create_config()
+ self.reload_config()
+
+ def add_route(self, route, attribute=''):
+ self.routes[route] = attribute
+ if self.is_running:
+ self.create_config()
+ self.reload_config()
+
+ def add_policy(self, policy, peer=None):
+ self.policies[policy['name']] = policy
+ if peer in self.peers:
+ self.peers[peer]['policies'].append(policy)
+ if self.is_running:
+ self.create_config()
+ self.reload_config()
+
+ def get_local_rib(self, peer, rf):
+ raise Exception('implement get_local_rib() method')
+
+ def get_global_rib(self, rf):
+ raise Exception('implement get_global_rib() method')
+
+ def get_neighbor_state(self, peer_id):
+ raise Exception('implement get_neighbor() method')
+
+ def wait_for(self, expected_state, peer, timeout=10):
+ interval = 1
+ count = 0
+ while True:
+ state = self.get_neighbor_state(peer)
+ y = colors.yellow
+ print y("{0}'s peer {1} state: {2}".format(self.router_id,
+ peer.router_id,
+ state))
+ if state == expected_state:
+ return
+
+ time.sleep(interval)
+ count += interval
+ if count >= timeout:
+ raise Exception('timeout')
+
+ def create_config(self):
+ raise Exception('implement create_config() method')
+
+ def reload_config(self):
+ raise Exception('implement reload_config() method')
diff --git a/test/scenario_test/lib/exabgp.py b/test/scenario_test/lib/exabgp.py
new file mode 100644
index 00000000..91919101
--- /dev/null
+++ b/test/scenario_test/lib/exabgp.py
@@ -0,0 +1,99 @@
+# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from base import *
+
+
+class ExaBGPContainer(BGPContainer):
+
+ SHARED_VOLUME = '/root/shared_volume'
+
+ def __init__(self, name, asn, router_id, ctn_image_name='osrg/exabgp',
+ exabgp_path=''):
+ super(ExaBGPContainer, self).__init__(name, asn, router_id,
+ ctn_image_name)
+ self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME))
+ self.exabgp_path = exabgp_path
+
+ def _start_exabgp(self):
+ cmd = CmdBuffer(' ')
+ cmd << 'docker exec -d {0}'.format(self.name)
+ cmd << 'env exabgp.log.destination={0}/exabgpd.log'.format(self.SHARED_VOLUME)
+ cmd << './exabgp/sbin/exabgp {0}/exabgpd.conf'.format(self.SHARED_VOLUME)
+ local(str(cmd), capture=True)
+
+ def _update_exabgp(self):
+ c = CmdBuffer()
+ c << '#!/bin/bash'
+
+ remotepath = '/root/exabgp'
+ localpath = self.exabgp_path
+ if localpath != '':
+ local('cp -r {0} {1}'.format(localpath, self.config_dir))
+ c << 'cp {0}/etc/exabgp/exabgp.env {1}'.format(remotepath, self.SHARED_VOLUME)
+ c << 'sed -i -e \'s/all = false/all = true/g\' {0}/exabgp.env'.format(self.SHARED_VOLUME)
+ c << 'cp -r {0}/exabgp {1}'.format(self.SHARED_VOLUME,
+ remotepath[:-1*len('exabgp')])
+ c << 'cp {0}/exabgp.env {1}/etc/exabgp/'.format(self.SHARED_VOLUME, remotepath)
+ cmd = 'echo "{0:s}" > {1}/update.sh'.format(c, self.config_dir)
+ local(cmd, capture=True)
+ cmd = 'chmod 755 {0}/update.sh'.format(self.config_dir)
+ local(cmd, capture=True)
+ cmd = 'docker exec {0} {1}/update.sh'.format(self.name,
+ self.SHARED_VOLUME)
+ local(cmd, capture=True)
+
+ def run(self):
+ super(ExaBGPContainer, self).run()
+ self._update_exabgp()
+ self._start_exabgp()
+ return self.WAIT_FOR_BOOT
+
+ def create_config(self):
+ cmd = CmdBuffer()
+ for peer, info in self.peers.iteritems():
+ cmd << 'neighbor {0} {{'.format(info['neigh_addr'].split('/')[0])
+ cmd << ' router-id {0};'.format(self.router_id)
+
+ local_addr = ''
+ for me, you in itertools.product(self.ip_addrs, peer.ip_addrs):
+ if me[2] == you[2]:
+ local_addr = me[1]
+ if local_addr == '':
+ raise Exception('local_addr not found')
+ local_addr = local_addr.split('/')[0]
+ cmd << ' local-address {0};'.format(local_addr)
+ cmd << ' local-as {0};'.format(self.asn)
+ cmd << ' peer-as {0};'.format(peer.asn)
+
+ cmd << ' static {'
+ for route, attr in self.routes.iteritems():
+ if attr == '':
+ cmd << ' route {0} next-hop {1};'.format(route, local_addr)
+ else:
+ cmd << ' route {0} next-hop {1} attribute {2};'.format(route, local_addr, attr)
+ cmd << ' }'
+ cmd << '}'
+
+ with open('{0}/exabgpd.conf'.format(self.config_dir), 'w') as f:
+ print colors.yellow(str(cmd))
+ f.write(str(cmd))
+
+ def reload_config(self):
+ cmd = 'docker exec {0} /usr/bin/pkill exabgp -SIGALRM'.format(self.name)
+ try:
+ local(cmd, capture=True)
+ except:
+ self._start_exabgp()
diff --git a/test/scenario_test/lib/gobgp.py b/test/scenario_test/lib/gobgp.py
new file mode 100644
index 00000000..d9115f1b
--- /dev/null
+++ b/test/scenario_test/lib/gobgp.py
@@ -0,0 +1,175 @@
+# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from base import *
+import json
+import toml
+import subprocess
+import select
+
+
+class GoBGPContainer(BGPContainer):
+
+ PEER_TYPE_INTERNAL = 0
+ PEER_TYPE_EXTERNAL = 1
+ SHARED_VOLUME = '/root/shared_volume'
+
+ def __init__(self, name, asn, router_id, ctn_image_name='gobgp',
+ log_level='debug'):
+ super(GoBGPContainer, self).__init__(name, asn, router_id,
+ ctn_image_name)
+ self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME))
+ self.log_level = log_level
+
+ def _start_gobgp(self):
+ c = CmdBuffer()
+ c << '#!/bin/bash'
+ c << '/go/bin/gobgpd -f {0}/gobgpd.conf -l {1} -p > ' \
+ '{0}/gobgpd.log 2>&1'.format(self.SHARED_VOLUME, self.log_level)
+
+ cmd = 'echo "{0:s}" > {1}/start.sh'.format(c, self.config_dir)
+ local(cmd, capture=True)
+ cmd = "chmod 755 {0}/start.sh".format(self.config_dir)
+ local(cmd, capture=True)
+ cmd = 'docker exec -d {0} {1}/start.sh'.format(self.name,
+ self.SHARED_VOLUME)
+ local(cmd, capture=True)
+
+ def run(self):
+ super(GoBGPContainer, self).run()
+ self._start_gobgp()
+ return self.WAIT_FOR_BOOT
+
+ def get_local_rib(self, peer, rf='ipv4'):
+ if peer not in self.peers:
+ raise Exception('not found peer {0}'.format(peer.router_id))
+ peer_addr = self.peers[peer]['neigh_addr'].split('/')[0]
+ gobgp = '/go/bin/gobgp'
+ cmd = CmdBuffer(' ')
+ cmd << "docker exec {0} {1}".format(self.name, gobgp)
+ cmd << "-j neighbor {0} local -a {1}".format(peer_addr, rf)
+ output = local(str(cmd), capture=True)
+ n = json.loads(output)
+ return n
+
+ def get_global_rib(self, prefix='', rf='ipv4'):
+ gobgp = '/go/bin/gobgp'
+ cmd = 'docker exec {0} {1} -j global rib {2} -a {3}'.format(self.name,
+ gobgp,
+ prefix,
+ rf)
+
+ output = local(cmd, capture=True)
+ n = json.loads(output)
+ return n
+
+ def get_neighbor_state(self, peer):
+ if peer not in self.peers:
+ raise Exception('not found peer {0}'.format(peer.router_id))
+ peer_addr = self.peers[peer]['neigh_addr'].split('/')[0]
+ gobgp = '/go/bin/gobgp'
+ cmd = 'docker exec {0} {1} -j neighbor {2}'.format(self.name,
+ gobgp,
+ peer_addr)
+ output = local(cmd, capture=True)
+ return json.loads(output)['info']['bgp_state']
+
+ def wait_for(self, expected_state, peer, timeout=20):
+ state = self.get_neighbor_state(peer)
+ y = colors.yellow
+ print y("{0}'s peer {1} state: {2}".format(self.router_id,
+ peer.router_id,
+ state))
+ if state == expected_state:
+ return
+
+ peer_addr = self.peers[peer]['neigh_addr'].split('/')[0]
+ gobgp = '/go/bin/gobgp'
+ cmd = 'docker exec {0} {1} monitor neighbor {2} -j'.format(self.name,
+ gobgp,
+ peer_addr)
+ process = subprocess.Popen(cmd, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ poll = select.epoll()
+ poll.register(process.stdout, select.POLLIN)
+
+ while True:
+ result = poll.poll(float(timeout))
+ if result:
+ line = process.stdout.readline()
+ info = json.loads(line)['info']
+ print y("{0}'s peer {1} state: {2}".format(self.router_id,
+ peer.router_id,
+ info['bgp_state']))
+ if info['bgp_state'] == expected_state:
+ return
+ continue
+ raise Exception('timeout')
+
+
+ def create_config(self):
+ config = {'Global': {'As': self.asn, 'RouterId': self.router_id}}
+ for peer, info in self.peers.iteritems():
+ if self.asn == peer.asn:
+ peer_type = self.PEER_TYPE_INTERNAL
+ else:
+ peer_type = self.PEER_TYPE_EXTERNAL
+
+ afi_safi_list = []
+ version = netaddr.IPNetwork(info['neigh_addr']).version
+ if version == 4:
+ afi_safi_list.append({'AfiSafiName': 'ipv4-unicast'})
+ elif version == 6:
+ afi_safi_list.append({'AfiSafiName': 'ipv6-unicast'})
+ else:
+ Exception('invalid ip address version. {0}'.format(version))
+
+ if info['evpn']:
+ afi_safi_list.append({'AfiSafiName': 'l2vpn-evpn'})
+ afi_safi_list.append({'AfiSafiName': 'encap'})
+ afi_safi_list.append({'AfiSafiName': 'rtc'})
+
+ n = {'NeighborAddress': info['neigh_addr'].split('/')[0],
+ 'PeerAs': peer.asn,
+ 'AuthPassword': info['passwd'],
+ 'PeerType': peer_type,
+ 'AfiSafiList': afi_safi_list}
+
+ if info['passive']:
+ n['TransportOptions'] = {'PassiveMode': True}
+
+ if info['is_rs_client']:
+ n['RouteServer'] = {'RouteServerClient': True}
+
+ if info['is_rr_client']:
+ clusterId = info['cluster_id']
+ n['RouteReflector'] = {'RouteReflectorClient': True,
+ 'RouteReflectorClusterId': clusterId}
+
+ if 'NeighborList' not in config:
+ config['NeighborList'] = []
+
+ config['NeighborList'].append(n)
+
+ with open('{0}/gobgpd.conf'.format(self.config_dir), 'w') as f:
+ print colors.yellow('[{0}\'s new config]'.format(self.name))
+ print colors.yellow(indent(toml.dumps(config)))
+ f.write(toml.dumps(config))
+
+ def reload_config(self):
+ cmd = 'docker exec {0} /usr/bin/pkill gobgpd -SIGHUP'.format(self.name)
+ local(cmd, capture=True)
diff --git a/test/scenario_test/lib/quagga.py b/test/scenario_test/lib/quagga.py
new file mode 100644
index 00000000..75c2f61c
--- /dev/null
+++ b/test/scenario_test/lib/quagga.py
@@ -0,0 +1,193 @@
+# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from base import *
+import telnetlib
+
+
+class QuaggaTelnetDaemon(object):
+ TELNET_PASSWORD = "zebra"
+ TELNET_PORT = 2605
+
+ def __init__(self, ctn):
+ ip_addr = None
+ for _, ip_addr, br in ctn.ip_addrs:
+ if br.ip_addr:
+ break
+
+ if not ip_addr:
+ Exception('quagga telnet daemon {0}'
+ ' is not ip reachable'.format(self.name))
+
+ self.host = ip_addr.split('/')[0]
+
+ def __enter__(self):
+ self.tn = telnetlib.Telnet(self.host, self.TELNET_PORT)
+ self.tn.read_until("Password: ")
+ self.tn.write(self.TELNET_PASSWORD + "\n")
+ self.tn.write("enable\n")
+ self.tn.read_until('bgpd#')
+ return self.tn
+
+ def __exit__(self, type, value, traceback):
+ self.tn.close()
+
+
+class QuaggaBGPContainer(BGPContainer):
+
+ WAIT_FOR_BOOT = 1
+ SHARED_VOLUME = '/etc/quagga'
+
+ def __init__(self, name, asn, router_id, ctn_image_name='osrg/quagga'):
+ super(QuaggaBGPContainer, self).__init__(name, asn, router_id,
+ ctn_image_name)
+ self.shared_volumes.append((self.config_dir, self.SHARED_VOLUME))
+
+ def run(self):
+ super(QuaggaBGPContainer, self).run()
+ return self.WAIT_FOR_BOOT
+
+ def get_global_rib(self, prefix='', rf='ipv4'):
+ rib = []
+ if prefix != '':
+ return self.get_global_rib_with_prefix(prefix, rf)
+ with QuaggaTelnetDaemon(self) as tn:
+ tn.write('show bgp {0} unicast\n'.format(rf))
+ tn.read_until(' Network Next Hop Metric '
+ 'LocPrf Weight Path')
+ for line in tn.read_until('bgpd#').split('\n'):
+ if line[0] == '*':
+ elems = line.split()
+ rib.append({'prefix': elems[1], 'nexthop': elems[2]})
+
+ return rib
+
+ def get_global_rib_with_prefix(self, prefix, rf):
+ rib = []
+ with QuaggaTelnetDaemon(self) as tn:
+ tn.write('show bgp {0} unicast {1}\n'.format(rf, prefix))
+ lines = [line.strip() for line in tn.read_until('bgpd#').split('\n')]
+ lines.pop(0) # throw away first line contains 'show bgp...'
+ if lines[0] == '% Network not in table':
+ return rib
+
+ lines = lines[2:]
+
+ if lines[0].startswith('Not advertised'):
+ lines.pop(0) # another useless line
+ elif lines[0].startswith('Advertised to non peer-group peers:'):
+ lines = lines[2:] # other useless lines
+ else:
+ raise Exception('unknown output format {0}'.format(lines))
+ nexthop = lines[1].split()[0].strip()
+ aspath = [int(asn) for asn in lines[0].split()]
+ rib.append({'prefix': prefix, 'nexthop': nexthop,
+ 'aspath': aspath})
+ return rib
+
+ def get_neighbor_state(self, peer):
+ if peer not in self.peers:
+ raise Exception('not found peer {0}'.format(peer.router_id))
+
+ neigh_addr = self.peers[peer]['neigh_addr'].split('/')[0]
+
+ with QuaggaTelnetDaemon(self) as tn:
+ tn.write('show bgp neighbors\n')
+ neighbor_info = []
+ curr_info = []
+ for line in tn.read_until('bgpd#').split('\n'):
+ line = line.strip()
+ if line.startswith('BGP neighbor is'):
+ neighbor_info.append(curr_info)
+ curr_info = []
+ curr_info.append(line)
+ neighbor_info.append(curr_info)
+
+ for info in neighbor_info:
+ if not info[0].startswith('BGP neighbor is'):
+ continue
+ idx1 = info[0].index('BGP neighbor is ')
+ idx2 = info[0].index(',')
+ n_addr = info[0][idx1+len('BGP neighbor is '):idx2]
+ if n_addr == neigh_addr:
+ idx1 = info[2].index('= ')
+ state = info[2][idx1+len('= '):]
+ if state.startswith('Idle'):
+ return BGP_FSM_IDLE
+ elif state.startswith('Active'):
+ return BGP_FSM_ACTIVE
+ elif state.startswith('Established'):
+ return BGP_FSM_ESTABLISHED
+ else:
+ return state
+
+ raise Exception('not found peer {0}'.format(peer.router_id))
+
+ def create_config(self):
+ c = CmdBuffer()
+ c << 'hostname bgpd'
+ c << 'password zebra'
+ c << 'router bgp {0}'.format(self.asn)
+ c << 'bgp router-id {0}'.format(self.router_id)
+
+ for peer, info in self.peers.iteritems():
+ version = netaddr.IPNetwork(info['neigh_addr']).version
+ n_addr = info['neigh_addr'].split('/')[0]
+ if version == 6:
+ c << 'no bgp default ipv4-unicast'
+
+ c << 'neighbor {0} remote-as {1}'.format(n_addr, peer.asn)
+ for policy in info['policies']:
+ name = policy['name']
+ direction = policy['direction']
+ c << 'neighbor {0} route-map {1} {2}'.format(n_addr, name,
+ direction)
+ if info['passwd'] != '':
+ c << 'neighbor {0} password {1}'.format(n_addr, info['passwd'])
+ if version == 6:
+ c << 'address-family ipv6 unicast'
+ c << 'neighbor {0} activate'.format(n_addr)
+ c << 'exit-address-family'
+
+ for route in self.routes.iterkeys():
+ version = netaddr.IPNetwork(route).version
+ if version == 4:
+ c << 'network {0}'.format(route)
+ elif version == 6:
+ c << 'address-family ipv6 unicast'
+ c << 'network {0}'.format(route)
+ c << 'exit-address-family'
+
+ for name, policy in self.policies.iteritems():
+ c << 'access-list {0} {1} {2}'.format(name, policy['type'],
+ policy['match'])
+ c << 'route-map {0} permit 10'.format(name)
+ c << 'match ip address {0}'.format(name)
+ c << 'set metric {0}'.format(policy['med'])
+
+ c << 'debug bgp as4'
+ c << 'debug bgp fsm'
+ c << 'debug bgp updates'
+ c << 'debug bgp events'
+ c << 'log file {0}/bgpd.log'.format(self.SHARED_VOLUME)
+
+ with open('{0}/bgpd.conf'.format(self.config_dir), 'w') as f:
+ print colors.yellow('[{0}\'s new config]'.format(self.name))
+ print colors.yellow(indent(str(c)))
+ f.writelines(str(c))
+
+ def reload_config(self):
+ cmd = 'docker exec {0} /usr/bin/pkill bgpd -SIGHUP'.format(self.name)
+ local(cmd, capture=True)
diff --git a/test/scenario_test/noseplugin.py b/test/scenario_test/noseplugin.py
index a0cedb80..1eae95bb 100644
--- a/test/scenario_test/noseplugin.py
+++ b/test/scenario_test/noseplugin.py
@@ -11,7 +11,8 @@ class OptionParser(Plugin):
parser.add_option('--use-local', action="store_true", dest="use_local", default=False)
parser.add_option('--exabgp-path', action="store", dest="exabgp_path", default="")
parser.add_option('--go-path', action="store", dest="go_path", default="")
- parser.add_option('--gobgp-log-debug', action="store_true", dest="gobgp_log_debug", default=False)
+ parser.add_option('--gobgp-log-level', action="store",
+ dest="gobgp_log_level", default="info")
def configure(self, options, conf):
super(OptionParser, self).configure(options, conf)
@@ -22,4 +23,4 @@ class OptionParser(Plugin):
return
def finalize(self, result):
- pass \ No newline at end of file
+ pass
diff --git a/test/scenario_test/route_server_ipv4_v6_test.py b/test/scenario_test/route_server_ipv4_v6_test.py
index bf47c516..bc9e234d 100644
--- a/test/scenario_test/route_server_ipv4_v6_test.py
+++ b/test/scenario_test/route_server_ipv4_v6_test.py
@@ -39,7 +39,7 @@ class GoBGPIPv6Test(GoBGPTestBase):
use_local = parser_option.use_local
go_path = parser_option.go_path
- log_debug = parser_option.gobgp_log_debug
+ log_debug = True if parser_option.gobgp_log_level == 'debug' else False
fab.init_ipv6_test_env_executor(self.quagga_num, use_local, go_path, log_debug)
print "please wait (" + str(self.initial_wait_time) + " second)"
time.sleep(self.initial_wait_time)
diff --git a/test/scenario_test/route_server_malformed_test.py b/test/scenario_test/route_server_malformed_test.py
index ac3d1186..75c641c2 100644
--- a/test/scenario_test/route_server_malformed_test.py
+++ b/test/scenario_test/route_server_malformed_test.py
@@ -73,7 +73,7 @@ def test_malformed_packet():
sys.exit(1)
use_local = parser_option.use_local
- log_debug = parser_option.gobgp_log_debug
+ log_debug = True if parser_option.gobgp_log_level == 'debug' else False
go_path = parser_option.go_path
exabgp_path = parser_option.exabgp_path
diff --git a/test/scenario_test/route_server_policy_test.py b/test/scenario_test/route_server_policy_test.py
index 737c9a05..cfbdddd3 100644
--- a/test/scenario_test/route_server_policy_test.py
+++ b/test/scenario_test/route_server_policy_test.py
@@ -65,7 +65,7 @@ class GoBGPTest(GoBGPTestBase):
print 'prepare gobgp'
cls.go_path = parser_option.go_path
cls.use_local = parser_option.use_local
- cls.log_debug = parser_option.gobgp_log_debug
+ cls.log_debug = True if parser_option.gobgp_log_level == 'debug' else False
fab.prepare_gobgp(cls.log_debug, cls.use_local)
fab.build_config_tools(cls.go_path)
diff --git a/test/scenario_test/route_server_test.py b/test/scenario_test/route_server_test.py
index 61c94eb0..63063d50 100644
--- a/test/scenario_test/route_server_test.py
+++ b/test/scenario_test/route_server_test.py
@@ -39,7 +39,7 @@ class GoBGPTest(GoBGPTestBase):
use_local = parser_option.use_local
go_path = parser_option.go_path
- log_debug = parser_option.gobgp_log_debug
+ log_debug = True if parser_option.gobgp_log_level == 'debug' else False
fab.init_test_env_executor(self.quagga_num, use_local, go_path, log_debug)
print "please wait " + str(self.initial_wait_time) + " second"