github.com/osrg/gobgp/v3@v3.30.0/test/scenario_test/bgp_confederation_test.py (about) 1 # Copyright (C) 2017 Nippon Telegraph and Telephone Corporation. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 # implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 16 17 import sys 18 import time 19 import unittest 20 21 import collections 22 collections.Callable = collections.abc.Callable 23 24 import nose 25 26 from lib.noseplugin import OptionParser, parser_option 27 28 from lib import base 29 from lib.base import BGP_FSM_ESTABLISHED, local 30 from lib.gobgp import GoBGPContainer 31 from lib.quagga import QuaggaBGPContainer 32 33 34 class GoBGPTestBase(unittest.TestCase): 35 36 def _check_global_rib_first(self, q, prefix, aspath): 37 route = q.get_global_rib(prefix)[0] 38 self.assertListEqual(aspath, route['aspath']) 39 40 @classmethod 41 def setUpClass(cls): 42 # +-----Confederation(AS30)-----+ 43 # AS21 AS20 | +-AS65002-+ +-AS65001-+ | AS10 44 # +----+ +----+ | | +-----+ | | +-----+ | | +----+ 45 # | q3 |---| q2 |--+-+-| g1 |-+-----+-| q11 |-+-+--| q1 | 46 # +----+ +----+ | | +-----+ | | +-----+ | | +----+ 47 # | | | | | | | | 48 # | | | | | | | | 49 # | | | | | | | | 50 # | | +-----+ | | +-----+ | | 51 # | | | q22 | | | | q12 | | | 52 # | | +-----+ | | +-----+ | | 53 # | +---------+ +---------+ | 54 # +-----------------------------+ 55 56 gobgp_ctn_image_name = parser_option.gobgp_image 57 base.TEST_PREFIX = parser_option.test_prefix 58 59 bgp_conf_1 = {'global': {'confederation': {'config': { 60 'enabled': True, 'identifier': 30, 'member-as-list': [65002]}}}} 61 bgp_conf_2 = {'global': {'confederation': {'config': { 62 'enabled': True, 'identifier': 30, 'member-as-list': [65001]}}}} 63 64 g1 = GoBGPContainer(name='g1', asn=65002, router_id='192.168.2.1', 65 ctn_image_name=gobgp_ctn_image_name, 66 log_level=parser_option.gobgp_log_level, 67 bgp_config=bgp_conf_2) 68 69 q1 = QuaggaBGPContainer(name='q1', asn=10, router_id='1.1.1.1') 70 q2 = QuaggaBGPContainer(name='q2', asn=20, router_id='2.2.2.2') 71 q3 = QuaggaBGPContainer(name='q3', asn=21, router_id='3.3.3.3') 72 q11 = QuaggaBGPContainer(name='q11', asn=65001, router_id='192.168.1.1', bgpd_config=bgp_conf_1) 73 q12 = QuaggaBGPContainer(name='q12', asn=65001, router_id='192.168.1.2', bgpd_config=bgp_conf_1) 74 q22 = QuaggaBGPContainer(name='q22', asn=65002, router_id='192.168.2.2', bgpd_config=bgp_conf_2) 75 76 ctns = [g1, q1, q2, q3, q11, q12, q22] 77 78 cls.initial_wait_time = max(ctn.run() for ctn in ctns) 79 80 time.sleep(cls.initial_wait_time) 81 82 q1.add_peer(q11, remote_as=30) 83 q11.add_peer(q1) 84 q11.add_peer(q12) 85 q12.add_peer(q11) 86 g1.add_peer(q11) 87 q11.add_peer(g1) 88 g1.add_peer(q22) 89 q22.add_peer(g1) 90 g1.add_peer(q2) 91 q2.add_peer(g1, remote_as=30) 92 q3.add_peer(q2) 93 q2.add_peer(q3) 94 cls.gobgp = g1 95 cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3, 'q11': q11, 'q12': q12, 'q22': q22} 96 97 # test each neighbor state is turned establish 98 def test_01_neighbor_established(self): 99 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.quaggas['q11']) 100 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.quaggas['q22']) 101 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.quaggas['q2']) 102 self.quaggas['q11'].wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.quaggas['q1']) 103 self.quaggas['q11'].wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.quaggas['q12']) 104 self.quaggas['q2'].wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.quaggas['q3']) 105 106 def test_02_route_advertise(self): 107 self.quaggas['q3'].add_route('10.0.0.0/24') 108 time.sleep(self.initial_wait_time) 109 110 routes = [] 111 for _ in range(60): 112 routes = self.quaggas['q1'].get_global_rib('10.0.0.0/24') 113 if routes: 114 break 115 time.sleep(1) 116 self.assertFalse(len(routes) == 0) 117 118 # Confirm AS_PATH in confederation is removed 119 self._check_global_rib_first(self.quaggas['q1'], '10.0.0.0/24', [30, 20, 21]) 120 121 # Confirm AS_PATH in confederation is not removed 122 self._check_global_rib_first(self.quaggas['q11'], '10.0.0.0/24', [65002, 20, 21]) 123 124 self._check_global_rib_first(self.quaggas['q22'], '10.0.0.0/24', [20, 21]) 125 126 def test_03_best_path(self): 127 self.quaggas['q1'].add_route('10.0.0.0/24') 128 129 routes = [] 130 for _ in range(60): 131 routes = self.gobgp.get_global_rib('10.0.0.0/24') 132 if len(routes) == 1: 133 if len(routes[0]['paths']) == 2: 134 break 135 time.sleep(1) 136 self.assertFalse(len(routes) != 1) 137 self.assertFalse(len(routes[0]['paths']) != 2) 138 139 # In g1, there are two routes to 10.0.0.0/24 140 # confirm the route from q1 is selected as the best path 141 # because it has shorter AS_PATH. 142 # (AS_CONFED_* segments in AS_PATH is not counted) 143 paths = routes[0]['paths'] 144 self.assertTrue(paths[0]['aspath'], [65001, 10]) 145 146 # confirm the new best path is advertised 147 self._check_global_rib_first(self.quaggas['q22'], '10.0.0.0/24', [65001, 10]) 148 149 150 if __name__ == '__main__': 151 output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 152 if int(output) != 0: 153 print("docker not found") 154 sys.exit(1) 155 156 nose.main(argv=sys.argv, addplugins=[OptionParser()], 157 defaultTest=sys.argv[0])