diff options
-rw-r--r-- | test/scenario_test/route_server_policy_test.py | 443 | ||||
-rw-r--r-- | test/scenario_test/scenario_test_util.py | 201 |
2 files changed, 644 insertions, 0 deletions
diff --git a/test/scenario_test/route_server_policy_test.py b/test/scenario_test/route_server_policy_test.py new file mode 100644 index 00000000..42d74d9e --- /dev/null +++ b/test/scenario_test/route_server_policy_test.py @@ -0,0 +1,443 @@ +# Copyright (C) 2014,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. + +import unittest +import requests +import json +import toml +import os +import time +import sys +import nose +import quagga_access as qaccess +from peer_info import Peer +from peer_info import Destination +from peer_info import Path +from ciscoconfparse import CiscoConfParse +import docker_control as fab +from noseplugin import OptionParser +from noseplugin import parser_option +import scenario_test_util as util + + +class GoBGPTest(unittest.TestCase): + + gobgp_ip = "10.0.255.1" + gobgp_port = "8080" + rest_url_neighbor = "http://" + gobgp_ip + ":" + gobgp_port + "/v1/bgp/neighbor/" + base_dir = "/tmp/gobgp/" + gobgp_config_file = "/tmp/gobgp/gobgpd.conf" + gobgp_config = None + quagga_num = 3 + initial_wait_time = 10 + wait_per_retry = 5 + + def __init__(self, *args, **kwargs): + super(GoBGPTest, self).__init__(*args, **kwargs) + + def setUp(self): + self.quagga_configs = [] + + def initialize(self, policy_pattern=None): + use_local = parser_option.use_local + go_path = parser_option.go_path + log_debug = parser_option.gobgp_log_debug + fab.init_policy_test_env_executor(self.quagga_num, use_local, go_path, log_debug, policy=policy_pattern) + print "please wait " + str(self.initial_wait_time) + " second" + time.sleep(self.initial_wait_time) + + self.assertTrue(self.check_load_config()) + + def check_established(self, addresses): + for address in addresses: + result = self.retry_until(address, target_state="BGP_FSM_ESTABLISHED",retry=10) + self.assertEqual(result, True) + + + """ + import-policy test + --------------------------------------- + peer2 ->(192.168.2.0/24)->| -> peer1-rib -> peer1-adj-rib-out | --> peer1 + | | + | ->x peer3-rib | + --------------------------------------- + """ + def test_01_import_policy_initial(self): + + # initialize test environment + # policy_pattern:p1 attaches a policy to reject route 192.168.0.0/16 (16...24) + # coming from peer2(10.0.0.2) to peer3(10.0.0.3)'s import-policy. + self.initialize(policy_pattern="p1") + self.check_established(util.get_neighbor_address(self.gobgp_config)) + + peer1 = "10.0.0.1" + peer2 = "10.0.0.2" + peer3 = "10.0.0.3" + base_url = self.rest_url_neighbor + w = self.wait_per_retry + + path = util.get_paths_in_localrib(base_url, peer1, "192.168.2.0", retry=3, interval=w) + self.assertIsNotNone(path) + + # check show ip bgp on peer1(quagga1) + qpath = util.get_routing_table(peer1,"192.168.2.0", retry=3, interval=w) + print qpath + self.assertIsNotNone(qpath) + + # check adj-rib-out in peer2 + path = util.get_adj_rib_in(base_url, peer2, "192.168.2.0/24", retry=3, interval=w) + # print path + self.assertIsNotNone(path) + + path = util.get_paths_in_localrib(base_url, peer3, "192.168.2.0",retry=0, interval=w) + # print path + self.assertIsNone(path) + + # check show ip bgp on peer1(quagga3) + qpath = util.get_routing_table(peer3,"192.168.2.0", retry=3, interval=w) + # print qpath + self.assertIsNone(qpath) + + + """ + export-policy test + --------------------------------------- + peer2 ->(192.168.2.0/24)->| -> peer1-rib -> peer1-adj-rib-out | --> peer1 + | | + | -> peer3-rib ->x peer3-adj-rib-out | + --------------------------------------- + """ + def test_02_export_policy_initial(self): + + # initialize test environment + # policy_pattern:p1 attaches a policy to reject route 192.168.0.0/16 (16...24) + # coming from peer2(10.0.0.2) to peer3(10.0.0.3)'s export-policy. + self.initialize(policy_pattern="p2") + self.check_established(util.get_neighbor_address(self.gobgp_config)) + + peer1 = "10.0.0.1" + peer2 = "10.0.0.2" + peer3 = "10.0.0.3" + base_url = self.rest_url_neighbor + w = self.wait_per_retry + + paths = util.get_paths_in_localrib(base_url, peer1, "192.168.2.0", retry=3, interval=w) + # print paths + self.assertIsNotNone(paths) + + # check show ip bgp on peer1(quagga1) + qpath = util.get_routing_table(peer1, "192.168.2.0", retry=3, interval=w) + # print qpath + self.assertIsNotNone(qpath) + + # check adj-rib-out in peer2 + path = util.get_adj_rib_in(base_url, peer2, "192.168.2.0/24", retry=1, interval=w) + # print path + self.assertIsNotNone(path) + + path = util.get_paths_in_localrib(base_url, peer3, "192.168.2.0") + # print path + self.assertIsNotNone(path) + + path = util.get_adj_rib_out(base_url, peer3, "192.168.2.0", retry=1, interval=w) + # print path + self.assertIsNone(path) + + # check show ip bgp on peer1(quagga3) + qpath = util.get_routing_table(peer3,"192.168.2.0", retry=3, interval=w) + # print qpath + self.assertIsNone(qpath) + + + """ + import-policy test + r1:192.168.2.0 + r2:192.168.20.0 + r3:192.168.200.0 + ------------------------------------------------- + |peer1 | + peer2 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> peer1 + | | + |peer3 | + | ->(r1)-> rib ->(r1)-> adj-rib-out | ->(r1)-> peer3 + ------------------------------------------------- + | + update gobgp.conf + | + V + ------------------------------------------------- + |peer1 | + peer2 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> peer1 + | | + |peer3 | + | ->(r1,r3)-> rib ->(r1,r3)-> adj-rib-out | ->(r1,r3)-> peer3 + ------------------------------------------------- + """ + def test_03_import_policy_update(self): + # initialize test environment + # policy_pattern:p3 attaches a policy to reject route + # 192.168.2.0/24, 192.168.20.0/24, 192.168.200.0/24 + # coming from peer2(10.0.0.2) to peer3(10.0.0.3)'s import-policy. + self.initialize(policy_pattern="p3") + + peer1 = "10.0.0.1" + peer2 = "10.0.0.2" + peer3 = "10.0.0.3" + base_url = self.rest_url_neighbor + w = self.wait_per_retry + + # add other network + tn = qaccess.login(peer2) + print "add network 192.168.20.0/24" + qaccess.add_network(tn, 65002, "192.168.20.0/24") + print "add network 192.168.200.0/24" + qaccess.add_network(tn, 65002, "192.168.200.0/24") + qaccess.logout(tn) + + self.check_established(util.get_neighbor_address(self.gobgp_config)) + + time.sleep(self.initial_wait_time) + + def path_exists_in_localrib(peer, prefix,r=10): + paths = util.get_paths_in_localrib(base_url, peer, prefix, retry=r, interval=w) + return paths is not None + + def path_exists_in_routing_table(peer, prefix,r=10): + qpath = util.get_routing_table(peer, prefix, retry=r, interval=w) + return qpath is not None + + def path_exists_in_adj_rib_in(peer, prefix,r=10): + path = util.get_adj_rib_in(base_url, peer, prefix, retry=r, interval=w) + return path is not None + + + self.assertTrue(path_exists_in_localrib(peer1,"192.168.2.0")) + self.assertTrue(path_exists_in_localrib(peer1,"192.168.20.0")) + self.assertTrue(path_exists_in_localrib(peer1,"192.168.200.0")) + + self.assertTrue(path_exists_in_localrib(peer3,"192.168.2.0")) + self.assertFalse(path_exists_in_localrib(peer3,"192.168.20.0",r=3)) + self.assertFalse(path_exists_in_localrib(peer3,"192.168.200.0",r=0)) + + # check show ip bgp on peer1(quagga1) + self.assertTrue(path_exists_in_routing_table(peer1, "192.168.2.0")) + self.assertTrue(path_exists_in_routing_table(peer1, "192.168.20.0")) + self.assertTrue(path_exists_in_routing_table(peer1, "192.168.200.0")) + + # check show ip bgp on peer3(quagga3) + self.assertTrue(path_exists_in_routing_table(peer3, "192.168.2.0")) + self.assertFalse(path_exists_in_routing_table(peer3, "192.168.20.0",r=3)) + self.assertFalse(path_exists_in_routing_table(peer3, "192.168.200.0",r=0)) + + # check adj-rib-out in peer2 + self.assertTrue(path_exists_in_adj_rib_in(peer2, "192.168.2.0/24")) + self.assertTrue(path_exists_in_adj_rib_in(peer2, "192.168.20.0/24")) + self.assertTrue(path_exists_in_adj_rib_in(peer2, "192.168.200.0/24")) + + # update policy + print "update_policy_config" + fab.update_policy_config(parser_option.go_path, policy_pattern="p3") + time.sleep(self.initial_wait_time) + + # soft reset + print "soft_reset" + self.soft_reset(peer2, "ipv4") + + # check local-rib + self.assertTrue(path_exists_in_localrib(peer3,"192.168.2.0")) + self.assertFalse(path_exists_in_localrib(peer3,"192.168.20.0",r=3)) + self.assertTrue(path_exists_in_localrib(peer3,"192.168.200.0")) + + # check show ip bgp on peer3(quagga3) + self.assertTrue(path_exists_in_routing_table(peer3, "192.168.2.0")) + self.assertFalse(path_exists_in_routing_table(peer3, "192.168.20.0",r=0)) + self.assertTrue(path_exists_in_routing_table(peer3, "192.168.200.0")) + + + """ + export-policy test + r1:192.168.2.0 + r2:192.168.20.0 + r3:192.168.200.0 + ------------------------------------------------- + |peer1 | + peer2 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> peer1 + | | + |peer3 | + | ->(r1,r2,r3)-> rib ->(r1)-> adj-rib-out | ->(r1)-> peer3 + ------------------------------------------------- + | + update gobgp.conf + | + V + ------------------------------------------------- + |peer1 | + peer2 ->(r1,r2,r3)-> | ->(r1,r2,r3)-> rib ->(r1,r2,r3)-> adj-rib-out | ->(r1,r2,r3)-> peer1 + | | + |peer3 | + | ->(r1,r2,r3)-> rib ->(r1,r3)-> adj-rib-out | ->(r1,r3)-> peer3 + ------------------------------------------------- + """ + @nose.tools.nottest + def test_04_export_policy_update(self): + # initialize test environment + # policy_pattern:p4 attaches a policy to reject route + # 192.168.2.0/24, 192.168.20.0/24, 192.168.200.0/24 + # coming from peer2(10.0.0.2) to peer3(10.0.0.3)'s export-policy. + self.initialize(policy_pattern="p4") + + peer1 = "10.0.0.1" + peer2 = "10.0.0.2" + peer3 = "10.0.0.3" + base_url = self.rest_url_neighbor + w = self.wait_per_retry + + # add other network + tn = qaccess.login(peer2) + print "add network 192.168.20.0/24" + qaccess.add_network(tn, 65002, "192.168.20.0/24") + print "add network 192.168.200.0/24" + qaccess.add_network(tn, 65002, "192.168.200.0/24") + qaccess.logout(tn) + + self.check_established(self.get_neighbor_address(self.gobgp_config)) + + time.sleep(self.initial_wait_time) + + + def path_exists_in_localrib(peer, prefix,r=10): + paths = util.get_paths_in_localrib(base_url, peer, prefix, retry=r, interval=w) + return paths is not None + + def path_exists_in_routing_table(peer, prefix,r=10): + qpath = util.get_routing_table(peer, prefix, retry=r, interval=w) + return qpath is not None + + def path_exists_in_adj_rib_in(peer, prefix,r=10): + path = util.get_adj_rib_in(base_url, peer, prefix, retry=r, interval=w) + return path is not None + + def path_exists_in_adj_rib_out(peer, prefix,r=10): + path = util.get_adj_rib_out(base_url, peer, prefix, retry=r, interval=w) + return path is not None + + + self.assertTrue(path_exists_in_localrib(peer1,"192.168.2.0")) + self.assertTrue(path_exists_in_localrib(peer1,"192.168.20.0")) + self.assertTrue(path_exists_in_localrib(peer1,"192.168.200.0")) + + # check peer3 local-rib + self.assertTrue(path_exists_in_localrib(peer3,"192.168.2.0")) + self.assertTrue(path_exists_in_localrib(peer3,"192.168.20.0")) + self.assertTrue(path_exists_in_localrib(peer3,"192.168.200.0")) + + # check peer3 rib-out + self.assertTrue(path_exists_in_adj_rib_out(peer3,"192.168.2.0/24")) + self.assertFalse(path_exists_in_adj_rib_out(peer3,"192.168.20.0/24",r=3)) + self.assertFalse(path_exists_in_adj_rib_out(peer3,"192.168.200.0/24",r=3)) + + # check show ip bgp on peer1(quagga1) + self.assertTrue(path_exists_in_routing_table(peer1, "192.168.2.0")) + self.assertTrue(path_exists_in_routing_table(peer1, "192.168.20.0")) + self.assertTrue(path_exists_in_routing_table(peer1, "192.168.200.0")) + + # check show ip bgp on peer3(quagga3) + self.assertTrue(path_exists_in_routing_table(peer3, "192.168.2.0")) + self.assertFalse(path_exists_in_routing_table(peer3, "192.168.20.0",r=3)) + self.assertFalse(path_exists_in_routing_table(peer3, "192.168.200.0",r=0)) + + # check adj-rib-out in peer2 + peer2 = "10.0.0.2" + self.assertTrue(path_exists_in_adj_rib_in(peer2, "192.168.2.0/24")) + self.assertTrue(path_exists_in_adj_rib_in(peer2, "192.168.20.0/24")) + self.assertTrue(path_exists_in_adj_rib_in(peer2, "192.168.200.0/24")) + + # update policy + print "update_policy_config" + fab.update_policy_config(parser_option.go_path, policy_pattern="p4") + time.sleep(self.initial_wait_time) + + # soft reset + print "soft_reset" + self.soft_reset(peer2, "ipv4") + + # check local-rib + self.assertTrue(path_exists_in_localrib(peer3,"192.168.2.0")) + self.assertTrue(path_exists_in_localrib(peer3,"192.168.20.0")) + self.assertTrue(path_exists_in_localrib(peer3,"192.168.200.0")) + + # check local-adj-out-rib + self.assertTrue(path_exists_in_adj_rib_out(peer3, "192.168.2.0/24")) + self.assertFalse(path_exists_in_adj_rib_out(peer3, "192.168.20.0/24",r=3)) + self.assertTrue(path_exists_in_adj_rib_out(peer3, "192.168.200.0/24")) + + # check show ip bgp on peer3(quagga3) + self.assertTrue(path_exists_in_routing_table(peer3, "192.168.2.0")) + self.assertFalse(path_exists_in_routing_table(peer3, "192.168.20.0",r=3)) + self.assertTrue(path_exists_in_routing_table(peer3, "192.168.200.0")) + + + def retry_until(self, neighbor_address, target_state="BGP_FSM_ESTABLISHED", retry=3): + retry_count = 0 + + while True: + + current_state = util.get_neighbor_state(self.rest_url_neighbor, neighbor_address) + if current_state == target_state: + print "state changed to %s : %s" % (current_state, neighbor_address) + return True + else: + retry_count += 1 + if retry_count > retry: + break + else: + print "current state is %s" % current_state + print "please wait more (" + str(self.wait_per_retry) + " second)" + time.sleep(self.wait_per_retry) + + print "exceeded retry count : %s" % neighbor_address + return False + + + def soft_reset(self, neighbor_address, route_family, type="in"): + url = self.rest_url_neighbor + neighbor_address + "/softreset"+type+"/" + route_family + r = requests.post(url) + if r.status_code == requests.codes.ok: + print "Succeed" + else: + print "Failed" + + + def check_load_config(self): + self.gobgp_config = util.load_gobgp_config(self.gobgp_config_file) + self.quagga_configs = util.load_quagga_config(self.base_dir) + if self.gobgp_config is None: + print "Failed to read the gobgp configuration file" + return False + if len(self.quagga_configs) == 0: + print "Failed to read the quagga configuration file" + return False + return True + + +if __name__ == '__main__': + if fab.test_user_check() is False: + print "you are not root." + sys.exit(1) + if fab.docker_pkg_check() is False: + print "not install docker package." + sys.exit(1) + + nose.main(argv=sys.argv, addplugins=[OptionParser()], defaultTest=sys.argv[0]) diff --git a/test/scenario_test/scenario_test_util.py b/test/scenario_test/scenario_test_util.py new file mode 100644 index 00000000..978f2416 --- /dev/null +++ b/test/scenario_test/scenario_test_util.py @@ -0,0 +1,201 @@ +# Copyright (C) 2014,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. + +import os +import time +import json +import requests +import quagga_access as qaccess +import toml +from peer_info import Peer +from peer_info import Destination +from peer_info import Path +from ciscoconfparse import CiscoConfParse + + +# get address of each neighbor from gobpg configration +def get_neighbor_address(config): + address = [] + neighbors_config = config['NeighborList'] + for neighbor_config in neighbors_config: + neighbor_ip = neighbor_config['NeighborAddress'] + address.append(neighbor_ip) + return address + + +# get route information on quagga +def get_routing_table(neighbor_address, target_prefix, retry=3, interval=5): + print "check route %s on quagga : %s" % (target_prefix, neighbor_address) + retry_count = 0 + while True: + + tn = qaccess.login(neighbor_address) + q_rib = qaccess.show_rib(tn) + qaccess.logout(tn) + for q_path in q_rib: + if target_prefix == q_path['Network']: + return q_path + + retry_count += 1 + if retry_count > retry: + break + else: + print "target_prefix %s is none" % target_prefix + print "wait (" + str(interval) + " seconds)" + time.sleep(interval) + + print "route : %s is none" % target_prefix + return None + + +def get_adj_rib_in(url, neighbor_address, target_prefix, retry=3, interval=5): + return get_adj_rib(url, neighbor_address, target_prefix, retry, interval, type="in") + + +def get_adj_rib_out(url, neighbor_address, target_prefix, retry=3, interval=5): + return get_adj_rib(url, neighbor_address, target_prefix, retry, interval, type="out") + + +def get_adj_rib(base_url, neighbor_address, target_prefix, retry, interval, type="in"): + url = base_url + neighbor_address + "/adj-rib-" +type +"/ipv4" + + retry_count = 0 + while True: + + r = requests.get(url) + in_rib = json.loads(r.text) + print in_rib + paths = [p for p in in_rib['RF_IPv4_UC'] if p['Network'] == target_prefix] + + if len(paths) > 0: + assert len(paths) == 1 + return paths[0] + else: + retry_count += 1 + if retry_count > retry: + break + else: + print "adj_rib_%s is none" % type + print "wait (" + str(interval) + " seconds)" + time.sleep(interval) + + print "adj_rib_%s is none" % type + return None + + +def get_neighbor_state(base_url, neighbor_address): + print "check neighbor state for %s" % (neighbor_address) + state = None + url = base_url + neighbor_address + try: + r = requests.get(url) + neighbor = json.loads(r.text) + state = neighbor['info']['bgp_state'] + remote_ip = neighbor['conf']['remote_ip'] + assert remote_ip == neighbor_address + return state + except Exception as e: + print e + return state + + +def get_paths_in_localrib(base_url, neighbor_address, target_prefix, retry=3, interval=5): + url = base_url + neighbor_address + "/local-rib" + "/ipv4" + + retry_count = 0 + while True: + + r = requests.get(url) + local_rib = json.loads(r.text) + g_dests = local_rib['Destinations'] + g_dest = [dest for dest in g_dests if dest['Prefix'] == target_prefix] + if len(g_dest) > 0: + assert len(g_dest) == 1 + d = g_dest[0] + return d['Paths'] + else: + retry_count += 1 + if retry_count > retry: + break + else: + print "destination is none : %s" % neighbor_address + print "please wait more (" + str(interval) + " second)" + time.sleep(interval) + + print "destination is none" + return None + + +def load_gobgp_config(gobgp_config_file): + + config = None + try: + config = toml.loads(open(gobgp_config_file).read()) + except IOError, (errno, strerror): + print "I/O error(%s): %s" % (errno, strerror) + + return config + + +# load configration from quagga(bgpd.conf) +def load_quagga_config(base_dir): + configs = [] + dirs = [] + try: + content = os.listdir(base_dir) + for item in content: + if "q" != item[0]: + continue + if os.path.isdir(os.path.join(base_dir, item)): + dirs.append(item) + except OSError, (errno, strerror): + print "I/O error(%s): %s" % (errno, strerror) + + for dir in dirs: + config_path = base_dir + dir + "/bgpd.conf" + config = CiscoConfParse(config_path) + + peer_ip = config.find_objects(r"^!\smy\saddress")[0].text.split(" ")[3] + peer_ip_version = config.find_objects(r"^!\smy\sip_version")[0].text.split(" ")[3] + peer_id = config.find_objects(r"^bgp\srouter-id")[0].text.split(" ")[2] + peer_as = config.find_objects(r"^router\sbgp")[0].text.split(" ")[2] + quagga_config = Peer(peer_ip, peer_id, peer_as, peer_ip_version) + + networks = config.find_objects(r"^network") + if len(networks) == 0: + continue + for network in networks: + elems = network.text.split(" ") + prefix = elems[1].split("/")[0] + network = elems[1] + nexthop = peer_ip + path = Path(network, nexthop) + dest = Destination(prefix) + dest.paths.append(path) + quagga_config.destinations[prefix] = dest + # print "prefix: " + prefix + # print "network: " + network + # print "nexthop: " + nexthop + + neighbors = config.find_objects(r"^neighbor\s.*\sremote-as") + if len(neighbors) == 0: + continue + for neighbor in neighbors: + elems = neighbor.text.split(" ") + neighbor = Peer(elems[1], None, elems[3], None) + quagga_config.neighbors.append(neighbor) + configs.append(quagga_config) + + return configs
\ No newline at end of file |