github.com/osrg/gobgp@v2.0.0+incompatible/test/scenario_test/bgp_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  import json
    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_ACTIVE,
    32      BGP_FSM_ESTABLISHED,
    33      BGP_ATTR_TYPE_MULTI_EXIT_DISC,
    34      BGP_ATTR_TYPE_LOCAL_PREF,
    35      wait_for_completion,
    36      assert_several_times,
    37  )
    38  from lib.gobgp import (
    39      GoBGPContainer,
    40      extract_path_attribute,
    41  )
    42  from lib.quagga import QuaggaBGPContainer
    43  from lib.exabgp import ExaBGPContainer
    44  
    45  
    46  class GoBGPTestBase(unittest.TestCase):
    47  
    48      @classmethod
    49      def setUpClass(cls):
    50          gobgp_ctn_image_name = parser_option.gobgp_image
    51          base.TEST_PREFIX = parser_option.test_prefix
    52  
    53          g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
    54                              ctn_image_name=gobgp_ctn_image_name,
    55                              log_level=parser_option.gobgp_log_level)
    56          q1 = QuaggaBGPContainer(name='q1', asn=65001, router_id='192.168.0.2')
    57          q2 = QuaggaBGPContainer(name='q2', asn=65002, router_id='192.168.0.3')
    58          q3 = QuaggaBGPContainer(name='q3', asn=65003, router_id='192.168.0.4')
    59  
    60          qs = [q1, q2, q3]
    61          ctns = [g1, q1, q2, q3]
    62  
    63          initial_wait_time = max(ctn.run() for ctn in ctns)
    64          time.sleep(initial_wait_time)
    65  
    66          for q in qs:
    67              g1.add_peer(q, passwd='passwd')
    68              q.add_peer(g1, passwd='passwd', passive=True)
    69  
    70          # advertise a route from q1, q2, q3
    71          for idx, q in enumerate(qs):
    72              route = '10.0.{0}.0/24'.format(idx + 1)
    73              q.add_route(route)
    74  
    75          cls.gobgp = g1
    76          cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3}
    77  
    78      # test each neighbor state is turned establish
    79      def test_01_neighbor_established(self):
    80          for q in self.quaggas.itervalues():
    81              self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q)
    82  
    83      def test_02_check_gobgp_global_rib(self):
    84          for q in self.quaggas.itervalues():
    85              # paths expected to exist in gobgp's global rib
    86              routes = q.routes.keys()
    87              timeout = 120
    88              interval = 1
    89              count = 0
    90  
    91              while True:
    92                  # gobgp's global rib
    93                  state = self.gobgp.get_neighbor_state(q)
    94                  self.assertEqual(state, BGP_FSM_ESTABLISHED)
    95                  global_rib = [p['prefix'] for p in self.gobgp.get_global_rib()]
    96  
    97                  for p in global_rib:
    98                      if p in routes:
    99                          routes.remove(p)
   100  
   101                  if len(routes) == 0:
   102                      break
   103  
   104                  time.sleep(interval)
   105                  count += interval
   106                  if count >= timeout:
   107                      raise Exception('timeout')
   108  
   109      # check gobgp properly add it's own asn to aspath
   110      def test_03_check_gobgp_adj_out_rib(self):
   111          for q in self.quaggas.itervalues():
   112              for path in self.gobgp.get_adj_rib_out(q):
   113                  asns = path['aspath']
   114                  self.assertTrue(self.gobgp.asn in asns)
   115  
   116      # check routes are properly advertised to all BGP speaker
   117      def test_04_check_quagga_global_rib(self):
   118          interval = 1
   119          timeout = int(120 / interval)
   120          for q in self.quaggas.itervalues():
   121              done = False
   122              for _ in range(timeout):
   123                  if done:
   124                      break
   125                  global_rib = q.get_global_rib()
   126                  global_rib = [p['prefix'] for p in global_rib]
   127                  if len(global_rib) < len(self.quaggas):
   128                      time.sleep(interval)
   129                      continue
   130  
   131                  self.assertEqual(len(global_rib), len(self.quaggas))
   132  
   133                  for c in self.quaggas.itervalues():
   134                      for r in c.routes:
   135                          self.assertTrue(r in global_rib)
   136                  done = True
   137              if done:
   138                  continue
   139              # should not reach here
   140              raise AssertionError
   141  
   142      def test_05_add_quagga(self):
   143          q4 = QuaggaBGPContainer(name='q4', asn=65004, router_id='192.168.0.5')
   144          self.quaggas['q4'] = q4
   145          initial_wait_time = q4.run()
   146          time.sleep(initial_wait_time)
   147  
   148          self.gobgp.add_peer(q4)
   149          q4.add_peer(self.gobgp)
   150  
   151          q4.add_route('10.0.4.0/24')
   152  
   153          self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q4)
   154  
   155      def test_06_check_global_rib(self):
   156          self.test_02_check_gobgp_global_rib()
   157          self.test_04_check_quagga_global_rib()
   158  
   159      def test_07_stop_one_quagga(self):
   160          g1 = self.gobgp
   161          q4 = self.quaggas['q4']
   162          q4.stop()
   163          self.gobgp.wait_for(expected_state=BGP_FSM_ACTIVE, peer=q4)
   164  
   165          g1.del_peer(q4)
   166          del self.quaggas['q4']
   167  
   168      # check gobgp properly send withdrawal message with q4's route
   169      def test_08_check_global_rib(self):
   170          self.test_02_check_gobgp_global_rib()
   171          self.test_04_check_quagga_global_rib()
   172  
   173      def test_09_add_distant_relative(self):
   174          q1 = self.quaggas['q1']
   175          q2 = self.quaggas['q2']
   176          q3 = self.quaggas['q3']
   177          q5 = QuaggaBGPContainer(name='q5', asn=65005, router_id='192.168.0.6')
   178  
   179          initial_wait_time = q5.run()
   180          time.sleep(initial_wait_time)
   181  
   182          for q in [q2, q3]:
   183              q5.add_peer(q)
   184              q.add_peer(q5)
   185  
   186          med200 = {'name': 'med200',
   187                    'type': 'permit',
   188                    'match': '0.0.0.0/0',
   189                    'med': 200}
   190          q2.add_policy(med200, self.gobgp, 'out')
   191          med100 = {'name': 'med100',
   192                    'type': 'permit',
   193                    'match': '0.0.0.0/0',
   194                    'med': 100}
   195          q3.add_policy(med100, self.gobgp, 'out')
   196  
   197          q5.add_route('10.0.6.0/24')
   198  
   199          self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q2)
   200          self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q3)
   201          q2.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q5)
   202          q3.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q5)
   203  
   204          timeout = 120
   205          interval = 1
   206          count = 0
   207          while True:
   208              paths = self.gobgp.get_adj_rib_out(q1, '10.0.6.0/24')
   209              if len(paths) > 0:
   210                  path = paths[0]
   211                  print "{0}'s nexthop is {1}".format(path['nlri']['prefix'],
   212                                                      path['nexthop'])
   213                  n_addrs = [i[1].split('/')[0] for i in self.gobgp.ip_addrs]
   214                  if path['nexthop'] in n_addrs:
   215                      break
   216  
   217              time.sleep(interval)
   218              count += interval
   219              if count >= timeout:
   220                  raise Exception('timeout')
   221  
   222      def test_10_originate_path(self):
   223          self.gobgp.add_route('10.10.0.0/24')
   224          dst = self.gobgp.get_global_rib('10.10.0.0/24')
   225          self.assertEqual(len(dst), 1)
   226          self.assertEqual(len(dst[0]['paths']), 1)
   227          path = dst[0]['paths'][0]
   228          self.assertEqual(path['nexthop'], '0.0.0.0')
   229          self.assertEqual(len(path['aspath']), 0)
   230  
   231      def test_11_check_adj_rib_out(self):
   232          for q in self.quaggas.itervalues():
   233              paths = self.gobgp.get_adj_rib_out(q, '10.10.0.0/24')
   234              self.assertEqual(len(paths), 1)
   235              path = paths[0]
   236              peer_info = self.gobgp.peers[q]
   237              local_addr = peer_info['local_addr'].split('/')[0]
   238              self.assertEqual(path['nexthop'], local_addr)
   239              self.assertEqual(path['aspath'], [self.gobgp.asn])
   240  
   241      def test_12_disable_peer(self):
   242          q1 = self.quaggas['q1']
   243          self.gobgp.disable_peer(q1)
   244          self.gobgp.wait_for(expected_state=BGP_FSM_IDLE, peer=q1)
   245  
   246          time.sleep(3)
   247  
   248          for route in q1.routes.iterkeys():
   249              dst = self.gobgp.get_global_rib(route)
   250              self.assertEqual(len(dst), 0)
   251  
   252              for q in self.quaggas.itervalues():
   253                  if q is q1:
   254                      continue
   255                  paths = self.gobgp.get_adj_rib_out(q, route)
   256                  self.assertEqual(len(paths), 0)
   257  
   258      def test_13_enable_peer(self):
   259          q1 = self.quaggas['q1']
   260          self.gobgp.enable_peer(q1)
   261          self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q1)
   262  
   263      def test_14_check_adj_rib_out(self):
   264          self.test_11_check_adj_rib_out()
   265  
   266      def test_15_check_active_connection(self):
   267          g1 = self.gobgp
   268          g2 = GoBGPContainer(name='g2', asn=65000, router_id='192.168.0.7',
   269                              ctn_image_name=self.gobgp.image,
   270                              log_level=parser_option.gobgp_log_level)
   271          time.sleep(g2.run())
   272          self.quaggas['g2'] = g2
   273          g2.add_peer(g1, passive=True)
   274          g1.add_peer(g2)
   275          g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=g2)
   276  
   277      def test_16_check_local_pref_and_med_handling(self):
   278          g1 = self.gobgp
   279          g1.add_route('10.20.0.0/24', local_pref=1000, med=2000)
   280          # iBGP peer
   281          g2 = self.quaggas['g2']
   282          paths = g2.get_global_rib('10.20.0.0/24')
   283          self.assertEqual(len(paths), 1)
   284          self.assertEqual(len(paths[0]['paths']), 1)
   285          path = paths[0]['paths'][0]
   286          local_pref = extract_path_attribute(path, BGP_ATTR_TYPE_LOCAL_PREF)
   287          self.assertEqual(local_pref['value'], 1000)
   288          med = extract_path_attribute(path, BGP_ATTR_TYPE_MULTI_EXIT_DISC)
   289          self.assertEqual(med['metric'], 2000)
   290  
   291          # eBGP peer
   292          q1 = self.quaggas['q1']
   293          paths = q1.get_global_rib('10.20.0.0/24')
   294          self.assertEqual(len(paths), 1)
   295          path = paths[0]
   296          local_pref = extract_path_attribute(path, BGP_ATTR_TYPE_LOCAL_PREF)
   297          # local_pref's default value is 100
   298          self.assertEqual(local_pref['value'], 100)
   299          med = extract_path_attribute(path, BGP_ATTR_TYPE_MULTI_EXIT_DISC)
   300          self.assertEqual(med['metric'], 2000)
   301  
   302      def test_17_check_shutdown(self):
   303          g1 = self.gobgp
   304          q1 = self.quaggas['q1']
   305          q2 = self.quaggas['q2']
   306          q3 = self.quaggas['q3']
   307  
   308          q2.add_route('20.0.0.0/24')
   309          q3.add_route('20.0.0.0/24')
   310  
   311          self.test_01_neighbor_established()
   312  
   313          self.test_02_check_gobgp_global_rib()
   314  
   315          paths = q1.get_global_rib('20.0.0.0/24')
   316          self.assertEqual(len(paths), 1)
   317          n_addrs = [i[1].split('/')[0] for i in self.gobgp.ip_addrs]
   318          self.assertIn(paths[0]['nexthop'], n_addrs)
   319  
   320          q3.stop()
   321  
   322          self.gobgp.wait_for(expected_state=BGP_FSM_ACTIVE, peer=q3)
   323  
   324          def f():
   325              paths = q1.get_global_rib('20.0.0.0/24')
   326              self.assertEqual(len(paths), 1)
   327              self.assertIn(paths[0]['nexthop'], n_addrs)
   328  
   329          assert_several_times(f)
   330  
   331          g1.del_peer(q3)
   332          del self.quaggas['q3']
   333  
   334      def test_18_check_withdrawal(self):
   335          g1 = self.gobgp
   336          q1 = self.quaggas['q1']
   337          q2 = self.quaggas['q2']
   338  
   339          g1.add_route('30.0.0.0/24')
   340          q1.add_route('30.0.0.0/24')
   341  
   342          self.test_01_neighbor_established()
   343  
   344          self.test_02_check_gobgp_global_rib()
   345  
   346          paths = g1.get_adj_rib_out(q1, '30.0.0.0/24')
   347          self.assertEqual(len(paths), 1)
   348          self.assertNotIn('source-id', paths[0])
   349          paths = g1.get_adj_rib_out(q2, '30.0.0.0/24')
   350          self.assertEqual(len(paths), 1)
   351          self.assertNotIn('source-id', paths[0])
   352  
   353          g1.local('gobgp global rib del 30.0.0.0/24')
   354  
   355          def f():
   356              paths = g1.get_adj_rib_out(q1, '30.0.0.0/24')
   357              self.assertEqual(len(paths), 0)
   358              paths = g1.get_adj_rib_out(q2, '30.0.0.0/24')
   359              self.assertEqual(len(paths), 1)
   360              self.assertEqual(paths[0]['source-id'], '192.168.0.2')
   361  
   362          assert_several_times(f)
   363  
   364      def test_19_check_grpc_add_neighbor(self):
   365          g1 = self.gobgp
   366          e1 = ExaBGPContainer(name='e1', asn=65000, router_id='192.168.0.7')
   367          time.sleep(e1.run())
   368          e1.add_peer(g1)
   369          self.quaggas['e1'] = e1
   370          n = e1.peers[g1]['local_addr'].split('/')[0]
   371          g1.local('gobgp n add {0} as 65000'.format(n))
   372          g1.add_peer(e1, reload_config=False)
   373  
   374          g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=e1)
   375  
   376      def test_20_check_grpc_del_neighbor(self):
   377          g1 = self.gobgp
   378          e1 = self.quaggas['e1']
   379          n = e1.peers[g1]['local_addr'].split('/')[0]
   380          g1.local('gobgp n del {0}'.format(n))
   381          g1.del_peer(e1, reload_config=False)
   382  
   383      def test_21_check_withdrawal_2(self):
   384          g1 = self.gobgp
   385          g2 = self.quaggas['g2']
   386  
   387          prefix = '40.10.0.0/24'
   388          g1.add_route(prefix)
   389          wait_for_completion(lambda: len(g1.get_global_rib(prefix)) == 1)
   390          wait_for_completion(lambda: len(g2.get_global_rib(prefix)) == 1)
   391  
   392          r = g2.local('gobgp monitor global rib -j', stream=True, tty=False)
   393  
   394          g1.local('gobgp global rib del 40.10.0.0/24')
   395          del g1.routes[prefix]
   396  
   397          wait_for_completion(lambda: len(g1.get_global_rib(prefix)) == 0)
   398          wait_for_completion(lambda: len(g2.get_global_rib(prefix)) == 0)
   399  
   400          ret = json.loads(r.next())
   401          self.assertEqual(ret[0]['nlri']['prefix'], prefix)
   402          self.assertTrue('withdrawal' in ret[0])
   403  
   404      def test_22_check_cli_sorted(self):
   405          g1 = self.gobgp
   406          cnt = 0
   407  
   408          def next_prefix():
   409              for i in range(100, 105):
   410                  for j in range(100, 105):
   411                      yield '{0}.{1}.0.0/24'.format(i, j)
   412  
   413          for p in next_prefix():
   414              g1.local('gobgp global rib add {0}'.format(p))
   415              cnt += 1
   416  
   417          cnt2 = 0
   418          g = next_prefix()
   419          n = g.next()
   420          for path in g1.local("gobgp global rib", capture=True).split('\n')[1:]:
   421              if [elem for elem in path.split(' ') if elem != ''][1] == n:
   422                  try:
   423                      cnt2 += 1
   424                      n = g.next()
   425                  except StopIteration:
   426                      break
   427  
   428          self.assertEqual(cnt, cnt2)
   429  
   430      def test_23_check_withdrawal3(self):
   431          gobgp_ctn_image_name = parser_option.gobgp_image
   432          g1 = self.gobgp
   433          g3 = GoBGPContainer(name='g3', asn=65006, router_id='192.168.0.8',
   434                              ctn_image_name=gobgp_ctn_image_name,
   435                              log_level=parser_option.gobgp_log_level)
   436          g4 = GoBGPContainer(name='g4', asn=65007, router_id='192.168.0.9',
   437                              ctn_image_name=gobgp_ctn_image_name,
   438                              log_level=parser_option.gobgp_log_level)
   439  
   440          initial_wait_time = max(ctn.run() for ctn in [g3, g4])
   441          time.sleep(initial_wait_time)
   442  
   443          self.quaggas = {'g3': g3, 'g4': g4}
   444  
   445          g3.local('gobgp global rib add 50.0.0.0/24')
   446  
   447          g1.add_peer(g3, passive=True)
   448          g3.add_peer(g1)
   449          g1.add_peer(g4, passive=True)
   450          g4.add_peer(g1)
   451  
   452          self.test_01_neighbor_established()
   453  
   454          self.test_02_check_gobgp_global_rib()
   455  
   456          g4.local('gobgp global rib add 50.0.0.0/24 med 10')
   457  
   458          paths = g1.get_adj_rib_out(g3, '50.0.0.0/24')
   459          self.assertEqual(len(paths), 0)
   460          paths = g1.get_adj_rib_out(g4, '50.0.0.0/24')
   461          self.assertEqual(len(paths), 1)
   462          self.assertEqual(paths[0]['source-id'], '192.168.0.8')
   463  
   464          g3.local('gobgp global rib del 50.0.0.0/24')
   465  
   466          paths = g1.get_adj_rib_out(g3, '50.0.0.0/24')
   467          self.assertEqual(len(paths), 1)
   468          self.assertEqual(paths[0]['source-id'], '192.168.0.9')
   469          paths = g1.get_adj_rib_out(g4, '50.0.0.0/24')
   470          self.assertEqual(len(paths), 0)
   471  
   472  
   473  if __name__ == '__main__':
   474      output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True)
   475      if int(output) is not 0:
   476          print "docker not found"
   477          sys.exit(1)
   478  
   479      nose.main(argv=sys.argv, addplugins=[OptionParser()],
   480                defaultTest=sys.argv[0])