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])