backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / tests / unit / services / protocols / bgp / core_managers / test_table_manager.py
diff --git a/ryu/build/lib.linux-armv7l-2.7/ryu/tests/unit/services/protocols/bgp/core_managers/test_table_manager.py b/ryu/build/lib.linux-armv7l-2.7/ryu/tests/unit/services/protocols/bgp/core_managers/test_table_manager.py
new file mode 100644 (file)
index 0000000..c9c9f55
--- /dev/null
@@ -0,0 +1,937 @@
+# Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from collections import OrderedDict
+import unittest
+import logging
+try:
+    import mock  # Python 2
+except ImportError:
+    from unittest import mock  # Python 3
+
+from nose.tools import ok_, eq_, raises
+
+from ryu.lib.packet.bgp import BGPPathAttributeOrigin
+from ryu.lib.packet.bgp import BGPPathAttributeAsPath
+from ryu.lib.packet.bgp import BGP_ATTR_ORIGIN_IGP
+from ryu.lib.packet.bgp import BGP_ATTR_TYPE_ORIGIN
+from ryu.lib.packet.bgp import BGP_ATTR_TYPE_AS_PATH
+from ryu.lib.packet.bgp import BGP_ATTR_TYPE_EXTENDED_COMMUNITIES
+from ryu.lib.packet.bgp import IPAddrPrefix
+from ryu.lib.packet.bgp import IP6AddrPrefix
+from ryu.lib.packet.bgp import EvpnArbitraryEsi
+from ryu.lib.packet.bgp import EvpnLACPEsi
+from ryu.lib.packet.bgp import EvpnEthernetAutoDiscoveryNLRI
+from ryu.lib.packet.bgp import EvpnMacIPAdvertisementNLRI
+from ryu.lib.packet.bgp import EvpnInclusiveMulticastEthernetTagNLRI
+from ryu.lib.packet.bgp import FlowSpecIPv4NLRI
+from ryu.lib.packet.bgp import BGPPathAttributeExtendedCommunities
+from ryu.services.protocols.bgp.bgpspeaker import EVPN_MAX_ET
+from ryu.services.protocols.bgp.bgpspeaker import ESI_TYPE_LACP
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_IPV4
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_FAMILY_VPNV4
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_TA_SAMPLE
+from ryu.services.protocols.bgp.bgpspeaker import FLOWSPEC_TA_TERMINAL
+from ryu.services.protocols.bgp.core import BgpCoreError
+from ryu.services.protocols.bgp.core_managers import table_manager
+from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4
+from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV6
+from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_L2_EVPN
+from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4_FLOWSPEC
+from ryu.services.protocols.bgp.utils.bgp import create_v4flowspec_actions
+
+
+LOG = logging.getLogger(__name__)
+
+
+class Test_TableCoreManager(unittest.TestCase):
+    """
+    Test case for bgp.core_managers.table_manager.TableCoreManager
+    """
+
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.__init__',
+        mock.MagicMock(return_value=None))
+    def _test_update_vrf_table(self, prefix_inst, route_dist, prefix_str,
+                               next_hop, route_family, route_type,
+                               is_withdraw=False, **kwargs):
+        # Instantiate TableCoreManager
+        tbl_mng = table_manager.TableCoreManager(None, None)
+        vrf_table_mock = mock.MagicMock()
+        tbl_mng._tables = {(route_dist, route_family): vrf_table_mock}
+
+        # Test
+        tbl_mng.update_vrf_table(
+            route_dist=route_dist,
+            prefix=prefix_str,
+            next_hop=next_hop,
+            route_family=route_family,
+            route_type=route_type,
+            is_withdraw=is_withdraw,
+            **kwargs)
+
+        # Check
+        call_args_list = vrf_table_mock.insert_vrf_path.call_args_list
+        ok_(len(call_args_list) == 1)  # insert_vrf_path should be called once
+        args, kwargs = call_args_list[0]
+        ok_(len(args) == 0)  # no positional argument
+        eq_(str(prefix_inst), str(kwargs['nlri']))
+        eq_(is_withdraw, kwargs['is_withdraw'])
+        if is_withdraw:
+            eq_(None, kwargs['next_hop'])
+            eq_(False, kwargs['gen_lbl'])
+        else:
+            eq_(next_hop, kwargs['next_hop'])
+            eq_(True, kwargs['gen_lbl'])
+
+    def test_update_vrf_table_ipv4(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = '192.168.0.0'
+        ip_prefix_len = 24
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        prefix_inst = IPAddrPrefix(ip_prefix_len, ip_network)
+        next_hop = '10.0.0.1'
+        route_family = VRF_RF_IPV4
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    def test_update_vrf_table_ipv6(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = 'fe80::'
+        ip_prefix_len = 64
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        prefix_inst = IP6AddrPrefix(ip_prefix_len, ip_network)
+        next_hop = 'fe80::0011:aabb:ccdd:eeff'
+        route_family = VRF_RF_IPV6
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    def test_update_vrf_table_l2_evpn_with_esi_int(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        prefix_str = None  # should be ignored
+        kwargs = {
+            'ethernet_tag_id': 100,
+            'mac_addr': 'aa:bb:cc:dd:ee:ff',
+            'ip_addr': '192.168.0.1',
+            'mpls_labels': [],  # not be used
+        }
+        esi = EvpnArbitraryEsi(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        prefix_inst = EvpnMacIPAdvertisementNLRI(
+            route_dist=route_dist,
+            esi=esi,
+            **kwargs)
+        next_hop = '10.0.0.1'
+        route_family = VRF_RF_L2_EVPN
+        route_type = EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME
+        kwargs['esi'] = 0
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    def test_update_vrf_table_l2_evpn_with_esi_dict(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        prefix_str = None  # should be ignored
+        kwargs = {
+            'ethernet_tag_id': EVPN_MAX_ET,
+        }
+        esi = EvpnLACPEsi(mac_addr='aa:bb:cc:dd:ee:ff', port_key=100)
+        prefix_inst = EvpnEthernetAutoDiscoveryNLRI(
+            route_dist=route_dist,
+            esi=esi,
+            **kwargs)
+        next_hop = '0.0.0.0'
+        route_family = VRF_RF_L2_EVPN
+        route_type = EvpnEthernetAutoDiscoveryNLRI.ROUTE_TYPE_NAME
+        kwargs['esi'] = {
+            'type': ESI_TYPE_LACP,
+            'mac_addr': 'aa:bb:cc:dd:ee:ff',
+            'port_key': 100,
+        }
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    def test_update_vrf_table_l2_evpn_without_esi(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        prefix_str = None  # should be ignored
+        kwargs = {
+            'ethernet_tag_id': 100,
+            'ip_addr': '192.168.0.1',
+        }
+        prefix_inst = EvpnInclusiveMulticastEthernetTagNLRI(
+            route_dist=route_dist, **kwargs)
+        next_hop = '10.0.0.1'
+        route_family = VRF_RF_L2_EVPN
+        route_type = EvpnInclusiveMulticastEthernetTagNLRI.ROUTE_TYPE_NAME
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.__init__',
+        mock.MagicMock(return_value=None))
+    def test_update_vrf_table_l2_evpn_with_vni(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        prefix_str = None  # should be ignored
+        kwargs = {
+            'ethernet_tag_id': 100,
+            'mac_addr': 'aa:bb:cc:dd:ee:ff',
+            'ip_addr': '192.168.0.1',
+            'vni': 500,
+        }
+        esi = EvpnArbitraryEsi(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        prefix_inst = EvpnMacIPAdvertisementNLRI(
+            route_dist=route_dist,
+            esi=esi,
+            **kwargs)
+        next_hop = '10.0.0.1'
+        route_family = VRF_RF_L2_EVPN
+        route_type = EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME
+        tunnel_type = 'vxlan'
+        kwargs['esi'] = 0
+
+        # Instantiate TableCoreManager
+        tbl_mng = table_manager.TableCoreManager(None, None)
+        vrf_table_mock = mock.MagicMock()
+        tbl_mng._tables = {(route_dist, route_family): vrf_table_mock}
+
+        # Test
+        tbl_mng.update_vrf_table(
+            route_dist=route_dist,
+            prefix=prefix_str,
+            next_hop=next_hop,
+            route_family=route_family,
+            route_type=route_type,
+            tunnel_type=tunnel_type,
+            **kwargs)
+
+        # Check
+        call_args_list = vrf_table_mock.insert_vrf_path.call_args_list
+        ok_(len(call_args_list) == 1)  # insert_vrf_path should be called once
+        args, kwargs = call_args_list[0]
+        ok_(len(args) == 0)  # no positional argument
+        eq_(str(prefix_inst), str(kwargs['nlri']))
+        eq_(next_hop, kwargs['next_hop'])
+        eq_(False, kwargs['gen_lbl'])  # should not generate MPLS labels
+        eq_(tunnel_type, kwargs['tunnel_type'])
+
+    def test_update_vrf_table_ipv4_withdraw(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = '192.168.0.0'
+        ip_prefix_len = 24
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        prefix_inst = IPAddrPrefix(ip_prefix_len, ip_network)
+        next_hop = '10.0.0.1'
+        route_family = VRF_RF_IPV4
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    is_withdraw=True, **kwargs)
+
+    @raises(BgpCoreError)
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.__init__',
+        mock.MagicMock(return_value=None))
+    def test_update_vrf_table_no_vrf(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = '192.168.0.0'
+        ip_prefix_len = 24
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        next_hop = '10.0.0.1'
+        route_family = VRF_RF_IPV4
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        # Instantiate TableCoreManager
+        tbl_mng = table_manager.TableCoreManager(None, None)
+        tbl_mng._tables = {}  # no table
+
+        # Test
+        tbl_mng.update_vrf_table(
+            route_dist=route_dist,
+            prefix=prefix_str,
+            next_hop=next_hop,
+            route_family=route_family,
+            route_type=route_type,
+            **kwargs)
+
+    @raises(BgpCoreError)
+    def test_update_vrf_table_invalid_next_hop(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = '192.168.0.0'
+        ip_prefix_len = 24
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        prefix_inst = IPAddrPrefix(ip_prefix_len, ip_network)
+        next_hop = 'xxx.xxx.xxx.xxx'  # invalid
+        route_family = VRF_RF_IPV4
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    @raises(BgpCoreError)
+    def test_update_vrf_table_invalid_ipv4_prefix(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = 'xxx.xxx.xxx.xxx'  # invalid
+        ip_prefix_len = 24
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        prefix_inst = IPAddrPrefix(ip_prefix_len, ip_network)
+        next_hop = '10.0.0.1'
+        route_family = VRF_RF_IPV4
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    @raises(BgpCoreError)
+    def test_update_vrf_table_invalid_ipv6_prefix(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = 'xxxx::'  # invalid
+        ip_prefix_len = 64
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        prefix_inst = IP6AddrPrefix(ip_prefix_len, ip_network)
+        next_hop = 'fe80::0011:aabb:ccdd:eeff'
+        route_family = VRF_RF_IPV6
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    @raises(BgpCoreError)
+    def test_update_vrf_table_invalid_route_family(self):
+        # Prepare test data
+        route_dist = '65000:100'
+        ip_network = '192.168.0.0'
+        ip_prefix_len = 24
+        prefix_str = '%s/%d' % (ip_network, ip_prefix_len)
+        prefix_inst = IPAddrPrefix(ip_prefix_len, ip_network)
+        next_hop = '10.0.0.1'
+        route_family = 'foobar'  # invalid
+        route_type = None  # should be ignored
+        kwargs = {}  # should be ignored
+
+        self._test_update_vrf_table(prefix_inst, route_dist, prefix_str,
+                                    next_hop, route_family, route_type,
+                                    **kwargs)
+
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.__init__',
+        mock.MagicMock(return_value=None))
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.learn_path')
+    def _test_update_global_table(self, learn_path_mock, prefix, next_hop,
+                                  is_withdraw, expected_next_hop):
+        # Prepare test data
+        origin = BGPPathAttributeOrigin(BGP_ATTR_ORIGIN_IGP)
+        aspath = BGPPathAttributeAsPath([[]])
+        pathattrs = OrderedDict()
+        pathattrs[BGP_ATTR_TYPE_ORIGIN] = origin
+        pathattrs[BGP_ATTR_TYPE_AS_PATH] = aspath
+        pathattrs = str(pathattrs)
+
+        # Instantiate TableCoreManager
+        tbl_mng = table_manager.TableCoreManager(None, None)
+
+        # Test
+        tbl_mng.update_global_table(
+            prefix=prefix,
+            next_hop=next_hop,
+            is_withdraw=is_withdraw,
+        )
+
+        # Check
+        call_args_list = learn_path_mock.call_args_list
+        ok_(len(call_args_list) == 1)  # learn_path should be called once
+        args, kwargs = call_args_list[0]
+        ok_(len(kwargs) == 0)  # no keyword argument
+        output_path = args[0]
+        eq_(None, output_path.source)
+        eq_(prefix, output_path.nlri.prefix)
+        eq_(pathattrs, str(output_path.pathattr_map))
+        eq_(expected_next_hop, output_path.nexthop)
+        eq_(is_withdraw, output_path.is_withdraw)
+
+    def test_update_global_table_ipv4(self):
+        self._test_update_global_table(
+            prefix='192.168.0.0/24',
+            next_hop='10.0.0.1',
+            is_withdraw=False,
+            expected_next_hop='10.0.0.1',
+        )
+
+    def test_update_global_table_ipv4_withdraw(self):
+        self._test_update_global_table(
+            prefix='192.168.0.0/24',
+            next_hop='10.0.0.1',
+            is_withdraw=True,
+            expected_next_hop='10.0.0.1',
+        )
+
+    def test_update_global_table_ipv4_no_next_hop(self):
+        self._test_update_global_table(
+            prefix='192.168.0.0/24',
+            next_hop=None,
+            is_withdraw=True,
+            expected_next_hop='0.0.0.0',
+        )
+
+    def test_update_global_table_ipv6(self):
+        self._test_update_global_table(
+            prefix='fe80::/64',
+            next_hop='fe80::0011:aabb:ccdd:eeff',
+            is_withdraw=False,
+            expected_next_hop='fe80::0011:aabb:ccdd:eeff',
+        )
+
+    def test_update_global_table_ipv6_withdraw(self):
+        self._test_update_global_table(
+            prefix='fe80::/64',
+            next_hop='fe80::0011:aabb:ccdd:eeff',
+            is_withdraw=True,
+            expected_next_hop='fe80::0011:aabb:ccdd:eeff',
+        )
+
+    def test_update_global_table_ipv6_no_next_hop(self):
+        self._test_update_global_table(
+            prefix='fe80::/64',
+            next_hop=None,
+            is_withdraw=True,
+            expected_next_hop='::',
+        )
+
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.__init__',
+        mock.MagicMock(return_value=None))
+    def _test_update_flowspec_vrf_table(self, flowspec_family, route_family,
+                                        route_dist, rules, prefix,
+                                        is_withdraw, actions=None):
+        # Instantiate TableCoreManager
+        tbl_mng = table_manager.TableCoreManager(None, None)
+        vrf_table_mock = mock.MagicMock()
+        tbl_mng._tables = {(route_dist, route_family): vrf_table_mock}
+
+        # Test
+        tbl_mng.update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_dist=route_dist,
+            rules=rules,
+            actions=actions,
+            is_withdraw=is_withdraw,
+        )
+
+        # Check
+        call_args_list = vrf_table_mock.insert_vrffs_path.call_args_list
+        ok_(len(
+            call_args_list) == 1)  # insert_vrffs_path should be called once
+        args, kwargs = call_args_list[0]
+        ok_(len(args) == 0)  # no positional argument
+        eq_(prefix, kwargs['nlri'].prefix)
+        eq_(is_withdraw, kwargs['is_withdraw'])
+
+    def test_update_flowspec_vrf_table_vpnv4(self):
+        flowspec_family = 'vpnv4fs'
+        route_family = 'ipv4fs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '10.70.1.0/24',
+        }
+        actions = {
+            'traffic_rate': {
+                'as_number': 0,
+                'rate_info': 100.0,
+            },
+        }
+        prefix = 'ipv4fs(dst_prefix:10.70.1.0/24)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    def test_update_flowspec_vrf_table_vpnv4_without_actions(self):
+        flowspec_family = 'vpnv4fs'
+        route_family = 'ipv4fs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '10.70.1.0/24',
+        }
+        prefix = 'ipv4fs(dst_prefix:10.70.1.0/24)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_vrf_table_vpnv4_invalid_actions(self):
+        flowspec_family = 'vpnv4fs'
+        route_family = 'ipv4fs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '10.70.1.0/24',
+        }
+        actions = {
+            'invalid_actions': {
+                'invalid_param': 10,
+            },
+        }
+        prefix = 'ipv4fs(dst_prefix:10.70.1.0/24)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_vrf_table_vpnv4_invalid_flowspec_family(self):
+        flowspec_family = 'invalid'
+        route_family = 'ipv4fs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '10.70.1.0/24',
+        }
+        prefix = 'ipv4fs(dst_prefix:10.70.1.0/24)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_vrf_table_vpnv4_invalid_route_family(self):
+        flowspec_family = 'vpnv4fs'
+        route_family = 'invalid'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '10.70.1.0/24',
+        }
+        prefix = 'ipv4fs(dst_prefix:10.70.1.0/24)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.__init__',
+        mock.MagicMock(return_value=None))
+    @mock.patch(
+        'ryu.services.protocols.bgp.core_managers.TableCoreManager.learn_path')
+    def _test_update_flowspec_global_table(self, learn_path_mock,
+                                           flowspec_family, rules, prefix,
+                                           is_withdraw, actions=None):
+        # Instantiate TableCoreManager
+        tbl_mng = table_manager.TableCoreManager(None, None)
+
+        # Test
+        tbl_mng.update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            actions=actions,
+            is_withdraw=is_withdraw,
+        )
+
+        # Check
+        call_args_list = learn_path_mock.call_args_list
+        ok_(len(call_args_list) == 1)  # learn_path should be called once
+        args, kwargs = call_args_list[0]
+        ok_(len(kwargs) == 0)  # no keyword argument
+        output_path = args[0]
+        eq_(None, output_path.source)
+        eq_(prefix, output_path.nlri.prefix)
+        eq_(None, output_path.nexthop)
+        eq_(is_withdraw, output_path.is_withdraw)
+
+    def test_update_flowspec_global_table_ipv4(self):
+        flowspec_family = 'ipv4fs'
+        rules = {
+            'dst_prefix': '10.60.1.0/24',
+        }
+        actions = {
+            'traffic_rate': {
+                'as_number': 0,
+                'rate_info': 100.0,
+            },
+        }
+        prefix = 'ipv4fs(dst_prefix:10.60.1.0/24)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    def test_update_flowspec_global_table_ipv4_without_actions(self):
+        flowspec_family = 'ipv4fs'
+        rules = {
+            'dst_prefix': '10.60.1.0/24',
+        }
+        prefix = 'ipv4fs(dst_prefix:10.60.1.0/24)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_global_table_ipv4_invalid_actions(self):
+        flowspec_family = 'ipv4fs'
+        rules = {
+            'dst_prefix': '10.60.1.0/24',
+        }
+        actions = {
+            'invalid_actions': {
+                'invalid_param': 10,
+            },
+        }
+        prefix = 'ipv4fs(dst_prefix:10.60.1.0/24)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_global_table_ipv4_invalid_flowspec_family(self):
+        flowspec_family = 'invalid'
+        rules = {
+            'dst_prefix': '10.60.1.0/24',
+        }
+        actions = {
+            'traffic_rate': {
+                'as_number': 0,
+                'rate_info': 100.0,
+            },
+        }
+        prefix = 'ipv4fs(dst_prefix:10.60.1.0/24)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    def test_update_flowspec_global_table_ipv6(self):
+        flowspec_family = 'ipv6fs'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        actions = {
+            'traffic_rate': {
+                'as_number': 0,
+                'rate_info': 100.0,
+            },
+        }
+        prefix = 'ipv6fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    def test_update_flowspec_global_table_ipv6_without_actions(self):
+        flowspec_family = 'ipv6fs'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        prefix = 'ipv6fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_global_table_ipv6_invalid_actions(self):
+        flowspec_family = 'ipv6fs'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        actions = {
+            'invalid_actions': {
+                'invalid_param': 10,
+            },
+        }
+        prefix = 'ipv4fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_global_table_ipv6_invalid_flowspec_family(self):
+        flowspec_family = 'invalid'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        actions = {
+            'traffic_rate': {
+                'as_number': 0,
+                'rate_info': 100.0,
+            },
+        }
+        prefix = 'ipv4fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_global_table(
+            flowspec_family=flowspec_family,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    def test_update_flowspec_vrf_table_vpnv6(self):
+        flowspec_family = 'vpnv6fs'
+        route_family = 'ipv6fs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        actions = {
+            'traffic_rate': {
+                'as_number': 0,
+                'rate_info': 100.0,
+            },
+        }
+        prefix = 'ipv6fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    def test_update_flowspec_vrf_table_vpnv6_without_actions(self):
+        flowspec_family = 'vpnv6fs'
+        route_family = 'ipv6fs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        prefix = 'ipv6fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_vrf_table_vpnv6_invalid_actions(self):
+        flowspec_family = 'vpnv6fs'
+        route_family = 'ipv6fs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        actions = {
+            'invalid_actions': {
+                'invalid_param': 10,
+            },
+        }
+        prefix = 'ipv6fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_vrf_table_vpnv6_invalid_route_family(self):
+        flowspec_family = 'vpnv6fs'
+        route_family = 'invalid'
+        route_dist = '65001:100'
+        rules = {
+            'dst_prefix': '2001::3/128/32',
+        }
+        prefix = 'ipv4fs(dst_prefix:2001::3/128/32)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    def test_update_flowspec_vrf_table_l2vpn(self):
+        flowspec_family = 'l2vpnfs'
+        route_family = 'l2vpnfs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_mac': '12:34:56:78:9a:bc',
+        }
+        actions = {
+            'traffic_rate': {
+                'as_number': 0,
+                'rate_info': 100.0,
+            },
+        }
+        prefix = 'l2vpnfs(dst_mac:12:34:56:78:9a:bc)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    def test_update_flowspec_vrf_table_l2vpn_without_actions(self):
+        flowspec_family = 'l2vpnfs'
+        route_family = 'l2vpnfs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_mac': '12:34:56:78:9a:bc',
+        }
+        prefix = 'l2vpnfs(dst_mac:12:34:56:78:9a:bc)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_vrf_table_l2vpn_invalid_actions(self):
+        flowspec_family = 'l2vpnfs'
+        route_family = 'l2vpnfs'
+        route_dist = '65001:100'
+        rules = {
+            'dst_mac': '12:34:56:78:9a:bc',
+        }
+        actions = {
+            'invalid_actions': {
+                'invalid_param': 10,
+            },
+        }
+        prefix = 'l2vpnfs(dst_mac:12:34:56:78:9a:bc)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+            actions=actions,
+        )
+
+    @raises(BgpCoreError)
+    def test_update_flowspec_vrf_table_l2vpn_invalid_route_family(self):
+        flowspec_family = 'l2vpnfs'
+        route_family = 'invalid'
+        route_dist = '65001:100'
+        rules = {
+            'dst_mac': '12:34:56:78:9a:bc',
+        }
+        prefix = 'l2vpnfs(dst_mac:12:34:56:78:9a:bc)'
+
+        self._test_update_flowspec_vrf_table(
+            flowspec_family=flowspec_family,
+            route_family=route_family,
+            route_dist=route_dist,
+            rules=rules,
+            prefix=prefix,
+            is_withdraw=False,
+        )