github.com/osrg/gobgp@v2.0.0+incompatible/test/scenario_test/route_reflector_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 from __future__ import absolute_import 17 18 import sys 19 import time 20 import unittest 21 22 from fabric.api import local 23 import nose 24 25 from lib.noseplugin import OptionParser, parser_option 26 27 from lib import base 28 from lib.base import BGP_FSM_ESTABLISHED 29 from lib.gobgp import GoBGPContainer 30 from lib.quagga import QuaggaBGPContainer 31 32 33 def wait_for(f, timeout=120): 34 interval = 1 35 count = 0 36 while True: 37 if f(): 38 return 39 40 time.sleep(interval) 41 count += interval 42 if count >= timeout: 43 raise Exception('timeout') 44 45 46 class GoBGPTestBase(unittest.TestCase): 47 def assert_adv_count(self, src, dst, rf, count): 48 self.assertEqual(count, len(src.get_adj_rib_out(dst, rf=rf))) 49 self.assertEqual(count, len(dst.get_adj_rib_in(src, rf=rf))) 50 51 def assert_upd_count(self, src, dst, sent, received): 52 messages = src.get_neighbor(dst)['state']['messages'] 53 self.assertEqual(messages['sent'].get('update', 0), sent) 54 self.assertEqual(messages['received'].get('update', 0), received) 55 56 @classmethod 57 def setUpClass(cls): 58 gobgp_ctn_image_name = parser_option.gobgp_image 59 base.TEST_PREFIX = parser_option.test_prefix 60 61 g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', 62 ctn_image_name=gobgp_ctn_image_name, 63 log_level=parser_option.gobgp_log_level) 64 q1 = QuaggaBGPContainer(name='q1', asn=65000, router_id='192.168.0.2') 65 q2 = QuaggaBGPContainer(name='q2', asn=65000, router_id='192.168.0.3') 66 q3 = QuaggaBGPContainer(name='q3', asn=65000, router_id='192.168.0.4') 67 q4 = QuaggaBGPContainer(name='q4', asn=65000, router_id='192.168.0.5') 68 69 qs = [q1, q2, q3, q4] 70 ctns = [g1, q1, q2, q3, q4] 71 72 initial_wait_time = max(ctn.run() for ctn in ctns) 73 time.sleep(initial_wait_time) 74 75 # g1 as a route reflector 76 g1.add_peer(q1, is_rr_client=True) 77 q1.add_peer(g1) 78 g1.add_peer(q2, is_rr_client=True) 79 q2.add_peer(g1) 80 g1.add_peer(q3) 81 q3.add_peer(g1) 82 g1.add_peer(q4) 83 q4.add_peer(g1) 84 85 # advertise a route from q1, q2 86 for idx, c in enumerate(qs): 87 route = '10.0.{0}.0/24'.format(idx + 1) 88 c.add_route(route) 89 90 cls.gobgp = g1 91 cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3, 'q4': q4} 92 93 # test each neighbor state is turned establish 94 def test_01_neighbor_established(self): 95 for q in self.quaggas.itervalues(): 96 self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q) 97 98 def test_02_check_gobgp_global_rib(self): 99 for q in self.quaggas.itervalues(): 100 # paths expected to exist in gobgp's global rib 101 def f(): 102 state = self.gobgp.get_neighbor_state(q) 103 self.assertEqual(state, BGP_FSM_ESTABLISHED) 104 105 routes = q.routes.keys() 106 global_rib = [p['prefix'] for p in self.gobgp.get_global_rib()] 107 for p in global_rib: 108 if p in routes: 109 routes.remove(p) 110 111 return len(routes) == 0 112 wait_for(f) 113 114 def test_03_check_gobgp_adj_rib_out(self): 115 for q in self.quaggas.itervalues(): 116 paths = [p['nlri']['prefix'] for p in self.gobgp.get_adj_rib_out(q)] 117 for qq in self.quaggas.itervalues(): 118 if q == qq: 119 continue 120 if self.gobgp.peers[q]['is_rr_client']: 121 for p in qq.routes.keys(): 122 self.assertTrue(p in paths) 123 else: 124 for p in qq.routes.keys(): 125 if self.gobgp.peers[qq]['is_rr_client']: 126 self.assertTrue(p in paths) 127 else: 128 self.assertFalse(p in paths) 129 130 def test_10_setup_rr_rtc_isolation_policy(self): 131 # +-------+ 132 # | rr | 133 # +----------------+----| (RR) |---+----------------+ 134 # | | +-------+ | | 135 # | | | | 136 # (iBGP) (iBGP) (iBGP) (iBGP) 137 # | | | | 138 # +-------------+ +-------------+ +-------------+ +-------------+ 139 # | acme1 | | acme2 | | tyrell1 | | tyrell2 | 140 # | (RR Client) | | (RR Client) | | (RR Client) | | (RR Client) | 141 # +-------------+ +-------------+ +-------------+ +-------------+ 142 143 144 gobgp_ctn_image_name = parser_option.gobgp_image 145 rr = GoBGPContainer(name='rr', asn=65000, router_id='192.168.1.1', 146 ctn_image_name=gobgp_ctn_image_name, 147 log_level=parser_option.gobgp_log_level) 148 acme1 = GoBGPContainer(name='acme1', asn=65000, router_id='192.168.1.101', 149 ctn_image_name=gobgp_ctn_image_name, 150 log_level=parser_option.gobgp_log_level) 151 acme2 = GoBGPContainer(name='acme2', asn=65000, router_id='192.168.1.102', 152 ctn_image_name=gobgp_ctn_image_name, 153 log_level=parser_option.gobgp_log_level) 154 155 tyrell1 = GoBGPContainer(name='tyrell1', asn=65000, router_id='192.168.1.201', 156 ctn_image_name=gobgp_ctn_image_name, 157 log_level=parser_option.gobgp_log_level) 158 159 tyrell2 = GoBGPContainer(name='tyrell2', asn=65000, router_id='192.168.1.202', 160 ctn_image_name=gobgp_ctn_image_name, 161 log_level=parser_option.gobgp_log_level) 162 163 time.sleep(max(ctn.run() for ctn in [rr, acme1, acme2, tyrell1, tyrell2])) 164 165 rr.add_peer(acme1, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True) 166 acme1.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True) 167 168 rr.add_peer(acme2, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True) 169 acme2.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True) 170 171 rr.add_peer(tyrell1, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True) 172 tyrell1.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True) 173 174 rr.add_peer(tyrell2, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True) 175 tyrell2.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True) 176 177 self.__class__.rr = rr 178 self.__class__.acme1 = acme1 179 self.__class__.acme2 = acme2 180 self.__class__.tyrell1 = tyrell1 181 self.__class__.tyrell2 = tyrell2 182 183 # add import/export policy to allow peers exchange routes within specific RTs 184 # later tests should not break due to RTC Updates being filtered-out 185 186 rr.local("gobgp policy neighbor add clients-acme {} {}".format( 187 rr.peer_name(acme1), 188 rr.peer_name(acme2))) 189 190 rr.local("gobgp policy neighbor add clients-tyrell {} {}".format( 191 rr.peer_name(tyrell1), 192 rr.peer_name(tyrell2))) 193 194 rr.local("gobgp policy ext-community add rts-acme rt:^100:.*$") 195 rr.local("gobgp policy ext-community add rts-tyrell rt:^200:.*$") 196 197 rr.local('gobgp policy statement add allow-rtc') 198 rr.local('gobgp policy statement allow-rtc add condition afi-safi-in rtc') 199 rr.local('gobgp policy statement allow-rtc add action accept') 200 201 rr.local('gobgp policy statement add allow-acme') 202 rr.local('gobgp policy statement allow-acme add condition neighbor clients-acme') 203 rr.local('gobgp policy statement allow-acme add condition ext-community rts-acme') 204 rr.local('gobgp policy statement allow-acme add action accept') 205 206 rr.local('gobgp policy statement add allow-tyrell') 207 rr.local('gobgp policy statement allow-tyrell add condition neighbor clients-tyrell') 208 rr.local('gobgp policy statement allow-tyrell add condition ext-community rts-tyrell') 209 rr.local('gobgp policy statement allow-tyrell add action accept') 210 rr.local('gobgp policy add tenancy allow-rtc allow-acme allow-tyrell') 211 212 rr.local('gobgp global policy import add tenancy default reject') 213 rr.local('gobgp global policy export add tenancy default reject') 214 215 acme1.local("gobgp vrf add a1 rd 100:100 rt both 100:100") 216 acme2.local("gobgp vrf add a1 rd 100:100 rt both 100:100") 217 218 tyrell1.local("gobgp vrf add t1 rd 200:100 rt both 200:100") 219 tyrell2.local("gobgp vrf add t1 rd 200:100 rt both 200:100") 220 221 rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=acme1) 222 rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=acme2) 223 rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=tyrell1) 224 rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=tyrell2) 225 226 def test_11_routes_in_allowed_acme_rts_are_exchanged(self): 227 self.acme1.local("gobgp vrf a1 rib add 10.10.0.0/16 local-pref 100") 228 self.acme2.local("gobgp vrf a1 rib add 10.20.0.0/16") 229 self.tyrell1.local("gobgp vrf t1 rib add 20.10.0.0/16") 230 self.tyrell2.local("gobgp vrf t1 rib add 20.20.0.0/16") 231 time.sleep(1) 232 233 self.assert_adv_count(self.rr, self.acme1, 'rtc', 2) 234 self.assert_adv_count(self.rr, self.acme1, 'ipv4-l3vpn', 1) 235 self.assert_adv_count(self.rr, self.acme2, 'rtc', 2) 236 self.assert_adv_count(self.rr, self.acme2, 'ipv4-l3vpn', 1) 237 self.assert_adv_count(self.rr, self.tyrell1, 'rtc', 2) 238 self.assert_adv_count(self.rr, self.tyrell1, 'ipv4-l3vpn', 1) 239 self.assert_adv_count(self.rr, self.tyrell2, 'rtc', 2) 240 self.assert_adv_count(self.rr, self.tyrell2, 'ipv4-l3vpn', 1) 241 242 def test_12_routes_from_separate_rts_peers_are_isolated_by_rr(self): 243 self.tyrell1.local("gobgp vrf add a1 rd 100:100 rt both 100:100") 244 self.tyrell1.local("gobgp vrf a1 rib add 10.10.0.0/16 local-pref 200") 245 self.tyrell1.local("gobgp vrf a1 rib add 10.30.0.0/16") 246 time.sleep(1) 247 248 rr_t2_in = self.rr.get_adj_rib_in(self.tyrell1, rf='ipv4-l3vpn') 249 self.assertEqual(3, len(rr_t2_in)) 250 251 rr_a2_out = self.rr.get_adj_rib_out(self.acme2, rf='ipv4-l3vpn') 252 self.assertEqual(1, len(rr_a2_out)) 253 254 a2_routes = self.acme2.get_adj_rib_in(self.rr, rf='ipv4-l3vpn') 255 self.assertEqual(1, len(a2_routes)) 256 ar0 = a2_routes[0] 257 self.assertEqual('10.10.0.0/16', ar0['prefix']) 258 self.assertEqual(self.rr.peer_name(self.acme1), ar0['nexthop']) 259 self.assertEqual(100, ar0['local-pref']) 260 261 262 if __name__ == '__main__': 263 output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 264 if int(output) is not 0: 265 print "docker not found" 266 sys.exit(1) 267 268 nose.main(argv=sys.argv, addplugins=[OptionParser()], 269 defaultTest=sys.argv[0])