github.com/osrg/gobgp/v3@v3.30.0/test/scenario_test/addpath_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  import sys
    17  import json
    18  import time
    19  import unittest
    20  
    21  import collections
    22  collections.Callable = collections.abc.Callable
    23  
    24  import nose
    25  
    26  from lib import base
    27  from lib.base import (
    28      BGP_FSM_ESTABLISHED,
    29      assert_several_times,
    30      local,
    31  )
    32  from lib.gobgp import GoBGPContainer
    33  from lib.exabgp import ExaBGPContainer
    34  from lib.noseplugin import OptionParser, parser_option
    35  
    36  
    37  class GoBGPTestBase(unittest.TestCase):
    38      SEND_MAX = 5
    39      INSTALLED_PATHS = SEND_MAX + 1
    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=65000, 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=65000, 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=65000, router_id="192.168.0.4",
    56                              ctn_image_name=gobgp_ctn_image_name,
    57                              log_level=parser_option.gobgp_log_level)
    58          g5 = GoBGPContainer(name="g5", asn=65000,router_id="192.168.0.5",
    59                              ctn_image_name=gobgp_ctn_image_name,
    60                              log_level=parser_option.gobgp_log_level)
    61          e1 = ExaBGPContainer(name="e1", asn=65000, router_id="192.168.0.6")
    62  
    63          ctns = [g1, g2, g3, g4, g5, e1]
    64          initial_wait_time = max(ctn.run() for ctn in ctns)
    65  
    66          time.sleep(initial_wait_time)
    67  
    68          g1.add_peer(e1, addpath=16)
    69          e1.add_peer(g1, addpath=16)
    70  
    71          g1.add_peer(g2, is_rr_client=True)
    72          g2.add_peer(g1)
    73  
    74          g1.add_peer(g3, addpath=cls.SEND_MAX, is_rr_client=True)
    75          g3.add_peer(g1, addpath=cls.SEND_MAX)
    76  
    77          g4.add_peer(g5, addpath=cls.SEND_MAX)
    78          g5.add_peer(g4, addpath=cls.SEND_MAX)
    79  
    80          cls.g1 = g1
    81          cls.g2 = g2
    82          cls.g3 = g3
    83          cls.g4 = g4
    84          cls.g5 = g5
    85          cls.e1 = e1
    86  
    87      # test each neighbor state is turned establish
    88      def test_00_neighbor_established(self):
    89          self.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.g2)
    90          self.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.g3)
    91          self.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.e1)
    92          self.g4.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.g5)
    93  
    94      # prepare routes with path_id (no error check)
    95      def test_01_prepare_add_paths_routes(self):
    96          aspath = []
    97          for i in range(self.INSTALLED_PATHS):
    98              aspath.append((i + 1) * 100)
    99              self.e1.add_route(
   100                  route="192.168.100.0/24",
   101                  identifier=(i + 1) * 10,
   102                  aspath=aspath,
   103              )
   104  
   105          # update multiple time the same route
   106          # and expect the route counter to increment only once
   107          for i in range(self.INSTALLED_PATHS):
   108              self.g4.add_route(
   109                  route="192.168.100.0/24",
   110                  identifier=10,
   111                  local_pref=i + 100 + 1,
   112              )
   113  
   114      def test_02_check_g4_adj_out(self):
   115          def f():
   116              # the last update should have been received by g5
   117              rib = self.g4.get_adj_rib_out(self.g5, add_path_enabled=True)
   118              self.assertEqual(len(rib), 1)
   119              self.assertEqual(len(rib[0]["paths"]), 1)
   120              self.assertEqual(
   121                  rib[0]["paths"][0]["local-pref"], 100 + self.INSTALLED_PATHS
   122              )
   123              self.assertFalse(rib[0]["paths"][0].get("send-max-filtered", False))
   124  
   125          assert_several_times(f)
   126  
   127      def test_03_check_g5_global_rib(self):
   128          def f():
   129              # the last update should have been received by g5
   130              rib = self.g5.get_global_rib()
   131              self.assertEqual(len(rib), 1)
   132              self.assertEqual(len(rib[0]["paths"]), 1)
   133              self.assertEqual(
   134                  rib[0]["paths"][0]["local-pref"], 100 + self.INSTALLED_PATHS
   135              )
   136  
   137          assert_several_times(f)
   138  
   139      # test INSTALLED_PATHS routes are installed to the rib due to add-path feature
   140      def test_04_check_g1_global_rib(self):
   141          def f():
   142              rib = self.g1.get_global_rib()
   143              self.assertEqual(len(rib), 1)
   144              self.assertEqual(len(rib[0]["paths"]), self.INSTALLED_PATHS)
   145  
   146          assert_several_times(f)
   147  
   148      # test only the best path is advertised to g2
   149      def test_05_check_g2_global_rib(self):
   150          def f():
   151              rib = self.g2.get_global_rib()
   152              self.assertEqual(len(rib), 1)
   153              self.assertEqual(len(rib[0]['paths']), 1)
   154              self.assertEqual(len(rib[0]["paths"][0]["aspath"]), 1)
   155  
   156          assert_several_times(f)
   157  
   158      # test SEND_MAX routes are advertised to g3
   159      def test_06_check_g3_global_rib(self):
   160          def f():
   161              rib = self.g3.get_global_rib()
   162              self.assertEqual(len(rib), 1)
   163              self.assertEqual(len(rib[0]["paths"]), self.SEND_MAX)
   164  
   165          assert_several_times(f)
   166  
   167      def test_07_check_g1_adj_out(self):
   168          adj_out = self.g1.get_adj_rib_out(self.g2, add_path_enabled=True)
   169          self.assertEqual(len(adj_out), 1)
   170          self.assertEqual(len(adj_out[0]["paths"]), 1)
   171  
   172          adj_out = self.g1.get_adj_rib_out(self.g3, add_path_enabled=True)
   173          self.assertEqual(len(adj_out), 1)
   174          self.assertEqual(len(adj_out[0]["paths"]), self.INSTALLED_PATHS)
   175          # expect the last path to be filtered
   176          self.assertTrue(adj_out[0]["paths"][-1].get("send-max-filtered", False))
   177  
   178      # withdraw a route with path_id (no error check)
   179      def test_08_withdraw_route_with_path_id(self):
   180          self.e1.del_route(route="192.168.100.0/24", identifier=10)
   181  
   182      # test the withdrawn route is removed from the rib
   183      def test_09_check_g1_global_rib(self):
   184          def f():
   185              rib = self.g1.get_global_rib()
   186              self.assertEqual(len(rib), 1)
   187              self.assertEqual(len(rib[0]["paths"]), self.INSTALLED_PATHS - 1)
   188              # we deleted the highest priority path
   189              for path in rib[0]['paths']:
   190                  self.assertTrue(2 <= len(path["aspath"]) <= self.INSTALLED_PATHS)
   191  
   192          assert_several_times(f)
   193  
   194      def test_10_check_g1_adj_out(self):
   195          adj_out = self.g1.get_adj_rib_out(self.g2, add_path_enabled=True)
   196          self.assertEqual(len(adj_out), 1)
   197          self.assertEqual(len(adj_out[0]["paths"]), 1)
   198  
   199          adj_out = self.g1.get_adj_rib_out(self.g3, add_path_enabled=True)
   200          self.assertEqual(len(adj_out), 1)
   201          self.assertEqual(len(adj_out[0]["paths"]), self.SEND_MAX)
   202          # expect the last path to not be filtered
   203          self.assertFalse(adj_out[0]["paths"][-1].get("send-max-filtered", False))
   204  
   205      # test the best path is replaced due to the removal from g1 rib
   206      def test_11_check_g2_global_rib(self):
   207          def f():
   208              rib = self.g2.get_global_rib()
   209              self.assertEqual(len(rib), 1)
   210              self.assertEqual(len(rib[0]['paths']), 1)
   211              self.assertEqual(len(rib[0]["paths"][0]["aspath"]), 2)
   212  
   213          assert_several_times(f)
   214  
   215      # test the withdrawn route is removed from the rib of g3
   216      # and the filtered route is advertised to g3
   217      def test_12_check_g3_global_rib(self):
   218          def f():
   219              rib = self.g3.get_global_rib()
   220              self.assertEqual(len(rib), 1)
   221              self.assertEqual(len(rib[0]["paths"]), self.SEND_MAX)
   222              for path in rib[0]['paths']:
   223                  self.assertTrue(2 <= len(path["aspath"]) <= self.INSTALLED_PATHS)
   224  
   225          assert_several_times(f)
   226  
   227      # install a route with path_id via GoBGP CLI (no error check)
   228      def test_13_install_add_paths_route_via_cli(self):
   229          # identifier is duplicated with the identifier of the route from e1
   230          self.g1.add_route(route='192.168.100.0/24', identifier=10, local_pref=500)
   231  
   232      # test the route from CLI is installed to the rib
   233      def test_14_check_g1_global_rib(self):
   234          def f():
   235              rib = self.g1.get_global_rib()
   236              self.assertEqual(len(rib), 1)
   237              self.assertEqual(len(rib[0]["paths"]), self.INSTALLED_PATHS)
   238              for path in rib[0]['paths']:
   239                  if not path["aspath"]:
   240                      self.assertEqual(path['local-pref'], 500)
   241                  else:
   242                      self.assertTrue(2 <= len(path["aspath"]) <= self.INSTALLED_PATHS)
   243  
   244          assert_several_times(f)
   245  
   246      def test_15_check_g1_adj_out(self):
   247          adj_out = self.g1.get_adj_rib_out(self.g2, add_path_enabled=True)
   248          self.assertEqual(len(adj_out), 1)
   249          self.assertEqual(len(adj_out[0]["paths"]), 1)
   250  
   251          adj_out = self.g1.get_adj_rib_out(self.g3, add_path_enabled=True)
   252          self.assertEqual(len(adj_out), 1)
   253          self.assertEqual(len(adj_out[0]["paths"]), self.INSTALLED_PATHS)
   254          # the new best path shouldn't be advertised as it is added after
   255          # the limit is reached
   256          self.assertEqual(adj_out[0]["paths"][0]["local-pref"], 500)
   257          self.assertTrue(adj_out[0]["paths"][0].get("send-max-filtered", False))
   258  
   259      # test the best path is replaced due to the CLI route from g1 rib
   260      def test_16_check_g2_global_rib(self):
   261          def f():
   262              rib = self.g2.get_global_rib()
   263              self.assertEqual(len(rib), 1)
   264              self.assertEqual(len(rib[0]['paths']), 1)
   265              self.assertEqual(len(rib[0]["paths"][0]["aspath"]), 0)
   266              self.assertEqual(rib[0]["paths"][0]["local-pref"], 500)
   267  
   268          assert_several_times(f)
   269  
   270      # test the route from CLI is advertised from g1
   271      def test_17_check_g3_global_rib(self):
   272          def f():
   273              rib = self.g3.get_global_rib()
   274              self.assertEqual(len(rib), 1)
   275              self.assertEqual(len(rib[0]["paths"]), self.SEND_MAX)
   276              for path in rib[0]['paths']:
   277                  self.assertTrue(2 <= len(path["aspath"]) <= self.INSTALLED_PATHS)
   278  
   279          assert_several_times(f)
   280  
   281      # remove non-existing route with path_id via GoBGP CLI (no error check)
   282      def test_18_remove_non_existing_add_paths_route_via_cli(self):
   283          # specify locally non-existing identifier which has the same value
   284          # with the identifier of the route from e1
   285          self.g1.del_route(route='192.168.100.0/24', identifier=20)
   286  
   287      # test none of route is removed by non-existing path_id via CLI
   288      def test_19_check_g1_global_rib(self):
   289          def f():
   290              rib = self.g1.get_global_rib()
   291              self.assertEqual(len(rib), 1)
   292              self.assertEqual(len(rib[0]["paths"]), self.INSTALLED_PATHS)
   293              for path in rib[0]['paths']:
   294                  if not path["aspath"]:
   295                      self.assertEqual(path['local-pref'], 500)
   296                  else:
   297                      self.assertTrue(2 <= len(path["aspath"]) <= self.INSTALLED_PATHS)
   298  
   299          assert_several_times(f)
   300  
   301      # remove route with path_id via GoBGP CLI (no error check)
   302      def test_20_remove_add_paths_route_via_cli(self):
   303          self.g1.del_route(route='192.168.100.0/24', identifier=10)
   304  
   305      def test_21_check_g1_adj_out(self):
   306          adj_out = self.g1.get_adj_rib_out(self.g2, add_path_enabled=True)
   307          self.assertEqual(len(adj_out), 1)
   308          self.assertEqual(len(adj_out[0]["paths"]), 1)
   309  
   310          adj_out = self.g1.get_adj_rib_out(self.g3, add_path_enabled=True)
   311          self.assertEqual(len(adj_out), 1)
   312          self.assertEqual(len(adj_out[0]["paths"]), self.INSTALLED_PATHS - 1)
   313  
   314      # test the route is removed from the rib via CLI
   315      def test_22_check_g1_global_rib(self):
   316          def f():
   317              rib = self.g1.get_global_rib()
   318              self.assertEqual(len(rib), 1)
   319              self.assertEqual(len(rib[0]["paths"]), self.INSTALLED_PATHS - 1)
   320              for path in rib[0]['paths']:
   321                  if not path["aspath"]:
   322                      self.assertTrue(2 <= len(path["aspath"]) <= self.INSTALLED_PATHS)
   323  
   324          assert_several_times(f)
   325  
   326      # test the best path is replaced the removal from g1 rib
   327      def test_23_check_g2_global_rib(self):
   328          def f():
   329              rib = self.g2.get_global_rib()
   330              self.assertEqual(len(rib), 1)
   331              self.assertEqual(len(rib[0]['paths']), 1)
   332              self.assertEqual(len(rib[0]["paths"][0]["aspath"]), 2)
   333  
   334          assert_several_times(f)
   335  
   336      # test the removed route from CLI is withdrawn by g1
   337      def test_24_check_g3_global_rib(self):
   338          def f():
   339              rib = self.g3.get_global_rib()
   340              self.assertEqual(len(rib), 1)
   341              self.assertEqual(len(rib[0]["paths"]), self.SEND_MAX)
   342              for path in rib[0]['paths']:
   343                  if not path["aspath"]:
   344                      self.assertTrue(2 <= len(path["aspath"]) <= self.INSTALLED_PATHS)
   345  
   346          assert_several_times(f)
   347  
   348  
   349  if __name__ == '__main__':
   350      output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True)
   351      if int(output) != 0:
   352          print("docker not found")
   353          sys.exit(1)
   354  
   355      nose.main(argv=sys.argv, addplugins=[OptionParser()],
   356                defaultTest=sys.argv[0])