github.com/osrg/gobgp/v3@v3.30.0/test/scenario_test/ibgp_router_test.py (about) 1 # Copyright (C) 2015 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 from itertools import combinations 18 import sys 19 import time 20 import unittest 21 22 import collections 23 collections.Callable = collections.abc.Callable 24 25 import nose 26 27 from lib.noseplugin import OptionParser, parser_option 28 29 from lib import base 30 from lib.base import ( 31 BGP_FSM_IDLE, 32 BGP_FSM_ESTABLISHED, 33 local, 34 ) 35 from lib.base import wait_for_completion 36 from lib.gobgp import GoBGPContainer 37 from lib.quagga import QuaggaBGPContainer 38 39 40 class GoBGPTestBase(unittest.TestCase): 41 42 @classmethod 43 def setUpClass(cls): 44 gobgp_ctn_image_name = parser_option.gobgp_image 45 base.TEST_PREFIX = parser_option.test_prefix 46 47 g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', 48 ctn_image_name=gobgp_ctn_image_name, 49 log_level=parser_option.gobgp_log_level) 50 q1 = QuaggaBGPContainer(name='q1', asn=65000, router_id='192.168.0.2') 51 q2 = QuaggaBGPContainer(name='q2', asn=65000, router_id='192.168.0.3') 52 53 qs = [q1, q2] 54 ctns = [g1, q1, q2] 55 56 initial_wait_time = max(ctn.run() for ctn in ctns) 57 time.sleep(initial_wait_time) 58 59 # ibgp peer. loop topology 60 for a, b in combinations(ctns, 2): 61 a.add_peer(b) 62 b.add_peer(a) 63 64 # advertise a route from q1, q2 65 for idx, c in enumerate(qs): 66 route = '10.0.{0}.0/24'.format(idx + 1) 67 c.add_route(route) 68 69 cls.gobgp = g1 70 cls.quaggas = {'q1': q1, 'q2': q2} 71 72 # test each neighbor state is turned establish 73 def test_01_neighbor_established(self): 74 for q in self.quaggas.values(): 75 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q) 76 77 def test_02_check_gobgp_global_rib(self): 78 for q in self.quaggas.values(): 79 # paths expected to exist in gobgp's global rib 80 routes = list(q.routes.keys()) 81 timeout = 120 82 interval = 1 83 count = 0 84 while True: 85 # gobgp's global rib 86 state = self.gobgp.get_neighbor_state(q) 87 self.assertEqual(state, BGP_FSM_ESTABLISHED) 88 global_rib = [p['prefix'] for p in self.gobgp.get_global_rib()] 89 90 for p in global_rib: 91 if p in routes: 92 routes.remove(p) 93 94 if len(routes) == 0: 95 break 96 97 time.sleep(interval) 98 count += interval 99 if count >= timeout: 100 raise Exception('timeout') 101 102 def test_03_check_gobgp_adj_rib_out(self): 103 for q in self.quaggas.values(): 104 paths = self.gobgp.get_adj_rib_out(q) 105 # bgp speaker mustn't forward iBGP routes to iBGP peers 106 self.assertEqual(len(paths), 0) 107 108 def test_04_originate_path(self): 109 self.gobgp.add_route('10.10.0.0/24') 110 dst = self.gobgp.get_global_rib('10.10.0.0/24') 111 self.assertEqual(len(dst), 1) 112 self.assertEqual(len(dst[0]['paths']), 1) 113 path = dst[0]['paths'][0] 114 self.assertEqual(path['nexthop'], '0.0.0.0') 115 self.assertEqual(len(path['aspath']), 0) 116 117 def test_05_check_gobgp_adj_rib_out(self): 118 for q in self.quaggas.values(): 119 paths = self.gobgp.get_adj_rib_out(q) 120 self.assertEqual(len(paths), len(self.gobgp.routes)) 121 path = paths[0] 122 self.assertEqual(path['nlri']['prefix'], '10.10.0.0/24') 123 peer_info = self.gobgp.peers[q] 124 local_addr = peer_info['local_addr'].split('/')[0] 125 self.assertEqual(path['nexthop'], local_addr) 126 self.assertEqual(len(path['aspath']), 0) 127 128 # check routes are properly advertised to all BGP speaker 129 def test_06_check_quagga_global_rib(self): 130 interval = 1 131 timeout = int(120 / interval) 132 for q in self.quaggas.values(): 133 done = False 134 for _ in range(timeout): 135 if done: 136 break 137 global_rib = q.get_global_rib() 138 # quagga's global_rib must have two routes at least, 139 # a self-generated route and a gobgp-generated route 140 if len(global_rib) < len(q.routes) + len(self.gobgp.routes): 141 time.sleep(interval) 142 continue 143 144 peer_info = self.gobgp.peers[q] 145 local_addr = peer_info['local_addr'].split('/')[0] 146 for r in self.gobgp.routes: 147 self.assertTrue(r in (p['prefix'] for p in global_rib)) 148 for rr in global_rib: 149 if rr['prefix'] == r: 150 self.assertEqual(rr['nexthop'], local_addr) 151 152 for r in list(q.routes.keys()): 153 self.assertTrue(r in (p['prefix'] for p in global_rib)) 154 for rr in global_rib: 155 if rr['prefix'] == r: 156 self.assertEqual(rr['nexthop'], '0.0.0.0') 157 158 done = True 159 if done: 160 continue 161 # should not reach here 162 raise AssertionError 163 164 def test_07_add_ebgp_peer(self): 165 q3 = QuaggaBGPContainer(name='q3', asn=65001, router_id='192.168.0.4') 166 self.quaggas['q3'] = q3 167 initial_wait_time = q3.run() 168 time.sleep(initial_wait_time) 169 170 self.gobgp.add_peer(q3) 171 q3.add_peer(self.gobgp) 172 173 q3.add_route('10.0.3.0/24') 174 175 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q3) 176 177 def test_08_check_global_rib(self): 178 self.test_02_check_gobgp_global_rib() 179 180 def test_09_check_gobgp_ebgp_adj_rib_out(self): 181 q1 = self.quaggas['q1'] 182 q2 = self.quaggas['q2'] 183 q3 = self.quaggas['q3'] 184 paths = self.gobgp.get_adj_rib_out(q3) 185 total_len = len(q1.routes) + len(q2.routes) + len(self.gobgp.routes) 186 assert len(paths) == total_len 187 for path in paths: 188 peer_info = self.gobgp.peers[q3] 189 local_addr = peer_info['local_addr'].split('/')[0] 190 self.assertEqual(path['nexthop'], local_addr) 191 self.assertEqual(path['aspath'], [self.gobgp.asn]) 192 193 def test_10_check_gobgp_ibgp_adj_rib_out(self): 194 q1 = self.quaggas['q1'] 195 q3 = self.quaggas['q3'] 196 peer_info = self.gobgp.peers[q3] 197 neigh_addr = peer_info['neigh_addr'].split('/')[0] 198 199 for prefix in q3.routes.keys(): 200 paths = self.gobgp.get_adj_rib_out(q1, prefix) 201 self.assertEqual(len(paths), 1) 202 path = paths[0] 203 # bgp router mustn't change nexthop of routes from eBGP peers 204 # which are sent to iBGP peers 205 self.assertEqual(path['nexthop'], neigh_addr) 206 # bgp router mustn't change aspath of routes from eBGP peers 207 # which are sent to iBGP peers 208 self.assertEqual(path['aspath'], [q3.asn]) 209 210 # disable ebgp peer, check ebgp routes are removed 211 def test_11_disable_ebgp_peer(self): 212 q3 = self.quaggas['q3'] 213 self.gobgp.disable_peer(q3) 214 del self.quaggas['q3'] 215 self.gobgp.wait_for(expected_state=BGP_FSM_IDLE, peer=q3) 216 217 for route in q3.routes.keys(): 218 dst = self.gobgp.get_global_rib(route) 219 self.assertEqual(len(dst), 0) 220 221 for q in self.quaggas.values(): 222 paths = self.gobgp.get_adj_rib_out(q) 223 # only gobgp's locally generated routes must exists 224 print(paths) 225 self.assertEqual(len(paths), len(self.gobgp.routes)) 226 227 def test_12_disable_ibgp_peer(self): 228 q1 = self.quaggas['q1'] 229 self.gobgp.disable_peer(q1) 230 self.gobgp.wait_for(expected_state=BGP_FSM_IDLE, peer=q1) 231 232 for route in q1.routes.keys(): 233 dst = self.gobgp.get_global_rib(route) 234 self.assertEqual(len(dst), 0) 235 236 def test_13_enable_ibgp_peer(self): 237 q1 = self.quaggas['q1'] 238 self.gobgp.enable_peer(q1) 239 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q1) 240 241 def test_14_check_gobgp_adj_rib_out(self): 242 for q in self.quaggas.values(): 243 paths = self.gobgp.get_adj_rib_out(q) 244 # only gobgp's locally generated routes must exists 245 self.assertEqual(len(paths), len(self.gobgp.routes)) 246 247 def test_15_add_ebgp_peer(self): 248 q4 = QuaggaBGPContainer(name='q4', asn=65001, router_id='192.168.0.5') 249 self.quaggas['q4'] = q4 250 initial_wait_time = q4.run() 251 time.sleep(initial_wait_time) 252 253 self.gobgp.add_peer(q4) 254 q4.add_peer(self.gobgp) 255 256 prefix = '10.0.4.0/24' 257 q4.add_route(prefix) 258 259 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q4) 260 261 q1 = self.quaggas['q1'] 262 q2 = self.quaggas['q2'] 263 for q in [q1, q2]: 264 def _f(): 265 return prefix in [p['nlri']['prefix'] for p in self.gobgp.get_adj_rib_out(q)] 266 wait_for_completion(_f) 267 268 def f(): 269 return len(q2.get_global_rib(prefix)) == 1 270 wait_for_completion(f) 271 272 def test_16_add_best_path_from_ibgp(self): 273 q1 = self.quaggas['q1'] 274 q2 = self.quaggas['q2'] 275 276 prefix = '10.0.4.0/24' 277 q1.add_route(prefix) 278 279 def f1(): 280 l = self.gobgp.get_global_rib(prefix) 281 return len(l) == 1 and len(l[0]['paths']) == 2 282 wait_for_completion(f1) 283 284 def f2(): 285 return prefix not in [p['nlri']['prefix'] for p in self.gobgp.get_adj_rib_out(q2)] 286 wait_for_completion(f2) 287 288 def f3(): 289 l = q2.get_global_rib(prefix) 290 # route from ibgp so aspath should be empty 291 return len(l) == 1 and len(l[0]['aspath']) == 0 292 wait_for_completion(f3) 293 294 295 if __name__ == '__main__': 296 output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 297 if int(output) != 0: 298 print("docker not found") 299 sys.exit(1) 300 301 nose.main(argv=sys.argv, addplugins=[OptionParser()], 302 defaultTest=sys.argv[0])