github.com/osrg/gobgp/v3@v3.30.0/test/scenario_test/long_lived_graceful_restart_test.py (about) 1 # Copyright (C) 2016 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 chain 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_ACTIVE, 32 BGP_FSM_ESTABLISHED, 33 LONG_LIVED_GRACEFUL_RESTART_TIME, 34 local, 35 ) 36 from lib.gobgp import GoBGPContainer 37 38 39 class GoBGPTestBase(unittest.TestCase): 40 41 @classmethod 42 def setUpClass(cls): 43 gobgp_ctn_image_name = parser_option.gobgp_image 44 base.TEST_PREFIX = parser_option.test_prefix 45 46 g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', 47 ctn_image_name=gobgp_ctn_image_name, 48 log_level=parser_option.gobgp_log_level) 49 g2 = GoBGPContainer(name='g2', asn=65001, router_id='192.168.0.2', 50 ctn_image_name=gobgp_ctn_image_name, 51 log_level=parser_option.gobgp_log_level) 52 g3 = GoBGPContainer(name='g3', asn=65002, router_id='192.168.0.3', 53 ctn_image_name=gobgp_ctn_image_name, 54 log_level=parser_option.gobgp_log_level) 55 g4 = GoBGPContainer(name='g4', asn=65003, router_id='192.168.0.4', 56 ctn_image_name=gobgp_ctn_image_name, 57 log_level=parser_option.gobgp_log_level) 58 ctns = [g1, g2, g3, g4] 59 60 initial_wait_time = max(ctn.run() for ctn in ctns) 61 62 time.sleep(initial_wait_time) 63 64 g1.add_peer(g2, graceful_restart=True, llgr=True) 65 g2.add_peer(g1, graceful_restart=True, llgr=True) 66 g1.add_peer(g3, graceful_restart=True, llgr=True) 67 g3.add_peer(g1, graceful_restart=True, llgr=True) 68 g1.add_peer(g4, graceful_restart=True) 69 g4.add_peer(g1, graceful_restart=True) 70 71 cls.bgpds = {'g1': g1, 'g2': g2, 'g3': g3, 'g4': g4} 72 73 # test each neighbor state is turned establish 74 def test_01_neighbor_established(self): 75 g1 = self.bgpds['g1'] 76 g2 = self.bgpds['g2'] 77 g3 = self.bgpds['g3'] 78 g4 = self.bgpds['g4'] 79 g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=g2) 80 g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=g3) 81 g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=g4) 82 83 def _test_graceful_restart(self): 84 g1 = self.bgpds['g1'] 85 g2 = self.bgpds['g2'] 86 g3 = self.bgpds['g3'] 87 g4 = self.bgpds['g4'] 88 89 g1.wait_for(expected_state=BGP_FSM_ACTIVE, peer=g2) 90 91 time.sleep(1) 92 93 self.assertEqual(len(g1.get_global_rib('10.0.0.0/24')), 1) 94 # check llgr-stale community is added to 10.0.0.0/24 95 r = g1.get_global_rib('10.0.0.0/24')[0]['paths'][0] 96 comms = list(chain.from_iterable([attr['communities'] for attr in r['attrs'] if attr['type'] == 8])) 97 self.assertTrue(0xffff0006 in comms) 98 99 # 10.10.0.0/24 is announced with no-llgr community 100 # must not exist in the rib 101 self.assertEqual(len(g1.get_global_rib('10.10.0.0/24')), 0) 102 for d in g1.get_global_rib(): 103 for p in d['paths']: 104 self.assertTrue(p['stale']) 105 106 # check llgr-stale community is present in received route 10.0.0.0/24 107 self.assertEqual(len(g3.get_global_rib('10.0.0.0/24')), 1) 108 r = g3.get_global_rib('10.0.0.0/24')[0]['paths'][0] 109 comms = list(chain.from_iterable([attr['communities'] for attr in r['attrs'] if attr['type'] == 8])) 110 self.assertTrue(0xffff0006 in comms) 111 112 # g4 is not llgr capable, llgr-stale route must be 113 # withdrawn 114 self.assertEqual(len(g4.get_global_rib('10.0.0.0/24')), 0) 115 116 def test_02_hold_timer_expiry_graceful_restart(self): 117 g1 = self.bgpds['g1'] 118 g2 = self.bgpds['g2'] 119 g3 = self.bgpds['g3'] 120 g4 = self.bgpds['g4'] 121 122 g2.local('gobgp global rib add 10.0.0.0/24') 123 g2.local('gobgp global rib add 10.10.0.0/24 community no-llgr') 124 125 time.sleep(1) 126 127 g2.local("ip route add blackhole {}/32".format(g1.ip_addrs[0][1].split("/")[0])) 128 g2.local("ip route add blackhole {}/32".format(g3.ip_addrs[0][1].split("/")[0])) 129 g2.local("ip route add blackhole {}/32".format(g4.ip_addrs[0][1].split("/")[0])) 130 131 self._test_graceful_restart() 132 133 def test_03_neighbor_established_after_hold_time_expiry(self): 134 g1 = self.bgpds['g1'] 135 g2 = self.bgpds['g2'] 136 g3 = self.bgpds['g3'] 137 g4 = self.bgpds['g4'] 138 g2.local("ip route del blackhole {}/32".format(g1.ip_addrs[0][1].split("/")[0])) 139 g2.local("ip route del blackhole {}/32".format(g3.ip_addrs[0][1].split("/")[0])) 140 g2.local("ip route del blackhole {}/32".format(g4.ip_addrs[0][1].split("/")[0])) 141 142 g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=g2) 143 time.sleep(1) 144 self.assertEqual(len(g1.get_global_rib('10.0.0.0/24')), 1) 145 self.assertEqual(len(g1.get_global_rib('10.10.0.0/24')), 1) 146 # check llgr-stale community is not present in 10.0.0.0/24 147 r = g1.get_global_rib('10.0.0.0/24')[0]['paths'][0] 148 comms = list(chain.from_iterable([attr['communities'] for attr in r['attrs'] if attr['type'] == 8])) 149 self.assertFalse(0xffff0006 in comms) 150 151 # check llgr-stale community is not present in 10.0.0.0/24 152 self.assertEqual(len(g3.get_global_rib('10.0.0.0/24')), 1) 153 r = g3.get_global_rib('10.0.0.0/24')[0]['paths'][0] 154 comms = list(chain.from_iterable([attr['communities'] for attr in r['attrs'] if attr['type'] == 8])) 155 self.assertFalse(0xffff0006 in comms) 156 157 def test_04_graceful_restart(self): 158 g1 = self.bgpds['g1'] 159 g2 = self.bgpds['g2'] 160 g3 = self.bgpds['g3'] 161 g4 = self.bgpds['g4'] 162 163 g2.local('gobgp global rib add 10.0.0.0/24') 164 g2.local('gobgp global rib add 10.10.0.0/24 community no-llgr') 165 166 time.sleep(1) 167 168 g2.stop_gobgp() 169 self._test_graceful_restart() 170 171 def test_05_softreset_preserves_llgr_community(self): 172 g1 = self.bgpds['g1'] 173 g2 = self.bgpds['g2'] 174 g3 = self.bgpds['g3'] 175 g4 = self.bgpds['g4'] 176 177 g1.softreset(g2) 178 time.sleep(1) 179 180 # 10.10.0.0/24 received with no-llgr community is not reinstalled to rib 181 self.assertEqual(len(g1.get_global_rib('10.10.0.0/24')), 0) 182 # Stale flags are not cleared 183 for d in g1.get_global_rib(): 184 for p in d['paths']: 185 self.assertTrue(p['stale']) 186 187 # check llgr-stale community is not cleared from 10.0.0.0/24 188 r = g1.get_global_rib('10.0.0.0/24')[0]['paths'][0] 189 comms = list(chain.from_iterable([attr['communities'] for attr in r['attrs'] if attr['type'] == 8])) 190 self.assertTrue(0xffff0006 in comms) 191 192 # check llgr-stale community is not cleared in route 10.0.0.0/24 on g3 193 self.assertEqual(len(g3.get_global_rib('10.0.0.0/24')), 1) 194 r = g3.get_global_rib('10.0.0.0/24')[0]['paths'][0] 195 comms = list(chain.from_iterable([attr['communities'] for attr in r['attrs'] if attr['type'] == 8])) 196 self.assertTrue(0xffff0006 in comms) 197 198 # g4 is not llgr capable, llgr-stale route must not be advertized on softreset g1 199 self.assertEqual(len(g4.get_global_rib('10.0.0.0/24')), 0) 200 201 def test_06_neighbor_established(self): 202 g1 = self.bgpds['g1'] 203 g2 = self.bgpds['g2'] 204 # g3 = self.bgpds['g3'] 205 # g4 = self.bgpds['g4'] 206 207 g2.start_gobgp(graceful_restart=True) 208 g2.local('gobgp global rib add 10.0.0.0/24') 209 g2.local('gobgp global rib add 10.10.0.0/24') 210 211 g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=g2) 212 time.sleep(1) 213 self.assertEqual(len(g1.get_global_rib('10.0.0.0/24')), 1) 214 self.assertEqual(len(g1.get_global_rib('10.10.0.0/24')), 1) 215 for d in g1.get_global_rib(): 216 for p in d['paths']: 217 self.assertFalse(p.get('stale', False)) 218 219 def test_07_llgr_stale_route_depreferenced(self): 220 g1 = self.bgpds['g1'] 221 g2 = self.bgpds['g2'] 222 g3 = self.bgpds['g3'] 223 g4 = self.bgpds['g4'] 224 g4.local('gobgp global rib add 10.0.0.0/24 med 100') 225 time.sleep(1) 226 # check g2's path is chosen as best and advertised 227 rib = g3.get_global_rib('10.0.0.0/24') 228 self.assertEqual(len(rib), 1) 229 self.assertTrue(g2.asn in rib[0]['paths'][0]['aspath']) 230 231 g2.stop_gobgp() 232 g1.wait_for(expected_state=BGP_FSM_ACTIVE, peer=g2) 233 234 time.sleep(1) 235 236 # llgr_stale route depreference must happend 237 # check g4's path is chosen as best and advertised 238 rib = g3.get_global_rib('10.0.0.0/24') 239 self.assertEqual(len(rib), 1) 240 self.assertTrue(g4.asn in rib[0]['paths'][0]['aspath']) 241 242 # if no candidate exists, llgr_stale route will be chosen as best 243 rib = g3.get_global_rib('10.10.0.0/24') 244 self.assertEqual(len(rib), 1) 245 self.assertTrue(g2.asn in rib[0]['paths'][0]['aspath']) 246 247 def test_08_llgr_restart_timer_expire(self): 248 time.sleep(LONG_LIVED_GRACEFUL_RESTART_TIME + 5) 249 g3 = self.bgpds['g3'] 250 rib = g3.get_global_rib('10.10.0.0/24') 251 self.assertEqual(len(rib), 0) 252 253 254 if __name__ == '__main__': 255 output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) 256 if int(output) != 0: 257 print("docker not found") 258 sys.exit(1) 259 260 nose.main(argv=sys.argv, addplugins=[OptionParser()], 261 defaultTest=sys.argv[0])