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