summaryrefslogtreecommitdiffhomepage
path: root/test/scenario_test/flow_spec_test.py
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-12-22 21:31:24 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2018-01-19 13:25:19 +0900
commit4c51cdedf75158e01e6ea4c621abb42f0d896235 (patch)
tree5fb8a5bdb6de86d16bed037f63783bd4f4c25d97 /test/scenario_test/flow_spec_test.py
parentf3a6c3519a43919391d1aebd420f555cb2c6a93f (diff)
flow_spec_test: Enhance test cases with YABGP
This patch extends test cases using YABGP; - Test "gobgp" command outputs representations with IPv4/IPv6 - IPv4 FlowSpec rules advertisements and withdraws TODO: Supports test cases for the IPv6 FlowSpec rules withdraws when YABGP supports the IPv6 FlowSpec or when ExaBGP fixes issues(*) of logging the received FlowSpec rules. (*): ExaBGP (v4.0.2 or v3.4.21) will failed to log the received FlowSpec rules which contains some specific operators/operands (e.g., "!=" or empty operator). Then, we need to wait for the next release to implement more test cases. Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Diffstat (limited to 'test/scenario_test/flow_spec_test.py')
-rw-r--r--test/scenario_test/flow_spec_test.py279
1 files changed, 243 insertions, 36 deletions
diff --git a/test/scenario_test/flow_spec_test.py b/test/scenario_test/flow_spec_test.py
index 2671bf5e..d4b401a7 100644
--- a/test/scenario_test/flow_spec_test.py
+++ b/test/scenario_test/flow_spec_test.py
@@ -15,7 +15,6 @@
from __future__ import absolute_import
-from itertools import combinations
import sys
import time
import unittest
@@ -29,57 +28,265 @@ from lib import base
from lib.base import BGP_FSM_ESTABLISHED
from lib.gobgp import GoBGPContainer
from lib.exabgp import ExaBGPContainer
+from lib.yabgp import YABGPContainer
-class GoBGPTestBase(unittest.TestCase):
+class FlowSpecTest(unittest.TestCase):
+
+ """
+ Test case for Flow Specification.
+ """
+ # +------------+ +------------+
+ # | G1(GoBGP) |---(iBGP)---| E1(ExaBGP) |
+ # | 172.17.0.2 | | 172.17.0.3 |
+ # +------------+ +------------+
+ # |
+ # (iBGP)
+ # |
+ # +------------+
+ # | Y1(YABGP) |
+ # | 172.17.0.4 |
+ # +------------+
@classmethod
def setUpClass(cls):
gobgp_ctn_image_name = parser_option.gobgp_image
base.TEST_PREFIX = parser_option.test_prefix
- g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
- ctn_image_name=gobgp_ctn_image_name,
- log_level=parser_option.gobgp_log_level)
- e1 = ExaBGPContainer(name='e1', asn=65000, router_id='192.168.0.2')
-
- ctns = [g1, e1]
-
- # advertise a route from q1, q2
- matchs = ['destination 10.0.0.0/24', 'source 20.0.0.0/24']
- thens = ['discard']
- e1.add_route(route='flow1', rf='ipv4-flowspec', matchs=matchs, thens=thens)
- matchs2 = ['tcp-flags S', 'protocol ==tcp ==udp', "packet-length '>1000&<2000'", "source-port '!=2&!=22&!=222'"]
- thens2 = ['rate-limit 9600', 'redirect 0.10:100', 'mark 20', 'action sample']
- g1.add_route(route='flow1', rf='ipv4-flowspec', matchs=matchs2, thens=thens2)
- matchs3 = ['destination 2001::/24/10', 'source 2002::/24/15']
- thens3 = ['discard']
- e1.add_route(route='flow2', rf='ipv6-flowspec', matchs=matchs3, thens=thens3)
- matchs4 = ['destination 2001::/24 10', "label '==100'"]
- thens4 = ['discard']
- g1.add_route(route='flow2', rf='ipv6-flowspec', matchs=matchs4, thens=thens4)
+ cls.g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1',
+ ctn_image_name=gobgp_ctn_image_name,
+ log_level=parser_option.gobgp_log_level)
- initial_wait_time = max(ctn.run() for ctn in ctns)
+ cls.e1 = ExaBGPContainer(name='e1', asn=65000, router_id='192.168.0.2')
+
+ cls.y1 = YABGPContainer(name='y1', asn=65000, router_id='192.168.0.3')
+ ctns = [cls.g1, cls.e1, cls.y1]
+ initial_wait_time = max(ctn.run() for ctn in ctns)
time.sleep(initial_wait_time)
- # ibgp peer. loop topology
- for a, b in combinations(ctns, 2):
- a.add_peer(b, flowspec=True)
- b.add_peer(a, flowspec=True)
+ # Add FlowSpec routes into ExaBGP.
+ # Note: Currently, ExaBGPContainer only supports to add routes by
+ # reloading configuration, so we add routes here.
+ cls.e1.add_route(
+ route='ipv4/dst/src',
+ rf='ipv4-flowspec',
+ matchs=[
+ 'destination 12.1.0.0/24',
+ 'source 12.2.0.0/24',
+ ],
+ thens=['discard'])
+ cls.e1.add_route(
+ route='ipv6/dst/src',
+ rf='ipv6-flowspec',
+ matchs=[
+ 'destination 2002:1::/64/10',
+ 'source 2002:2::/64/15',
+ ],
+ thens=['discard'])
+
+ # Add FlowSpec routes into GoBGP.
+ cls.g1.add_route(
+ route='ipv4/all',
+ rf='ipv4-flowspec',
+ matchs=[
+ 'destination 11.1.0.0/24',
+ 'source 11.2.0.0/24',
+ "protocol '==tcp &=udp icmp >igmp >=egp <igp <=rsvp !=gre'",
+ "port '==80 &=90 8080 >9090 >=8180 <9190 <=8081 !=9091 &!443'",
+ 'destination-port 80',
+ 'source-port 8080',
+ 'icmp-type 1',
+ 'icmp-code 2',
+ "tcp-flags '==S &=SA A !F !=U =!C'",
+ 'packet-length 100',
+ 'dscp 12',
+ 'fragment dont-fragment is-fragment+first-fragment',
+ ],
+ thens=['discard'])
+ cls.g1.add_route(
+ route='ipv6/dst/src/label', # others are tested on IPv4
+ rf='ipv6-flowspec',
+ matchs=[
+ 'destination 2001:1::/64 10',
+ 'source 2001:2::/64 15',
+ 'label 12',
+ ],
+ thens=['discard'])
+
+ cls.g1.add_peer(cls.e1, flowspec=True)
+ cls.e1.add_peer(cls.g1, flowspec=True)
+ cls.g1.add_peer(cls.y1, flowspec=True)
+ cls.y1.add_peer(cls.g1, flowspec=True)
+
+ cls.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=cls.e1)
+ cls.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=cls.y1)
+
+ # Add FlowSpec routes into YABGP.
+ # Note: Currently, YABGPContainer only supports to add routes via
+ # REST API after connection established, so we add routes here.
+ cls.y1.add_route(
+ route='ipv4/all',
+ rf='ipv4-flowspec',
+ matchs=[
+ 'destination 13.1.0.0/24',
+ 'source 13.2.0.0/24',
+ "protocol =6|=17",
+ # "port", # not seem to be supported
+ 'destination-port =80',
+ 'source-port <8080|>9090',
+ 'icmp-type >=1',
+ 'icmp-code <2',
+ # "tcp-flags", # not seem to be supported via REST API
+ 'packet-length <=100',
+ 'dscp =12',
+ # "fragment", # not seem to be supported via REST API
+ ],
+ thens=['traffic-rate:0:0']) # 'discard'
+ # IPv6 FlowSpec: not supported with YABGP v0.4.0
+ # cls.y1.add_route(
+ # route='ipv6/dst/src/label', # others are tested on IPv4
+ # rf='ipv6-flowspec',
+ # matchs=[
+ # 'destination 2003:1::/64/10',
+ # 'source 2003:2::/64/15',
+ # 'label 12',
+ # ],
+ # thens=['traffic-rate:0:0']) # 'discard'
+
+ def test_01_ipv4_yabgp_adj_rib_in(self):
+ rib = self.y1.get_adj_rib_in(peer=self.g1, rf='flowspec')
+ self.assertEqual(1, len(rib))
+ nlri = list(rib)[0] # advertised from G1(GoBGP)
+ expected = (
+ # INPUTS:
+ # 'destination 11.1.0.0/24',
+ '{"1": "11.1.0.0/24",'
+ # 'source 11.2.0.0/24',
+ ' "2": "11.2.0.0/24",'
+ # "protocol '==tcp &=udp icmp >igmp >=egp <igp <=rsvp !=gre'",
+ ' "3": "=6&=17|=1|>2|>=8|<9|<=46|><47",'
+ # "port '==80 &=90 8080 >9090 >=8180 <9190 <=8081 !=9091 &!443'",
+ ' "4": "=80&=90|=8080|>9090|>=8180|<9190|<=8081|><9091&><443",'
+ # 'destination-port 80',
+ ' "5": "=80",'
+ # 'source-port 8080',
+ ' "6": "=8080",'
+ # 'icmp-type 1',
+ ' "7": "=1",'
+ # 'icmp-code 2',
+ ' "8": "=2",'
+ # "tcp-flags '==S &=SA A !F !=U =!C'",
+ ' "9": "=2&=18|16|>1|>=32|>=128",'
+ # 'packet-length 100',
+ ' "10": "=100",'
+ # 'dscp 12',
+ ' "11": "=12",'
+ # 'fragment dont-fragment is-fragment+first-fragment',
+ ' "12": "1|6"}'
+ )
+ self.assertEqual(expected, nlri)
- cls.gobgp = g1
- cls.exabgp = e1
+ def test_02_ipv4_gobgp_global_rib(self):
+ rib = self.g1.get_global_rib(rf='ipv4-flowspec')
+ self.assertEqual(3, len(rib))
+ output_nlri_list = [r['prefix'] for r in rib]
+ nlri_e1 = (
+ # INPUTS:
+ # 'destination 12.1.0.0/24',
+ "[destination: 12.1.0.0/24]"
+ # 'source 12.2.0.0/24',
+ "[source: 12.2.0.0/24]"
+ )
+ nlri_g1 = (
+ # INPUTS:
+ # 'destination 11.1.0.0/24',
+ "[destination: 11.1.0.0/24]"
+ # 'source 11.2.0.0/24',
+ "[source: 11.2.0.0/24]"
+ # "protocol '==tcp &=udp icmp >igmp >=egp <igp <=rsvp !=gre'",
+ "[protocol: ==tcp&==udp ==icmp >igmp >=egp <igp <=rsvp !=gre]"
+ # "port '==80 &=90 8080 >9090 >=8180 <9190 <=8081 !=9091 &!443'",
+ "[port: ==80&==90 ==8080 >9090 >=8180 <9190 <=8081 !=9091&!=443]"
+ # 'destination-port 80',
+ "[destination-port: ==80]"
+ # 'source-port 8080',
+ "[source-port: ==8080]"
+ # 'icmp-type 1',
+ "[icmp-type: ==1]"
+ # 'icmp-code 2',
+ "[icmp-code: ==2]"
+ # "tcp-flags '==S &=SA A !F !=U =!C'",
+ "[tcp-flags: =S&=SA A !F !=U !=C]"
+ # 'packet-length 100',
+ "[packet-length: ==100]"
+ # 'dscp 12',
+ "[dscp: ==12]"
+ # 'fragment dont-fragment is-fragment+first-fragment',
+ "[fragment: dont-fragment is-fragment+first-fragment]"
+ )
+ nlri_y1 = (
+ # INPUTS:
+ # 'destination 13.1.0.0/24',
+ "[destination: 13.1.0.0/24]"
+ # 'source 13.2.0.0/24',
+ "[source: 13.2.0.0/24]"
+ # "protocol =6|=17",
+ "[protocol: ==tcp ==udp]"
+ # 'destination-port =80',
+ "[destination-port: ==80]"
+ # 'source-port <8080|>9090',
+ "[source-port: <8080 >9090]"
+ # 'icmp-type >=1',
+ "[icmp-type: >=1]"
+ # 'icmp-code <2',
+ "[icmp-code: <2]"
+ # 'packet-length <=100',
+ "[packet-length: <=100]"
+ # 'dscp =12',
+ "[dscp: ==12]"
+ )
+ for nlri in [nlri_e1, nlri_g1, nlri_y1]:
+ self.assertIn(nlri, output_nlri_list)
- # test each neighbor state is turned establish
- def test_01_neighbor_established(self):
- self.gobgp.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.exabgp)
+ def test_03_ipv6_gobgp_global_rib(self):
+ rib = self.g1.get_global_rib(rf='ipv6-flowspec')
+ self.assertEqual(2, len(rib))
+ output_nlri_list = [r['prefix'] for r in rib]
+ nlri_e1 = (
+ # INPUTS:
+ # 'destination 2002:1::/64/10',
+ "[destination: 2002:1::/64/10]"
+ # 'source 2002:2::/64/15',
+ "[source: 2002:2::/64/15]"
+ )
+ nlri_g1 = (
+ # INPUTS:
+ # 'destination 2001:1::/64 10',
+ "[destination: 2001:1::/64/10]"
+ # 'source 2001:2::/64 15',
+ "[source: 2001:2::/64/15]"
+ # 'label 12',
+ "[label: ==12]"
+ )
+ for nlri in [nlri_e1, nlri_g1]:
+ self.assertIn(nlri, output_nlri_list)
- def test_02_check_gobgp_global_rib(self):
- self.assertTrue(len(self.gobgp.get_global_rib(rf='ipv4-flowspec')) == 2)
+ def test_04_ipv4_yabgp_delete_route(self):
+ # Delete a route on Y1(YABGP)
+ self.y1.del_route(route='ipv4/all')
+ time.sleep(1)
+ # Test if the route is deleted or not
+ rib = self.g1.get_adj_rib_in(peer=self.y1, rf='ipv4-flowspec')
+ self.assertEqual(0, len(rib))
- def test_03_check_gobgp_global_rib(self):
- self.assertTrue(len(self.gobgp.get_global_rib(rf='ipv6-flowspec')) == 2)
+ def test_05_ipv4_gobgp_delete_route(self):
+ # Delete a route on G1(GoBGP)
+ self.g1.del_route(route='ipv4/all')
+ time.sleep(1)
+ # Test if the route is deleted or not
+ rib = self.y1.get_adj_rib_in(peer=self.g1, rf='ipv4-flowspec')
+ self.assertEqual(0, len(rib))
if __name__ == '__main__':