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