github.com/osrg/gobgp@v2.0.0+incompatible/test/scenario_test/flow_spec_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.exabgp import ExaBGPContainer
    31  from lib.yabgp import YABGPContainer
    32  
    33  
    34  class FlowSpecTest(unittest.TestCase):
    35  
    36      """
    37      Test case for Flow Specification.
    38      """
    39      # +------------+            +------------+
    40      # | G1(GoBGP)  |---(iBGP)---| E1(ExaBGP) |
    41      # | 172.17.0.2 |            | 172.17.0.3 |
    42      # +------------+            +------------+
    43      #      |
    44      #    (iBGP)
    45      #      |
    46      # +------------+
    47      # | Y1(YABGP)  |
    48      # | 172.17.0.4 |
    49      # +------------+
    50  
    51      @classmethod
    52      def setUpClass(cls):
    53          gobgp_ctn_image_name = parser_option.gobgp_image
    54          base.TEST_PREFIX = parser_option.test_prefix
    55  
    56          cls.g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
    57                                  ctn_image_name=gobgp_ctn_image_name,
    58                                  log_level=parser_option.gobgp_log_level)
    59  
    60          cls.e1 = ExaBGPContainer(name='e1', asn=65000, router_id='192.168.0.2')
    61  
    62          cls.y1 = YABGPContainer(name='y1', asn=65000, router_id='192.168.0.3')
    63  
    64          ctns = [cls.g1, cls.e1, cls.y1]
    65          initial_wait_time = max(ctn.run() for ctn in ctns)
    66          time.sleep(initial_wait_time)
    67  
    68          # Add FlowSpec routes into GoBGP.
    69          cls.g1.add_route(
    70              route='ipv4/all',
    71              rf='ipv4-flowspec',
    72              matchs=[
    73                  'destination 11.1.0.0/24',
    74                  'source 11.2.0.0/24',
    75                  "protocol '==tcp &=udp icmp >igmp >=egp <ipip <=rsvp !=gre'",
    76                  "port '==80 &=90 8080 >9090 >=8180 <9190 <=8081 !=9091 &!443'",
    77                  'destination-port 80',
    78                  'source-port 8080',
    79                  'icmp-type 0',
    80                  'icmp-code 2',
    81                  "tcp-flags '==S &=SA A !F !=U =!R'",
    82                  'packet-length 100',
    83                  'dscp 12',
    84                  'fragment dont-fragment is-fragment+first-fragment',
    85              ],
    86              thens=['discard'])
    87          cls.g1.add_route(
    88              route='ipv6/dst/src/label',  # others are tested on IPv4
    89              rf='ipv6-flowspec',
    90              matchs=[
    91                  'destination 2001:1::/64 10',
    92                  'source 2001:2::/64 15',
    93                  'label 12',
    94              ],
    95              thens=['discard'])
    96  
    97          cls.g1.add_peer(cls.e1, flowspec=True)
    98          cls.e1.add_peer(cls.g1, flowspec=True)
    99          cls.g1.add_peer(cls.y1, flowspec=True)
   100          cls.y1.add_peer(cls.g1, flowspec=True)
   101  
   102          cls.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=cls.e1)
   103          cls.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=cls.y1)
   104  
   105          # Add FlowSpec routes into ExaBGP.
   106          cls.e1.add_route(
   107              route='ipv4/all',
   108              rf='ipv4-flowspec',
   109              matchs=[
   110                  'destination 12.1.0.0/24',
   111                  'source 12.2.0.0/24',
   112                  'protocol =tcp',
   113                  'port >=80',
   114                  'destination-port >5000',
   115                  'source-port 8080',
   116                  'icmp-type <1',
   117                  'icmp-code <=2',
   118                  "tcp-flags FIN",
   119                  'packet-length >100&<200',
   120                  'dscp 12',
   121                  'fragment dont-fragment',
   122              ],
   123              thens=['discard'])
   124          cls.e1.add_route(
   125              route='ipv6/dst/src/protocol/label',  # others are tested on IPv4
   126              rf='ipv6-flowspec',
   127              matchs=[
   128                  'destination 2002:1::/64/10',
   129                  'source 2002:2::/64/15',
   130                  'next-header udp',
   131                  'flow-label >100',
   132              ],
   133              thens=['discard'])
   134  
   135          # Add FlowSpec routes into YABGP.
   136          cls.y1.add_route(
   137              route='ipv4/all',
   138              rf='ipv4-flowspec',
   139              matchs=[
   140                  'destination 13.1.0.0/24',
   141                  'source 13.2.0.0/24',
   142                  "protocol =6|=17",
   143                  # "port",  # not seem to be supported
   144                  'destination-port =80',
   145                  'source-port <8080|>9090',
   146                  'icmp-type >=1',
   147                  'icmp-code <2',
   148                  # "tcp-flags",  # not seem to be supported via REST API
   149                  'packet-length <=100',
   150                  'dscp =12',
   151                  # "fragment",  # not seem to be supported via REST API
   152              ],
   153              thens=['traffic-rate:0:0'])  # 'discard'
   154          # IPv6 FlowSpec: not supported with YABGP v0.4.0
   155          # cls.y1.add_route(
   156          #     route='ipv6/dst/src/label',  # others are tested on IPv4
   157          #     rf='ipv6-flowspec',
   158          #     matchs=[
   159          #         'destination 2003:1::/64/10',
   160          #         'source 2003:2::/64/15',
   161          #         'label 12',
   162          #     ],
   163          #     thens=['traffic-rate:0:0'])  # 'discard'
   164  
   165      def test_01_ipv4_exabgp_adj_rib_in(self):
   166          rib = self.e1.get_adj_rib_in(self.g1, rf='ipv4-flowspec')
   167          self.assertEqual(1, len(rib))
   168          nlri = list(rib)[0]  # advertised from G1(GoBGP)
   169          _exp_fmt = (
   170              # INPUTS:
   171              # 'destination 11.1.0.0/24',
   172              "destination-ipv4 11.1.0.0/24 "
   173              # 'source 11.2.0.0/24',
   174              "source-ipv4 11.2.0.0/24 "
   175              # "protocol '==tcp &=udp icmp >igmp >=egp <ipip <=rsvp !=gre'",
   176              "protocol [ =tcp&=udp =icmp >igmp >=egp <ipip <=rsvp !=gre ] "
   177              # "port '==80 &=90 8080 >9090 >=8180 <9190 <=8081 !=9091 &!443'",
   178              "port [ =80&=90 =8080 >9090 >=8180 <9190 <=8081 !=9091&!=443 ] "
   179              # 'destination-port 80',
   180              "destination-port =80 "
   181              # 'source-port 8080',
   182              "source-port =8080 "
   183              # 'icmp-type 0',
   184              "icmp-type =echo-reply "
   185              # 'icmp-code 2',
   186              "icmp-code =2 "
   187              # "tcp-flags '==S &=SA A !F !=U =!R'",
   188              "tcp-flags [ =syn&=%s ack !fin !=urgent !=rst ] "
   189              # 'packet-length 100',
   190              "packet-length =100 "
   191              # 'dscp 12',
   192              "dscp =12 "
   193              # 'fragment dont-fragment is-fragment+first-fragment',
   194              "fragment [ dont-fragment is-fragment+first-fragment ]"
   195          )
   196          # Note: Considers variants of SYN + ACK
   197          expected_list = (_exp_fmt % 'syn+ack', _exp_fmt % 'ack+syn')
   198          self.assertIn(nlri, expected_list)
   199  
   200      def test_02_ipv6_exabgp_adj_rib_in(self):
   201          rib = self.e1.get_adj_rib_in(self.g1, rf='ipv6-flowspec')
   202          self.assertEqual(1, len(rib))
   203          nlri = list(rib)[0]  # advertised from G1(GoBGP)
   204          expected = (
   205              # INPUTS:
   206              # 'destination 2001:1::/64 10',
   207              "destination-ipv6 2001:1::/64/10 "
   208              # 'source 2001:2::/64 15',
   209              "source-ipv6 2001:2::/64/15 "
   210              # 'label 12',
   211              "flow-label =12"
   212          )
   213          self.assertEqual(expected, nlri)
   214  
   215      def test_03_ipv4_yabgp_adj_rib_in(self):
   216          rib = self.y1.get_adj_rib_in(peer=self.g1, rf='flowspec')
   217          self.assertEqual(1, len(rib))
   218          nlri = list(rib)[0]  # advertised from G1(GoBGP)
   219          expected = (
   220              # INPUTS:
   221              # 'destination 11.1.0.0/24',
   222              '{"1": "11.1.0.0/24",'
   223              # 'source 11.2.0.0/24',
   224              ' "2": "11.2.0.0/24",'
   225              # "protocol '==tcp &=udp icmp >igmp >=egp <ipip <=rsvp !=gre'",
   226              ' "3": "=6&=17|=1|>2|>=8|<94|<=46|><47",'
   227              # "port '==80 &=90 8080 >9090 >=8180 <9190 <=8081 !=9091 &!443'",
   228              ' "4": "=80&=90|=8080|>9090|>=8180|<9190|<=8081|><9091&><443",'
   229              # 'destination-port 80',
   230              ' "5": "=80",'
   231              # 'source-port 8080',
   232              ' "6": "=8080",'
   233              # 'icmp-type 0',
   234              ' "7": "=0",'
   235              # 'icmp-code 2',
   236              ' "8": "=2",'
   237              # "tcp-flags '==S &=SA A !F !=U =!R'",
   238              ' "9": "=2&=18|16|>1|>=32|>=4",'
   239              # 'packet-length 100',
   240              ' "10": "=100",'
   241              # 'dscp 12',
   242              ' "11": "=12",'
   243              # 'fragment dont-fragment is-fragment+first-fragment',
   244              ' "12": "1|6"}'
   245          )
   246          self.assertEqual(expected, nlri)
   247  
   248      def test_04_ipv6_yabgp_adj_rib_in(self):
   249          # IPv6 FlowSpec: not supported with YABGP v0.4.0
   250          pass
   251  
   252      def test_05_ipv4_gobgp_global_rib(self):
   253          rib = self.g1.get_global_rib(rf='ipv4-flowspec')
   254          self.assertEqual(3, len(rib))
   255          output_nlri_list = [r['prefix'] for r in rib]
   256          nlri_g1 = (
   257              # INPUTS:
   258              # 'destination 11.1.0.0/24',
   259              "[destination: 11.1.0.0/24]"
   260              # 'source 11.2.0.0/24',
   261              "[source: 11.2.0.0/24]"
   262              # "protocol '==tcp &=udp icmp >igmp >=egp <ipip <=rsvp !=gre'",
   263              "[protocol: ==tcp&==udp ==icmp >igmp >=egp <ipip <=rsvp !=gre]"
   264              # "port '==80 &=90 8080 >9090 >=8180 <9190 <=8081 !=9091 &!443'",
   265              "[port: ==80&==90 ==8080 >9090 >=8180 <9190 <=8081 !=9091&!=443]"
   266              # 'destination-port 80',
   267              "[destination-port: ==80]"
   268              # 'source-port 8080',
   269              "[source-port: ==8080]"
   270              # 'icmp-type 0',
   271              "[icmp-type: ==0]"
   272              # 'icmp-code 2',
   273              "[icmp-code: ==2]"
   274              # "tcp-flags '==S &=SA A !F !=U =!R'",
   275              "[tcp-flags: =S&=SA A !F !=U !=R]"
   276              # 'packet-length 100',
   277              "[packet-length: ==100]"
   278              # 'dscp 12',
   279              "[dscp: ==12]"
   280              # 'fragment dont-fragment is-fragment+first-fragment',
   281              "[fragment: dont-fragment is-fragment+first-fragment]"
   282          )
   283          nlri_e1 = (
   284              # INPUTS:
   285              # 'destination 12.1.0.0/24',
   286              '[destination: 12.1.0.0/24]'
   287              # 'source 12.2.0.0/24',
   288              '[source: 12.2.0.0/24]'
   289              # 'protocol =tcp',
   290              '[protocol: ==tcp]'
   291              # 'port >=80',
   292              '[port: >=80]'
   293              # 'destination-port >5000',
   294              '[destination-port: >5000]'
   295              # 'source-port 8080',
   296              '[source-port: ==8080]'
   297              # 'icmp-type <1',
   298              '[icmp-type: <1]'
   299              # 'icmp-code <=2',
   300              '[icmp-code: <=2]'
   301              # "tcp-flags FIN",
   302              '[tcp-flags: F]'
   303              # 'packet-length >100&<200',
   304              '[packet-length: >100&<200]'
   305              # 'dscp 12',
   306              '[dscp: ==12]'
   307              # 'fragment dont-fragment',
   308              '[fragment: dont-fragment]'
   309          )
   310          nlri_y1 = (
   311              # INPUTS:
   312              # 'destination 13.1.0.0/24',
   313              "[destination: 13.1.0.0/24]"
   314              # 'source 13.2.0.0/24',
   315              "[source: 13.2.0.0/24]"
   316              # "protocol =6|=17",
   317              "[protocol: ==tcp ==udp]"
   318              # 'destination-port =80',
   319              "[destination-port: ==80]"
   320              # 'source-port <8080|>9090',
   321              "[source-port: <8080 >9090]"
   322              # 'icmp-type >=1',
   323              "[icmp-type: >=1]"
   324              # 'icmp-code <2',
   325              "[icmp-code: <2]"
   326              # 'packet-length <=100',
   327              "[packet-length: <=100]"
   328              # 'dscp =12',
   329              "[dscp: ==12]"
   330          )
   331          for nlri in [nlri_g1, nlri_e1, nlri_y1]:
   332              self.assertIn(nlri, output_nlri_list)
   333  
   334      def test_06_ipv6_gobgp_global_rib(self):
   335          rib = self.g1.get_global_rib(rf='ipv6-flowspec')
   336          import json
   337          self.assertEqual(2, len(rib), json.dumps(rib))
   338          output_nlri_list = [r['prefix'] for r in rib]
   339          nlri_g1 = (
   340              # INPUTS:
   341              # 'destination 2001:1::/64 10',
   342              "[destination: 2001:1::/64/10]"
   343              # 'source 2001:2::/64 15',
   344              "[source: 2001:2::/64/15]"
   345              # 'label 12',
   346              "[label: ==12]"
   347          )
   348          nlri_e1 = (
   349              # INPUTS:
   350              # 'destination 2002:1::/64/10',
   351              '[destination: 2002:1::/64/10]'
   352              # 'source 2002:2::/64/15',
   353              '[source: 2002:2::/64/15]'
   354              # 'next-header udp',
   355              '[protocol: ==udp]'
   356              # 'flow-label >100',
   357              '[label: >100]'
   358          )
   359          for nlri in [nlri_g1, nlri_e1]:
   360              self.assertIn(nlri, output_nlri_list)
   361  
   362      def test_07_ipv4_exabgp_delete_route(self):
   363          # Delete a route on E1(ExaBGP)
   364          self.e1.del_route(route='ipv4/all')
   365          time.sleep(1)
   366          # Test if the route is deleted or not
   367          rib = self.g1.get_adj_rib_in(peer=self.e1, rf='ipv4-flowspec')
   368          self.assertEqual(0, len(rib))
   369  
   370      def test_08_ipv6_exabgp_delete_route(self):
   371          # Delete a route on E1(ExaBGP)
   372          self.e1.del_route(route='ipv6/dst/src/protocol/label')
   373          time.sleep(1)
   374          # Test if the route is deleted or not
   375          rib = self.g1.get_adj_rib_in(peer=self.e1, rf='ipv6-flowspec')
   376          self.assertEqual(0, len(rib))
   377  
   378      def test_09_ipv4_yabgp_delete_route(self):
   379          # Delete a route on Y1(YABGP)
   380          self.y1.del_route(route='ipv4/all')
   381          time.sleep(1)
   382          # Test if the route is deleted or not
   383          rib = self.g1.get_adj_rib_in(peer=self.y1, rf='ipv4-flowspec')
   384          self.assertEqual(0, len(rib))
   385  
   386      def test_10_ipv6_yabgp_delete_route(self):
   387          # IPv6 FlowSpec: not supported with YABGP v0.4.0
   388          pass
   389  
   390      def test_11_ipv4_gobgp_delete_route(self):
   391          # Delete a route on G1(GoBGP)
   392          self.g1.del_route(route='ipv4/all')
   393          time.sleep(1)
   394          # Test if the route is deleted or not
   395          rib_e1 = self.e1.get_adj_rib_in(peer=self.g1, rf='ipv4-flowspec')
   396          self.assertEqual(0, len(rib_e1))
   397          rib_y1 = self.y1.get_adj_rib_in(peer=self.g1, rf='ipv4-flowspec')
   398          self.assertEqual(0, len(rib_y1))
   399  
   400      def test_12_ipv6_gobgp_delete_route(self):
   401          # Delete a route on G1(GoBGP)
   402          self.g1.del_route(route='ipv6/dst/src/label')
   403          time.sleep(1)
   404          # Test if the route is deleted or not
   405          rib_e1 = self.e1.get_adj_rib_in(peer=self.g1, rf='ipv6-flowspec')
   406          self.assertEqual(0, len(rib_e1))
   407          rib_y1 = self.y1.get_adj_rib_in(peer=self.g1, rf='ipv6-flowspec')
   408          self.assertEqual(0, len(rib_y1))
   409  
   410  
   411  if __name__ == '__main__':
   412      output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True)
   413      if int(output) is not 0:
   414          print "docker not found"
   415          sys.exit(1)
   416  
   417      nose.main(argv=sys.argv, addplugins=[OptionParser()],
   418                defaultTest=sys.argv[0])