github.com/osrg/gobgp@v2.0.0+incompatible/test/scenario_test/route_reflector_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 sys
    19  import time
    20  import unittest
    21  
    22  from fabric.api import local
    23  import nose
    24  
    25  from lib.noseplugin import OptionParser, parser_option
    26  
    27  from lib import base
    28  from lib.base import BGP_FSM_ESTABLISHED
    29  from lib.gobgp import GoBGPContainer
    30  from lib.quagga import QuaggaBGPContainer
    31  
    32  
    33  def wait_for(f, timeout=120):
    34      interval = 1
    35      count = 0
    36      while True:
    37          if f():
    38              return
    39  
    40          time.sleep(interval)
    41          count += interval
    42          if count >= timeout:
    43              raise Exception('timeout')
    44  
    45  
    46  class GoBGPTestBase(unittest.TestCase):
    47      def assert_adv_count(self, src, dst, rf, count):
    48          self.assertEqual(count, len(src.get_adj_rib_out(dst, rf=rf)))
    49          self.assertEqual(count, len(dst.get_adj_rib_in(src, rf=rf)))
    50  
    51      def assert_upd_count(self, src, dst, sent, received):
    52          messages = src.get_neighbor(dst)['state']['messages']
    53          self.assertEqual(messages['sent'].get('update', 0), sent)
    54          self.assertEqual(messages['received'].get('update', 0), received)
    55  
    56      @classmethod
    57      def setUpClass(cls):
    58          gobgp_ctn_image_name = parser_option.gobgp_image
    59          base.TEST_PREFIX = parser_option.test_prefix
    60  
    61          g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
    62                              ctn_image_name=gobgp_ctn_image_name,
    63                              log_level=parser_option.gobgp_log_level)
    64          q1 = QuaggaBGPContainer(name='q1', asn=65000, router_id='192.168.0.2')
    65          q2 = QuaggaBGPContainer(name='q2', asn=65000, router_id='192.168.0.3')
    66          q3 = QuaggaBGPContainer(name='q3', asn=65000, router_id='192.168.0.4')
    67          q4 = QuaggaBGPContainer(name='q4', asn=65000, router_id='192.168.0.5')
    68  
    69          qs = [q1, q2, q3, q4]
    70          ctns = [g1, q1, q2, q3, q4]
    71  
    72          initial_wait_time = max(ctn.run() for ctn in ctns)
    73          time.sleep(initial_wait_time)
    74  
    75          # g1 as a route reflector
    76          g1.add_peer(q1, is_rr_client=True)
    77          q1.add_peer(g1)
    78          g1.add_peer(q2, is_rr_client=True)
    79          q2.add_peer(g1)
    80          g1.add_peer(q3)
    81          q3.add_peer(g1)
    82          g1.add_peer(q4)
    83          q4.add_peer(g1)
    84  
    85          # advertise a route from q1, q2
    86          for idx, c in enumerate(qs):
    87              route = '10.0.{0}.0/24'.format(idx + 1)
    88              c.add_route(route)
    89  
    90          cls.gobgp = g1
    91          cls.quaggas = {'q1': q1, 'q2': q2, 'q3': q3, 'q4': q4}
    92  
    93      # test each neighbor state is turned establish
    94      def test_01_neighbor_established(self):
    95          for q in self.quaggas.itervalues():
    96              self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=q)
    97  
    98      def test_02_check_gobgp_global_rib(self):
    99          for q in self.quaggas.itervalues():
   100              # paths expected to exist in gobgp's global rib
   101              def f():
   102                  state = self.gobgp.get_neighbor_state(q)
   103                  self.assertEqual(state, BGP_FSM_ESTABLISHED)
   104  
   105                  routes = q.routes.keys()
   106                  global_rib = [p['prefix'] for p in self.gobgp.get_global_rib()]
   107                  for p in global_rib:
   108                      if p in routes:
   109                          routes.remove(p)
   110  
   111                  return len(routes) == 0
   112              wait_for(f)
   113  
   114      def test_03_check_gobgp_adj_rib_out(self):
   115          for q in self.quaggas.itervalues():
   116              paths = [p['nlri']['prefix'] for p in self.gobgp.get_adj_rib_out(q)]
   117              for qq in self.quaggas.itervalues():
   118                  if q == qq:
   119                      continue
   120                  if self.gobgp.peers[q]['is_rr_client']:
   121                      for p in qq.routes.keys():
   122                          self.assertTrue(p in paths)
   123                  else:
   124                      for p in qq.routes.keys():
   125                          if self.gobgp.peers[qq]['is_rr_client']:
   126                              self.assertTrue(p in paths)
   127                          else:
   128                              self.assertFalse(p in paths)
   129  
   130      def test_10_setup_rr_rtc_isolation_policy(self):
   131          #                              +-------+
   132          #                              |  rr   |
   133          #        +----------------+----| (RR)  |---+----------------+
   134          #        |                |    +-------+   |                |
   135          #        |                |                |                |
   136          #      (iBGP)           (iBGP)           (iBGP)          (iBGP)
   137          #        |                |                |                |
   138          # +-------------+  +-------------+  +-------------+  +-------------+
   139          # |     acme1   |  |    acme2    |  |   tyrell1   |  |   tyrell2   |
   140          # | (RR Client) |  | (RR Client) |  | (RR Client) |  | (RR Client) |
   141          # +-------------+  +-------------+  +-------------+  +-------------+
   142  
   143  
   144          gobgp_ctn_image_name = parser_option.gobgp_image
   145          rr = GoBGPContainer(name='rr', asn=65000, router_id='192.168.1.1',
   146                              ctn_image_name=gobgp_ctn_image_name,
   147                              log_level=parser_option.gobgp_log_level)
   148          acme1 = GoBGPContainer(name='acme1', asn=65000, router_id='192.168.1.101',
   149                                 ctn_image_name=gobgp_ctn_image_name,
   150                                 log_level=parser_option.gobgp_log_level)
   151          acme2 = GoBGPContainer(name='acme2', asn=65000, router_id='192.168.1.102',
   152                                 ctn_image_name=gobgp_ctn_image_name,
   153                                 log_level=parser_option.gobgp_log_level)
   154  
   155          tyrell1 = GoBGPContainer(name='tyrell1', asn=65000, router_id='192.168.1.201',
   156                                   ctn_image_name=gobgp_ctn_image_name,
   157                                   log_level=parser_option.gobgp_log_level)
   158  
   159          tyrell2 = GoBGPContainer(name='tyrell2', asn=65000, router_id='192.168.1.202',
   160                                   ctn_image_name=gobgp_ctn_image_name,
   161                                   log_level=parser_option.gobgp_log_level)
   162  
   163          time.sleep(max(ctn.run() for ctn in [rr, acme1, acme2, tyrell1, tyrell2]))
   164  
   165          rr.add_peer(acme1, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True)
   166          acme1.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True)
   167  
   168          rr.add_peer(acme2, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True)
   169          acme2.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True)
   170  
   171          rr.add_peer(tyrell1, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True)
   172          tyrell1.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True)
   173  
   174          rr.add_peer(tyrell2, vpn=True, addpath=True, graceful_restart=True, llgr=True, is_rr_client=True)
   175          tyrell2.add_peer(rr, vpn=True, addpath=True, graceful_restart=True, llgr=True)
   176  
   177          self.__class__.rr = rr
   178          self.__class__.acme1 = acme1
   179          self.__class__.acme2 = acme2
   180          self.__class__.tyrell1 = tyrell1
   181          self.__class__.tyrell2 = tyrell2
   182  
   183          # add import/export policy to allow peers exchange routes within specific RTs
   184          # later tests should not break due to RTC Updates being filtered-out
   185  
   186          rr.local("gobgp policy neighbor add clients-acme {} {}".format(
   187              rr.peer_name(acme1),
   188              rr.peer_name(acme2)))
   189  
   190          rr.local("gobgp policy neighbor add clients-tyrell {} {}".format(
   191              rr.peer_name(tyrell1),
   192              rr.peer_name(tyrell2)))
   193  
   194          rr.local("gobgp policy ext-community add rts-acme   rt:^100:.*$")
   195          rr.local("gobgp policy ext-community add rts-tyrell rt:^200:.*$")
   196  
   197          rr.local('gobgp policy statement add allow-rtc')
   198          rr.local('gobgp policy statement allow-rtc add condition afi-safi-in rtc')
   199          rr.local('gobgp policy statement allow-rtc add action accept')
   200  
   201          rr.local('gobgp policy statement add allow-acme')
   202          rr.local('gobgp policy statement allow-acme add condition neighbor clients-acme')
   203          rr.local('gobgp policy statement allow-acme add condition ext-community rts-acme')
   204          rr.local('gobgp policy statement allow-acme add action accept')
   205  
   206          rr.local('gobgp policy statement add allow-tyrell')
   207          rr.local('gobgp policy statement allow-tyrell add condition neighbor clients-tyrell')
   208          rr.local('gobgp policy statement allow-tyrell add condition ext-community rts-tyrell')
   209          rr.local('gobgp policy statement allow-tyrell add action accept')
   210          rr.local('gobgp policy add tenancy allow-rtc allow-acme allow-tyrell')
   211  
   212          rr.local('gobgp global policy import add tenancy default reject')
   213          rr.local('gobgp global policy export add tenancy default reject')
   214  
   215          acme1.local("gobgp vrf add a1 rd 100:100 rt both 100:100")
   216          acme2.local("gobgp vrf add a1 rd 100:100 rt both 100:100")
   217  
   218          tyrell1.local("gobgp vrf add t1 rd 200:100 rt both 200:100")
   219          tyrell2.local("gobgp vrf add t1 rd 200:100 rt both 200:100")
   220  
   221          rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=acme1)
   222          rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=acme2)
   223          rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=tyrell1)
   224          rr.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=tyrell2)
   225  
   226      def test_11_routes_in_allowed_acme_rts_are_exchanged(self):
   227          self.acme1.local("gobgp vrf a1 rib add 10.10.0.0/16 local-pref 100")
   228          self.acme2.local("gobgp vrf a1 rib add 10.20.0.0/16")
   229          self.tyrell1.local("gobgp vrf t1 rib add 20.10.0.0/16")
   230          self.tyrell2.local("gobgp vrf t1 rib add 20.20.0.0/16")
   231          time.sleep(1)
   232  
   233          self.assert_adv_count(self.rr, self.acme1, 'rtc', 2)
   234          self.assert_adv_count(self.rr, self.acme1, 'ipv4-l3vpn', 1)
   235          self.assert_adv_count(self.rr, self.acme2, 'rtc', 2)
   236          self.assert_adv_count(self.rr, self.acme2, 'ipv4-l3vpn', 1)
   237          self.assert_adv_count(self.rr, self.tyrell1, 'rtc', 2)
   238          self.assert_adv_count(self.rr, self.tyrell1, 'ipv4-l3vpn', 1)
   239          self.assert_adv_count(self.rr, self.tyrell2, 'rtc', 2)
   240          self.assert_adv_count(self.rr, self.tyrell2, 'ipv4-l3vpn', 1)
   241  
   242      def test_12_routes_from_separate_rts_peers_are_isolated_by_rr(self):
   243          self.tyrell1.local("gobgp vrf add a1 rd 100:100 rt both 100:100")
   244          self.tyrell1.local("gobgp vrf a1 rib add 10.10.0.0/16 local-pref 200")
   245          self.tyrell1.local("gobgp vrf a1 rib add 10.30.0.0/16")
   246          time.sleep(1)
   247  
   248          rr_t2_in = self.rr.get_adj_rib_in(self.tyrell1, rf='ipv4-l3vpn')
   249          self.assertEqual(3, len(rr_t2_in))
   250  
   251          rr_a2_out = self.rr.get_adj_rib_out(self.acme2, rf='ipv4-l3vpn')
   252          self.assertEqual(1, len(rr_a2_out))
   253  
   254          a2_routes = self.acme2.get_adj_rib_in(self.rr, rf='ipv4-l3vpn')
   255          self.assertEqual(1, len(a2_routes))
   256          ar0 = a2_routes[0]
   257          self.assertEqual('10.10.0.0/16', ar0['prefix'])
   258          self.assertEqual(self.rr.peer_name(self.acme1), ar0['nexthop'])
   259          self.assertEqual(100, ar0['local-pref'])
   260  
   261  
   262  if __name__ == '__main__':
   263      output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True)
   264      if int(output) is not 0:
   265          print "docker not found"
   266          sys.exit(1)
   267  
   268      nose.main(argv=sys.argv, addplugins=[OptionParser()],
   269                defaultTest=sys.argv[0])