aboutsummaryrefslogtreecommitdiffstats
path: root/networking_sfc/tests/unit/services/sfc
diff options
context:
space:
mode:
Diffstat (limited to 'networking_sfc/tests/unit/services/sfc')
-rw-r--r--networking_sfc/tests/unit/services/sfc/__init__.py0
-rw-r--r--networking_sfc/tests/unit/services/sfc/agent/__init__.py0
-rw-r--r--networking_sfc/tests/unit/services/sfc/agent/test-agent.py4012
-rw-r--r--networking_sfc/tests/unit/services/sfc/common/__init__.py0
-rw-r--r--networking_sfc/tests/unit/services/sfc/common/test_ovs_ext_lib.py93
-rw-r--r--networking_sfc/tests/unit/services/sfc/drivers/__init__.py0
-rw-r--r--networking_sfc/tests/unit/services/sfc/drivers/ovs/__init__.py0
-rw-r--r--networking_sfc/tests/unit/services/sfc/test_driver_manager.py325
-rw-r--r--networking_sfc/tests/unit/services/sfc/test_plugin.py468
9 files changed, 4898 insertions, 0 deletions
diff --git a/networking_sfc/tests/unit/services/sfc/__init__.py b/networking_sfc/tests/unit/services/sfc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/__init__.py
diff --git a/networking_sfc/tests/unit/services/sfc/agent/__init__.py b/networking_sfc/tests/unit/services/sfc/agent/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/agent/__init__.py
diff --git a/networking_sfc/tests/unit/services/sfc/agent/test-agent.py b/networking_sfc/tests/unit/services/sfc/agent/test-agent.py
new file mode 100644
index 0000000..113c343
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/agent/test-agent.py
@@ -0,0 +1,4012 @@
+# Copyright 2015 Huawei. All rights reserved.
+#
+# 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.
+
+import mock
+import six
+
+from neutron.agent.common import ovs_lib
+from neutron.agent.common import utils
+from neutron.agent import rpc as agent_rpc
+from neutron import context
+from neutron.tests import base
+
+from networking_sfc.services.sfc.agent import (
+ ovs_sfc_agent as agent)
+from networking_sfc.services.sfc.agent import br_int
+from networking_sfc.services.sfc.agent import br_phys
+from networking_sfc.services.sfc.agent import br_tun
+from networking_sfc.services.sfc.common import ovs_ext_lib
+
+
+class OVSSfcAgentTestCase(base.BaseTestCase):
+ def setUp(self):
+ super(OVSSfcAgentTestCase, self).setUp()
+ mock.patch(
+ 'neutron.agent.common.ovs_lib.OVSBridge.get_ports_attributes',
+ return_value=[]
+ ).start()
+ mock.patch(
+ 'neutron.agent.common.ovs_lib.BaseOVS.config',
+ new_callable=mock.PropertyMock,
+ return_value={}
+ ).start()
+ self.executed_cmds = []
+ self.node_flowrules = []
+ self.backup_plugin_rpc = agent.SfcPluginApi
+ self.plugin_rpc = mock.Mock()
+ self.plugin_rpc.get_flowrules_by_host_portid = mock.Mock(
+ side_effect=self.mock_get_flowrules_by_host_portid
+ )
+ self.plugin_rpc.get_all_src_node_flowrules = mock.Mock(
+ side_effect=self.mock_get_all_src_node_flowrules
+ )
+ agent.SfcPluginApi = mock.Mock(
+ return_value=self.plugin_rpc
+ )
+ self.create_consumers = mock.patch.object(
+ agent_rpc, "create_consumers",
+ self.mock_create_consumers
+ )
+ self.create_consumers.start()
+ self.execute = mock.patch.object(
+ utils, "execute", self.mock_execute,
+ spec=utils.execute)
+ self.execute.start()
+ self.added_flows = []
+ self.add_flow = mock.patch.object(
+ ovs_lib.OVSBridge, "add_flow", self.mock_add_flow
+ )
+ self.add_flow.start()
+ self.deleted_flows = []
+ self.delete_flows = mock.patch.object(
+ ovs_lib.OVSBridge, "delete_flows", self.mock_delete_flows
+ )
+ self.delete_flows.start()
+ self.int_patch = 1
+ self.tun_patch = 2
+ self.default_port_mapping = {
+ 'patch-int': {
+ 'ofport': self.int_patch
+ },
+ 'patch-tun': {
+ 'ofport': self.tun_patch
+ }
+ }
+ self.port_mapping = {}
+ self.get_vif_port_by_id = mock.patch.object(
+ ovs_lib.OVSBridge, "get_vif_port_by_id",
+ self.mock_get_vif_port_by_id
+ )
+ self.get_vif_port_by_id.start()
+ self.get_port_ofport = mock.patch.object(
+ ovs_lib.OVSBridge, "get_port_ofport",
+ self.mock_get_port_ofport
+ )
+ self.get_port_ofport.start()
+ self.set_secure_mode = mock.patch.object(
+ ovs_lib.OVSBridge, "set_secure_mode",
+ self.mock_set_secure_mode
+ )
+ self.set_secure_mode.start()
+ self.protocols = []
+ self.set_protocols = mock.patch.object(
+ ovs_lib.OVSBridge, "set_protocols",
+ self.mock_set_protocols
+ )
+ self.set_protocols.start()
+ self.del_controller = mock.patch.object(
+ ovs_lib.OVSBridge, "del_controller",
+ self.mock_del_controller
+ )
+ self.del_controller.start()
+ self.get_bridges = mock.patch.object(
+ ovs_lib.BaseOVS, "get_bridges",
+ self.mock_get_bridges
+ )
+ self.get_bridges.start()
+ self.get_vif_ports = mock.patch.object(
+ ovs_lib.OVSBridge, "get_vif_ports",
+ self.mock_get_vif_ports
+ )
+ self.get_vif_ports.start()
+ self.get_ports_attributes = mock.patch.object(
+ ovs_lib.OVSBridge, "get_ports_attributes",
+ self.mock_get_ports_attributes
+ )
+ self.get_ports_attributes.start()
+ self.delete_port = mock.patch.object(
+ ovs_lib.OVSBridge, "delete_port",
+ self.mock_delete_port
+ )
+ self.delete_port.start()
+ self.create = mock.patch.object(
+ ovs_lib.OVSBridge, "create",
+ self.mock_create
+ )
+ self.create.start()
+ self.add_port = mock.patch.object(
+ ovs_lib.OVSBridge, "add_port",
+ self.mock_add_port
+ )
+ self.add_port.start()
+ self.bridge_exists = mock.patch.object(
+ ovs_lib.BaseOVS, "bridge_exists",
+ self.mock_bridge_exists
+ )
+ self.bridge_exists.start()
+ self.port_exists = mock.patch.object(
+ ovs_lib.BaseOVS, "port_exists",
+ self.mock_port_exists
+ )
+ self.port_exists.start()
+ self.apply_flows = mock.patch.object(
+ ovs_lib.DeferredOVSBridge, "apply_flows",
+ self.mock_apply_flows
+ )
+ self.apply_flows.start()
+ self.group_mapping = {}
+ self.deleted_groups = []
+ self.dump_group_for_id = mock.patch.object(
+ ovs_ext_lib.OVSBridgeExt, "dump_group_for_id",
+ self.mock_dump_group_for_id
+ )
+ self.dump_group_for_id.start()
+ self.add_group = mock.patch.object(
+ ovs_ext_lib.OVSBridgeExt, "add_group",
+ self.mock_add_group
+ )
+ self.add_group.start()
+ self.mod_group = mock.patch.object(
+ ovs_ext_lib.OVSBridgeExt, "mod_group",
+ self.mock_mod_group
+ )
+ self.mod_group.start()
+ self.delete_group = mock.patch.object(
+ ovs_ext_lib.OVSBridgeExt, "delete_group",
+ self.mock_delete_group
+ )
+ self.delete_group.start()
+ self.local_ip = '10.0.0.1'
+ self.bridge_classes = {
+ 'br_int': br_int.OVSIntegrationBridge,
+ 'br_phys': br_phys.OVSPhysicalBridge,
+ 'br_tun': br_tun.OVSTunnelBridge,
+ }
+ self.context = context.get_admin_context_without_session()
+ self.init_agent()
+
+ def init_agent(self):
+ self.added_flows = []
+ self.deleted_flows = []
+ self.group_mapping = {}
+ self.deleted_groups = []
+ self.agent = agent.OVSSfcAgent(
+ self.bridge_classes,
+ 'br-int',
+ 'br-tun',
+ self.local_ip,
+ {},
+ 2,
+ tunnel_types=['gre', 'vxlan']
+ )
+
+ def mock_create_consumers(
+ self, endpoints, prefix, topic_details, start_listening=True
+ ):
+ self.added_flows = []
+ self.deleted_flows = []
+ return mock.Mock()
+
+ def mock_delete_group(self, group_id):
+ if group_id == 'all':
+ self.group_mapping = {}
+ else:
+ if group_id in self.group_mapping:
+ del self.group_mapping[group_id]
+ else:
+ self.deleted_groups.append(group_id)
+
+ def mock_mod_group(self, group_id, **kwargs):
+ kwargs['group_id'] = group_id
+ self.group_mapping[group_id] = kwargs
+
+ def mock_add_group(self, group_id, **kwargs):
+ kwargs['group_id'] = group_id
+ self.group_mapping[group_id] = kwargs
+
+ def mock_dump_group_for_id(self, group_id):
+ if group_id in self.group_mapping:
+ group_list = []
+ group = self.group_mapping[group_id]
+ for group_key, group_value in six.iteritems(group):
+ group_list.append('%s=%s' % (group_key, group_value))
+ return ' '.join(group_list)
+ else:
+ return ''
+
+ def mock_set_secure_mode(self):
+ pass
+
+ def mock_set_protocols(self, protocols):
+ self.protocols = protocols
+
+ def mock_del_controller(self):
+ pass
+
+ def mock_get_bridges(self):
+ return ['br-int', 'br-tun']
+
+ def mock_get_port_ofport(self, port_name):
+ for port_id, port_values in six.iteritems(self.port_mapping):
+ if port_values['port_name'] == port_name:
+ return port_values['ofport']
+ if port_name in self.default_port_mapping:
+ return self.default_port_mapping[port_name]['ofport']
+ return ovs_lib.INVALID_OFPORT
+
+ def mock_add_port(self, port_name, *interface_attr_tuples):
+ return self.mock_get_port_ofport(port_name)
+
+ def mock_bridge_exists(self, bridge_name):
+ return True
+
+ def mock_port_exists(self, port_name):
+ return True
+
+ def mock_apply_flows(self):
+ pass
+
+ def mock_get_vif_port_by_id(self, port_id):
+ if port_id in self.port_mapping:
+ port_values = self.port_mapping[port_id]
+ return ovs_lib.VifPort(
+ port_values['port_name'],
+ port_values['ofport'],
+ port_id,
+ port_values['vif_mac'],
+ self.agent.int_br
+ )
+
+ def mock_get_vif_ports(self):
+ vif_ports = []
+ for port_id, port_values in six.iteritems(self.port_mapping):
+ vif_ports.append(
+ ovs_lib.VifPort(
+ port_values['port_name'],
+ port_values['ofport'],
+ port_id,
+ port_values['vif_mac'],
+ self.agent.int_br
+ )
+ )
+ return vif_ports
+
+ def mock_get_ports_attributes(
+ self, table, columns=None, ports=None,
+ check_error=True, log_errors=True,
+ if_exists=False
+ ):
+ port_infos = []
+ for port_id, port_values in six.iteritems(self.port_mapping):
+ port_info = {}
+ if columns:
+ if 'name' in columns:
+ port_info['name'] = port_values['port_name']
+ if 'ofport' in columns:
+ port_info['ofport'] = port_values['ofport']
+ if 'extenal_ids' in columns:
+ port_info['extenal_ids'] = {
+ 'iface-id': port_id,
+ 'attached-mac': port_values['vif_mac']
+ }
+ if 'other_config' in columns:
+ port_info['other_config'] = {}
+ if 'tag' in columns:
+ port_info['tag'] = []
+ else:
+ port_info = {
+ 'name': port_values['port_name'],
+ 'ofport': port_values['ofport'],
+ 'extenal_ids': {
+ 'iface-id': port_id,
+ 'attached-mac': port_values['vif_mac']
+ },
+ 'other_config': {},
+ 'tag': []
+ }
+ if ports:
+ if port_values['port_name'] in ports:
+ port_infos.append(port_info)
+ else:
+ port_infos.append(port_info)
+ return port_infos
+
+ def mock_delete_port(self, port_name):
+ found_port_id = None
+ for port_id, port_values in six.iteritems(self.port_mapping):
+ if port_values['port_name'] == port_name:
+ found_port_id = port_id
+ if found_port_id:
+ del self.port_mapping[found_port_id]
+
+ def mock_create(self, secure_mode=False):
+ pass
+
+ def mock_add_flow(self, *args, **kwargs):
+ if kwargs not in self.added_flows:
+ self.added_flows.append(kwargs)
+
+ def mock_delete_flows(self, *args, **kwargs):
+ if kwargs not in self.deleted_flows:
+ self.deleted_flows.append(kwargs)
+
+ def mock_get_flowrules_by_host_portid(self, context, port_id):
+ return [
+ flowrule
+ for flowrule in self.node_flowrules
+ if (
+ flowrule['ingress'] == port_id or
+ flowrule['egress'] == port_id
+ )
+ ]
+
+ def mock_get_all_src_node_flowrules(self, context):
+ return [
+ flowrule
+ for flowrule in self.node_flowrules
+ if (
+ flowrule['node_type'] == 'src_node' and
+ flowrule['egress'] is None
+ )
+ ]
+
+ def mock_execute(self, cmd, *args, **kwargs):
+ self.executed_cmds.append(' '.join(cmd))
+
+ def tearDown(self):
+ agent.SfcPluginApi = self.backup_plugin_rpc
+ self.create_consumers.stop()
+ self.execute.stop()
+ self.add_flow.stop()
+ self.delete_flows.stop()
+ self.get_vif_port_by_id.stop()
+ self.get_port_ofport.stop()
+ self.set_secure_mode.stop()
+ self.set_protocols.stop()
+ self.del_controller.stop()
+ self.get_bridges.stop()
+ self.get_vif_ports.stop()
+ self.get_ports_attributes.stop()
+ self.delete_port.stop()
+ self.create.stop()
+ self.add_port.stop()
+ self.bridge_exists.stop()
+ self.port_exists.stop()
+ self.apply_flows.stop()
+ self.dump_group_for_id.stop()
+ self.add_group.stop()
+ self.mod_group.stop()
+ self.delete_group.stop()
+ self.node_flowrules = []
+ self.added_flows = []
+ self.deleted_flows = []
+ self.group_mapping = {}
+ self.deleted_groups = []
+ self.port_mapping = {}
+ super(OVSSfcAgentTestCase, self).tearDown()
+
+ def test_update_empty_flow_rules(self):
+ self.port_mapping = {
+ 'dd7374b9-a6ac-4a66-a4a6-7d3dee2a1579': {
+ 'port_name': 'src_port',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '2f1d2140-42ce-4979-9542-7ef25796e536': {
+ 'port_name': 'dst_port',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ }
+ }
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,%d)' % agent.SF_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.FWD_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI
+ }, {
+ 'actions': 'output:%d' % self.int_patch,
+ 'priority': 0,
+ 'table': agent.FWD_SELECTOR
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.GRP_SELECTOR,
+ 'in_port': self.int_patch,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': agent.FWD_SELECTOR
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {}
+ )
+
+ def test_update_flow_rules_port_pair(self):
+ self.port_mapping = {
+ 'dd7374b9-a6ac-4a66-a4a6-7d3dee2a1579': {
+ 'port_name': 'src_port',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '2f1d2140-42ce-4979-9542-7ef25796e536': {
+ 'port_name': 'dst_port',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ }
+ }
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': u'dd7374b9-a6ac-4a66-a4a6-7d3dee2a1579',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 75,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:fd:b2',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'2f1d2140-42ce-4979-9542-7ef25796e536',
+ 'next_group_id': None,
+ 'host_id': u'test1',
+ 'nsp': 256,
+ 'portchain_id': u'84c1411f-7a94-4b4f-9a8b-ad9607c67c76',
+ 'add_fcs': [],
+ 'id': '611bdc42-12b3-4639-8faf-83da4e6403f7'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,%d)' % agent.SF_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.FWD_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI
+ }, {
+ 'actions': 'output:%d' % self.int_patch,
+ 'priority': 0,
+ 'table': agent.FWD_SELECTOR
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.GRP_SELECTOR,
+ 'in_port': self.int_patch,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': agent.FWD_SELECTOR
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': agent.SF_SELECTOR
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {}
+ )
+
+ def test_update_flow_rules_flow_classifiers(self):
+ self.port_mapping = {
+ 'e1229670-2a07-450d-bdc9-34e71c301206': {
+ 'port_name': 'src_port',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '9bedd01e-c216-4dfd-b48e-fbd5c8212ba4': {
+ 'port_name': 'dst_port',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ }
+ }
+
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 43,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:72:05',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': u'9bedd01e-c216-4dfd-b48e-fbd5c8212ba4',
+ 'next_group_id': 1,
+ 'host_id': u'test1',
+ 'nsp': 256,
+ 'portchain_id': u'8cba323e-5e67-4df0-a4b0-7e1ef486a656',
+ 'add_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': u'10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ 'e1229670-2a07-450d-bdc9-34e71c301206'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 200,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': 400,
+ 'logical_source_port': (
+ '9bedd01e-c216-4dfd-b48e-fbd5c8212ba4')
+ }],
+ 'id': '611bdc42-12b3-4639-8faf-83da4e6403f7'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': 'e1229670-2a07-450d-bdc9-34e71c301206',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 43,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:c5:f3',
+ 'network_type': 'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': u'test2',
+ 'nsp': 256,
+ 'portchain_id': '8cba323e-5e67-4df0-a4b0-7e1ef486a656',
+ 'add_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': u'10.200.0.0/16',
+ 'protocol': 'tcp',
+ 'logical_destination_port': (
+ 'e1229670-2a07-450d-bdc9-34e71c301206'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 200,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': 'IPv4',
+ 'destination_port_range_max': 400,
+ 'logical_source_port': (
+ '9bedd01e-c216-4dfd-b48e-fbd5c8212ba4')
+ }],
+ 'id': '611bdc42-12b3-4639-8faf-83da4e6403f8'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,%d)' % agent.SF_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.FWD_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI
+ }, {
+ 'actions': 'output:%d' % self.int_patch,
+ 'priority': 0,
+ 'table': agent.FWD_SELECTOR
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.GRP_SELECTOR,
+ 'in_port': self.int_patch,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': agent.FWD_SELECTOR
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': agent.SF_SELECTOR
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {}
+ )
+
+ def test_update_flow_rules_flow_classifiers_port_pairs(self):
+ self.port_mapping = {
+ '8768d2b3-746d-4868-ae0e-e81861c2b4e6': {
+ 'port_name': 'port1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '29e38fb2-a643-43b1-baa8-a86596461cd5': {
+ 'port_name': 'port2',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ '82a575e0-6a6e-46ba-a5fc-692407839a85': {
+ 'port_name': 'port3',
+ 'ofport': 60,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ '93466f5d-252e-4552-afc6-5fb3f6019f76': {
+ 'port_name': 'port4',
+ 'ofport': 25,
+ 'vif_mac': '00:01:02:03:06:10'
+ }
+ }
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.2',
+ 'ingress': '8768d2b3-746d-4868-ae0e-e81861c2b4e6',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:cf:23'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 33,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:ed:01',
+ 'network_type': 'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': '29e38fb2-a643-43b1-baa8-a86596461cd5',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': 'b9570dc9-822b-41fc-a27c-d915a21a3fe8',
+ 'add_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': u'10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ '82a575e0-6a6e-46ba-a5fc-692407839a85'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': '10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': 'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '29e38fb2-a643-43b1-baa8-a86596461cd5')
+ }],
+ 'id': '73e97aad-8c0f-44e3-bee0-c0a641b00b66'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': '82a575e0-6a6e-46ba-a5fc-692407839a85',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 33,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:a6:84',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': 'b9570dc9-822b-41fc-a27c-d915a21a3fe8',
+ 'add_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': '10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ '82a575e0-6a6e-46ba-a5fc-692407839a85'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '29e38fb2-a643-43b1-baa8-a86596461cd5')
+ }],
+ 'id': 'fa385d84-7d78-44e7-aa8d-7b4a279a14d7'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': '8768d2b3-746d-4868-ae0e-e81861c2b4e6',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.2',
+ 'ingress': '82a575e0-6a6e-46ba-a5fc-692407839a85',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:a6:84'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 33,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:cf:23',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': '93466f5d-252e-4552-afc6-5fb3f6019f76',
+ 'next_group_id': None,
+ 'host_id': 'test3',
+ 'nsp': 256,
+ 'portchain_id': 'b9570dc9-822b-41fc-a27c-d915a21a3fe8',
+ 'add_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': '10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ '82a575e0-6a6e-46ba-a5fc-692407839a85'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '29e38fb2-a643-43b1-baa8-a86596461cd5')
+ }],
+ 'id': '07cc65a8-e99b-4175-a2f1-69b87eb8090a'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,%d)' % agent.SF_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.FWD_SELECTOR,
+ 'dl_type': 34887,
+ 'priority': agent.PC_DEF_PRI
+ }, {
+ 'actions': 'output:%d' % self.int_patch,
+ 'priority': 0,
+ 'table': agent.FWD_SELECTOR
+ }, {
+ 'actions': 'resubmit(,%d)' % agent.GRP_SELECTOR,
+ 'in_port': self.int_patch,
+ 'priority': agent.PC_DEF_PRI,
+ 'table': agent.FWD_SELECTOR
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 42,
+ 'nw_dst': u'10.200.0.0/16',
+ 'nw_proto': 6,
+ 'nw_src': u'10.100.0.0/16',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0x12c/0xffff',
+ 'tp_src': '0x64/0xffff'
+ }, {
+ 'actions': 'group:1',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 0,
+ 'table': agent.GRP_SELECTOR
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:60',
+ 'dl_dst': '00:01:02:03:06:09',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': agent.SF_SELECTOR
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:a6:84,'
+ 'set_field:33->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'nw_dst': u'10.200.0.0/16',
+ 'nw_proto': 6,
+ 'nw_src': u'10.100.0.0/16',
+ 'priority': 0,
+ 'table': agent.GRP_SELECTOR,
+ 'tp_dst': '0x12c/0xffff',
+ 'tp_src': '0x64/0xffff'
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 25,
+ 'nw_dst': u'10.200.0.0/16',
+ 'nw_proto': 6,
+ 'nw_src': u'10.100.0.0/16',
+ 'priority': agent.PC_DEF_PRI,
+ 'table': 0,
+ 'tp_dst': '0x12c/0xffff',
+ 'tp_src': '0x64/0xffff'
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': agent.SF_SELECTOR
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:cf:23,'
+ 'set_field:33->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ }
+ }
+ )
+
+ def test_update_flow_rules_flow_classifiers_multi_port_groups(self):
+ self.port_mapping = {
+ '6331a00d-779b-462b-b0e4-6a65aa3164ef': {
+ 'port_name': 'port1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '1ebf82cf-70f9-43fd-8b90-6546f7d13040': {
+ 'port_name': 'port2',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ '34032c43-5207-43bb-95cb-cf426266fa11': {
+ 'port_name': 'port3',
+ 'ofport': 60,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ 'eaeec782-4ee8-4c7f-8ecb-f759dab4c723': {
+ 'port_name': 'port4',
+ 'ofport': 25,
+ 'vif_mac': '00:01:02:03:06:10'
+ },
+ 'f56df7aa-e521-41ce-9001-ed7bedb65c9e': {
+ 'port_name': 'port5',
+ 'ofport': 5,
+ 'vif_mac': '00:01:02:03:06:11'
+ },
+ '15dc026d-0520-4f92-9841-1056e62fdcaa': {
+ 'port_name': 'port6',
+ 'ofport': 50,
+ 'vif_mac': '00:01:02:03:06:12'
+ },
+ 'd98a48fe-4ef7-4aa6-89fa-02312e54c1bd': {
+ 'port_name': 'port7',
+ 'ofport': 4,
+ 'vif_mac': '00:01:02:03:06:13'
+ },
+ 'd412d042-d8bc-4dd9-b2be-b29c7e8b2c1b': {
+ 'port_name': 'port8',
+ 'ofport': 8,
+ 'vif_mac': '00:01:02:03:06:14'
+ }
+ }
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.2',
+ 'ingress': '34032c43-5207-43bb-95cb-cf426266fa11',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:b0:88'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 37,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:74:91',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': '6331a00d-779b-462b-b0e4-6a65aa3164ef',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': 'd0b48df7-47ab-4909-b864-9aae1a6ee6fb',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '1ebf82cf-70f9-43fd-8b90-6546f7d13040'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': 'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '6331a00d-779b-462b-b0e4-6a65aa3164ef')
+ }],
+ 'id': 'bbb1e50c-ecbb-400c-a7e9-8aed8f36993f'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 251,
+ 'ingress': '1ebf82cf-70f9-43fd-8b90-6546f7d13040',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 37,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:b7:0d',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': 'd0b48df7-47ab-4909-b864-9aae1a6ee6fb',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '1ebf82cf-s70f9-43fd-8b90-6546f7d13040'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '6331a00d-779b-462b-b0e4-6a65aa3164ef')
+ }],
+ 'id': '7ed75c14-2283-484a-97b8-30e23fbf7457'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': '34032c43-5207-43bb-95cb-cf426266fa11',
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'f56df7aa-e521-41ce-9001-ed7bedb65c9e',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:b1:0d'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 37,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:b0:88',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'eaeec782-4ee8-4c7f-8ecb-f759dab4c723',
+ 'next_group_id': 2,
+ 'host_id': u'test3',
+ 'nsp': 256,
+ 'portchain_id': u'd0b48df7-47ab-4909-b864-9aae1a6ee6fb',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '1ebf82cf-70f9-43fd-8b90-6546f7d13040'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '6331a00d-779b-462b-b0e4-6a65aa3164ef')
+ }],
+ 'id': 'f9fd9c7a-0100-43fb-aea9-30c67f2a731a'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': 'f56df7aa-e521-41ce-9001-ed7bedb65c9e',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.2',
+ 'ingress': 'd98a48fe-4ef7-4aa6-89fa-02312e54c1bd',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:4e:dd'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 37,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:b1:0d',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'15dc026d-0520-4f92-9841-1056e62fdcaa',
+ 'next_group_id': 3,
+ 'host_id': u'test5',
+ 'nsp': 256,
+ 'portchain_id': u'd0b48df7-47ab-4909-b864-9aae1a6ee6fb',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '1ebf82cf-70f9-43fd-8b90-6546f7d13040'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '6331a00d-779b-462b-b0e4-6a65aa3164ef')
+ }],
+ 'id': '62f4bb35-1b4a-4cc4-bf07-f40ed5c2d6a7'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 252,
+ 'ingress': u'd98a48fe-4ef7-4aa6-89fa-02312e54c1bd',
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'1ebf82cf-70f9-43fd-8b90-6546f7d13040',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:b7:0d'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 37,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:4e:dd',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'd412d042-d8bc-4dd9-b2be-b29c7e8b2c1b',
+ 'next_group_id': None,
+ 'host_id': u'test7',
+ 'nsp': 256,
+ 'portchain_id': u'd0b48df7-47ab-4909-b864-9aae1a6ee6fb',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '1ebf82cf-70f9-43fd-8b90-6546f7d13040'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '6331a00d-779b-462b-b0e4-6a65aa3164ef')
+ }],
+ 'id': 'a535e740-02cc-47ef-aab1-7bcb1594db9b'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:%d' % self.int_patch,
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': self.int_patch,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 6,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:1',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:42'
+ ),
+ 'dl_dst': '00:01:02:03:06:08',
+ 'dl_type': 34887,
+ 'mpls_label': 65788,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 25,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:2',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:60'
+ ),
+ 'dl_dst': '00:01:02:03:06:09',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65789,'
+ 'set_mpls_ttl:253,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 50,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:3',
+ 'dl_type': 34887,
+ 'mpls_label': 65789,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:5'
+ ),
+ 'dl_dst': '00:01:02:03:06:11',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:b7:0d,'
+ 'set_field:37->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65788,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65788,'
+ 'set_mpls_ttl:252,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 8,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:4'
+ ),
+ 'dl_dst': '00:01:02:03:06:13',
+ 'dl_type': 34887,
+ 'mpls_label': 65789,
+ 'priority': 1,
+ 'table': 5
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:b0:88,'
+ 'set_field:37->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ },
+ 2: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:b1:0d,'
+ 'set_field:37->tun_id,output:[]'
+ ),
+ 'group_id': 2,
+ 'type': 'select'
+ },
+ 3: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:4e:dd,'
+ 'set_field:37->tun_id,output:[]'
+ ),
+ 'group_id': 3,
+ 'type': 'select'
+ }
+ }
+ )
+
+ def test_update_flow_rules_flow_classifiers_multi_port_pairs(self):
+ self.port_mapping = {
+ '9864d8e8-0aff-486e-8b84-7a8d20c017d4': {
+ 'port_name': 'port1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '21047d09-eaa7-4296-af56-b509e4a10853': {
+ 'port_name': 'port2',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ '38266cfe-cd42-413e-80ff-d0d0c74ad260': {
+ 'port_name': 'port3',
+ 'ofport': 60,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ '272be90c-b140-4e9d-8dd3-1993fbb3656c': {
+ 'port_name': 'port4',
+ 'ofport': 25,
+ 'vif_mac': '00:01:02:03:06:10'
+ },
+ 'd1791c8d-a07a-4f35-bd52-b99395da0d76': {
+ 'port_name': 'port5',
+ 'ofport': 5,
+ 'vif_mac': '00:01:02:03:06:11'
+ },
+ 'ed2804bd-d61a-49e7-9007-76d2540ae78a': {
+ 'port_name': 'port6',
+ 'ofport': 50,
+ 'vif_mac': '00:01:02:03:06:12'
+ },
+ 'bdf4f759-ca35-4cf5-89ac-53da0d6b3fbf': {
+ 'port_name': 'port7',
+ 'ofport': 4,
+ 'vif_mac': '00:01:02:03:06:13'
+ },
+ 'a55b9062-d3fa-4dc2-a4df-bb8b2a908c19': {
+ 'port_name': 'port8',
+ 'ofport': 8,
+ 'vif_mac': '00:01:02:03:06:14'
+ }
+ }
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'38266cfe-cd42-413e-80ff-d0d0c74ad260',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:74:c1'
+ }, {
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'd1791c8d-a07a-4f35-bd52-b99395da0d76',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:4f:6e'
+ }, {
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'bdf4f759-ca35-4cf5-89ac-53da0d6b3fbf',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:d5:66'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 51,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:9c:70',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': u'9864d8e8-0aff-486e-8b84-7a8d20c017d4',
+ 'next_group_id': 1,
+ 'host_id': u'test1',
+ 'nsp': 256,
+ 'portchain_id': u'3dddbb0c-5ac4-437c-9b62-ed7ddf8df37f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '21047d09-eaa7-4296-af56-b509e4a10853'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '9864d8e8-0aff-486e-8b84-7a8d20c017d4')
+ }],
+ 'id': '677dfe31-8566-4bd8-8a1e-5f8efd7a45eb'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': u'21047d09-eaa7-4296-af56-b509e4a10853',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 51,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:67:cb',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': u'test2',
+ 'nsp': 256,
+ 'portchain_id': u'3dddbb0c-5ac4-437c-9b62-ed7ddf8df37f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '21047d09-eaa7-4296-af56-b509e4a10853'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '9864d8e8-0aff-486e-8b84-7a8d20c017d4')
+ }],
+ 'id': '4f275568-38cb-45a1-a162-e0d1d4ef335d'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': u'38266cfe-cd42-413e-80ff-d0d0c74ad260',
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'21047d09-eaa7-4296-af56-b509e4a10853',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:67:cb'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 51,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:74:c1',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'272be90c-b140-4e9d-8dd3-1993fbb3656c',
+ 'next_group_id': None,
+ 'host_id': u'test3',
+ 'nsp': 256,
+ 'portchain_id': u'3dddbb0c-5ac4-437c-9b62-ed7ddf8df37f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '21047d09-eaa7-4296-af56-b509e4a10853'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '9864d8e8-0aff-486e-8b84-7a8d20c017d4')
+ }],
+ 'id': '48fd97b1-e166-4aff-906f-8096a48a7cb1'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': u'd1791c8d-a07a-4f35-bd52-b99395da0d76',
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'21047d09-eaa7-4296-af56-b509e4a10853',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:67:cb'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 51,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:4f:6e',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'ed2804bd-d61a-49e7-9007-76d2540ae78a',
+ 'next_group_id': None,
+ 'host_id': u'test5',
+ 'nsp': 256,
+ 'portchain_id': u'3dddbb0c-5ac4-437c-9b62-ed7ddf8df37f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '21047d09-eaa7-4296-af56-b509e4a10853'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '9864d8e8-0aff-486e-8b84-7a8d20c017d4')
+ }],
+ 'id': '48fd97b1-e166-4aff-906f-8096a48a7cb1'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': u'bdf4f759-ca35-4cf5-89ac-53da0d6b3fbf',
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'21047d09-eaa7-4296-af56-b509e4a10853',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:67:cb'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 51,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:d5:66',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'a55b9062-d3fa-4dc2-a4df-bb8b2a908c19',
+ 'next_group_id': None,
+ 'host_id': u'test7',
+ 'nsp': 256,
+ 'portchain_id': u'3dddbb0c-5ac4-437c-9b62-ed7ddf8df37f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '21047d09-eaa7-4296-af56-b509e4a10853'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '9864d8e8-0aff-486e-8b84-7a8d20c017d4')
+ }],
+ 'id': '48fd97b1-e166-4aff-906f-8096a48a7cb1'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:%d' % self.int_patch,
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': self.int_patch,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 6,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:1',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:42'
+ ),
+ 'dl_dst': '00:01:02:03:06:08',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:67:cb,'
+ 'set_field:51->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 25,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:60'
+ ),
+ 'dl_dst': '00:01:02:03:06:09',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 50,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:5'
+ ),
+ 'dl_dst': '00:01:02:03:06:11',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 8,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:4'
+ ),
+ 'dl_dst': '00:01:02:03:06:13',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:74:c1,'
+ 'set_field:51->tun_id,output:[],'
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:4f:6e,'
+ 'set_field:51->tun_id,output:[],'
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:d5:66,'
+ 'set_field:51->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ }
+ }
+ )
+
+ def test_update_flow_rules_multi_flow_classifiers(self):
+ self.port_mapping = {
+ '54abe601-6685-4c38-9b9d-0d8381a43d56': {
+ 'port_name': 'port1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ 'c2de00c2-bd91-4f60-8a7d-5a3ea8f65e77': {
+ 'port_name': 'port2',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ '460a5875-b0c6-408e-ada4-0ef01d39bcff': {
+ 'port_name': 'port3',
+ 'ofport': 60,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ 'b2b8a556-593b-4695-8812-cdd33a314867': {
+ 'port_name': 'port4',
+ 'ofport': 25,
+ 'vif_mac': '00:01:02:03:06:10'
+ },
+ '2656a373-a985-4940-90d1-cfe172951e0c': {
+ 'port_name': 'port5',
+ 'ofport': 5,
+ 'vif_mac': '00:01:02:03:06:11'
+ },
+ 'a979a847-3014-43ea-b37d-5a3775a173c7': {
+ 'port_name': 'port6',
+ 'ofport': 50,
+ 'vif_mac': '00:01:02:03:06:12'
+ }
+ }
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'2656a373-a985-4940-90d1-cfe172951e0c',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:5f:ea'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 58,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:b9:09',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': u'54abe601-6685-4c38-9b9d-0d8381a43d56',
+ 'next_group_id': 1,
+ 'host_id': u'test1',
+ 'nsp': 256,
+ 'portchain_id': u'3eefdf29-ea8f-4794-a36f-5e60ec7fe208',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '460a5875-b0c6-408e-ada4-0ef01d39bcff'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '54abe601-6685-4c38-9b9d-0d8381a43d56')
+ }],
+ 'id': 'd2e675d3-739e-4451-95d5-a15e23c6eaac'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'2656a373-a985-4940-90d1-cfe172951e0c',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:5f:ea'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 58,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:4d:d1',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': u'c2de00c2-bd91-4f60-8a7d-5a3ea8f65e77',
+ 'next_group_id': 1,
+ 'host_id': u'test3',
+ 'nsp': 256,
+ 'portchain_id': u'3eefdf29-ea8f-4794-a36f-5e60ec7fe208',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ 'b2b8a556-593b-4695-8812-cdd33a314867'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ 'c2de00c2-bd91-4f60-8a7d-5a3ea8f65e77')
+ }],
+ 'id': 'd2e675d3-739e-4451-95d5-a15e23c6eaac'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': u'460a5875-b0c6-408e-ada4-0ef01d39bcff',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 58,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:fc:b8',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': u'test2',
+ 'nsp': 256,
+ 'portchain_id': u'3eefdf29-ea8f-4794-a36f-5e60ec7fe208',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '460a5875-b0c6-408e-ada4-0ef01d39bcff'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '54abe601-6685-4c38-9b9d-0d8381a43d56')
+ }],
+ 'id': '029823ae-8524-4e1c-8f5b-4ee7ec55f1bd'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': u'b2b8a556-593b-4695-8812-cdd33a314867',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 58,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:7b:15',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': u'test4',
+ 'nsp': 256,
+ 'portchain_id': u'3eefdf29-ea8f-4794-a36f-5e60ec7fe208',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ 'b2b8a556-593b-4695-8812-cdd33a314867'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ 'c2de00c2-bd91-4f60-8a7d-5a3ea8f65e77')
+ }],
+ 'id': '029823ae-8524-4e1c-8f5b-4ee7ec55f1bd'
+ }
+ )
+ self.agent.update_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': u'2656a373-a985-4940-90d1-cfe172951e0c',
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'460a5875-b0c6-408e-ada4-0ef01d39bcff',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:fc:b8'
+ }, {
+ 'local_endpoint': u'10.0.0.2',
+ 'ingress': u'b2b8a556-593b-4695-8812-cdd33a314867',
+ 'weight': 1,
+ 'mac_address': u'12:34:56:78:7b:15'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 58,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:5f:ea',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'a979a847-3014-43ea-b37d-5a3775a173c7',
+ 'next_group_id': None,
+ 'host_id': u'test5',
+ 'nsp': 256,
+ 'portchain_id': u'3eefdf29-ea8f-4794-a36f-5e60ec7fe208',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ '460a5875-b0c6-408e-ada4-0ef01d39bcff'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '54abe601-6685-4c38-9b9d-0d8381a43d56')
+ }, {
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'logical_destination_port': (
+ 'b2b8a556-593b-4695-8812-cdd33a314867'),
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'destination_port_range_min': None,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ 'c2de00c2-bd91-4f60-8a7d-5a3ea8f65e77')
+ }],
+ 'id': '983cfa51-f9e6-4e36-8f6c-0c84df915cd1'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:%d' % self.int_patch,
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': self.int_patch,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 6,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:1',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 42,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:60'
+ ),
+ 'dl_dst': '00:01:02:03:06:09',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:25'
+ ),
+ 'dl_dst': '00:01:02:03:06:10',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:fc:b8,'
+ 'set_field:58->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:%d' % self.tun_patch
+ ),
+ 'dl_type': 2048,
+ 'in_port': 50,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:7b:15,'
+ 'set_field:58->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:5'
+ ),
+ 'dl_dst': '00:01:02:03:06:11',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:5f:ea,'
+ 'set_field:58->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ }
+ }
+ )
+
+ def test_delete_flow_rules_port_pair(self):
+ self.port_mapping = {
+ 'dd7374b9-a6ac-4a66-a4a6-7d3dee2a1579': {
+ 'port_name': 'src_port',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '2f1d2140-42ce-4979-9542-7ef25796e536': {
+ 'port_name': 'dst_port',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ }
+ }
+ self.agent.delete_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': u'dd7374b9-a6ac-4a66-a4a6-7d3dee2a1579',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 75,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:fd:b2',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': u'2f1d2140-42ce-4979-9542-7ef25796e536',
+ 'next_group_id': None,
+ 'host_id': u'test1',
+ 'nsp': 256,
+ 'portchain_id': u'84c1411f-7a94-4b4f-9a8b-ad9607c67c76',
+ 'add_fcs': [],
+ 'id': '611bdc42-12b3-4639-8faf-83da4e6403f7'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.deleted_flows, [{
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': '65791',
+ 'table': 5
+ }, {
+ 'dl_type': 34887,
+ 'mpls_label': '65790',
+ 'table': 31
+ }]
+ )
+ self.assertEqual(
+ self.deleted_groups, [
+ ]
+ )
+
+ def test_delete_flow_rules_flow_classifiers(self):
+ self.port_mapping = {
+ 'e1229670-2a07-450d-bdc9-34e71c301206': {
+ 'port_name': 'src_port',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '9bedd01e-c216-4dfd-b48e-fbd5c8212ba4': {
+ 'port_name': 'dst_port',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ }
+ }
+
+ self.agent.delete_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': None,
+ 'add_fcs': [],
+ 'segment_id': 43,
+ 'group_refcnt': 1,
+ 'mac_address': u'12:34:56:78:72:05',
+ 'network_type': u'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': u'9bedd01e-c216-4dfd-b48e-fbd5c8212ba4',
+ 'next_group_id': 1,
+ 'host_id': u'test1',
+ 'nsp': 256,
+ 'portchain_id': u'8cba323e-5e67-4df0-a4b0-7e1ef486a656',
+ 'del_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': u'10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ 'e1229670-2a07-450d-bdc9-34e71c301206'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '9bedd01e-c216-4dfd-b48e-fbd5c8212ba4')
+ }],
+ 'id': '611bdc42-12b3-4639-8faf-83da4e6403f7'
+ }
+ )
+ self.agent.delete_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': 'e1229670-2a07-450d-bdc9-34e71c301206',
+ 'next_hops': None,
+ 'add_fcs': [],
+ 'segment_id': 43,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:c5:f3',
+ 'network_type': 'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': u'test2',
+ 'nsp': 256,
+ 'portchain_id': '8cba323e-5e67-4df0-a4b0-7e1ef486a656',
+ 'del_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': u'10.200.0.0/16',
+ 'protocol': 'tcp',
+ 'logical_destination_port': (
+ 'e1229670-2a07-450d-bdc9-34e71c301206'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': 'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '9bedd01e-c216-4dfd-b48e-fbd5c8212ba4')
+ }],
+ 'id': '611bdc42-12b3-4639-8faf-83da4e6403f8'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.deleted_flows, [{
+ 'dl_type': 2048,
+ 'in_port': 42,
+ 'nw_dst': u'10.200.0.0/16',
+ 'nw_proto': 6,
+ 'nw_src': u'10.100.0.0/16',
+ 'table': 0,
+ 'tp_dst': '0x12c/0xffff',
+ 'tp_src': '0x64/0xffff'
+ }, {
+ 'dl_type': 34887,
+ 'mpls_label': '65791',
+ 'table': 31
+ }, {
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': '65790',
+ 'table': 5
+ }]
+ )
+ self.assertEqual(
+ self.deleted_groups, [1]
+ )
+
+ def test_delete_flow_rules_flow_classifiers_port_pairs(self):
+ self.port_mapping = {
+ '8768d2b3-746d-4868-ae0e-e81861c2b4e6': {
+ 'port_name': 'port1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '29e38fb2-a643-43b1-baa8-a86596461cd5': {
+ 'port_name': 'port2',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ '82a575e0-6a6e-46ba-a5fc-692407839a85': {
+ 'port_name': 'port3',
+ 'ofport': 60,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ '93466f5d-252e-4552-afc6-5fb3f6019f76': {
+ 'port_name': 'port4',
+ 'ofport': 25,
+ 'vif_mac': '00:01:02:03:06:10'
+ }
+ }
+ self.agent.delete_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.2',
+ 'ingress': '8768d2b3-746d-4868-ae0e-e81861c2b4e6',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:cf:23'
+ }],
+ 'add_fcs': [],
+ 'segment_id': 33,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:ed:01',
+ 'network_type': 'gre',
+ 'local_endpoint': u'10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': '29e38fb2-a643-43b1-baa8-a86596461cd5',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': 'b9570dc9-822b-41fc-a27c-d915a21a3fe8',
+ 'del_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': u'10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ '82a575e0-6a6e-46ba-a5fc-692407839a85'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': '10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': 'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '29e38fb2-a643-43b1-baa8-a86596461cd5')
+ }],
+ 'id': '73e97aad-8c0f-44e3-bee0-c0a641b00b66'
+ }
+ )
+ self.agent.delete_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 253,
+ 'ingress': '82a575e0-6a6e-46ba-a5fc-692407839a85',
+ 'next_hops': None,
+ 'add_fcs': [],
+ 'segment_id': 33,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:a6:84',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': 'b9570dc9-822b-41fc-a27c-d915a21a3fe8',
+ 'del_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': '10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ '82a575e0-6a6e-46ba-a5fc-692407839a85'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '29e38fb2-a643-43b1-baa8-a86596461cd5')
+ }],
+ 'id': 'fa385d84-7d78-44e7-aa8d-7b4a279a14d7'
+ }
+ )
+ self.agent.delete_flow_rules(
+ self.context, flowrule_entries={
+ 'nsi': 254,
+ 'ingress': '8768d2b3-746d-4868-ae0e-e81861c2b4e6',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.2',
+ 'ingress': '82a575e0-6a6e-46ba-a5fc-692407839a85',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:a6:84'
+ }],
+ 'add_fcs': [],
+ 'segment_id': 33,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:cf:23',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': '93466f5d-252e-4552-afc6-5fb3f6019f76',
+ 'next_group_id': None,
+ 'host_id': 'test3',
+ 'nsp': 256,
+ 'portchain_id': 'b9570dc9-822b-41fc-a27c-d915a21a3fe8',
+ 'del_fcs': [{
+ 'source_port_range_min': 100,
+ 'destination_ip_prefix': '10.200.0.0/16',
+ 'protocol': u'tcp',
+ 'logical_destination_port': (
+ '82a575e0-6a6e-46ba-a5fc-692407839a85'),
+ 'l7_parameters': {},
+ 'source_port_range_max': 100,
+ 'source_ip_prefix': u'10.100.0.0/16',
+ 'destination_port_range_min': 300,
+ 'ethertype': u'IPv4',
+ 'destination_port_range_max': 300,
+ 'logical_source_port': (
+ '29e38fb2-a643-43b1-baa8-a86596461cd5')
+ }],
+ 'id': '07cc65a8-e99b-4175-a2f1-69b87eb8090a'
+ }
+ )
+ self.assertEqual(
+ self.executed_cmds, [
+ ]
+ )
+ self.assertEqual(
+ self.deleted_flows, [{
+ 'dl_type': 2048,
+ 'in_port': 42,
+ 'nw_dst': u'10.200.0.0/16',
+ 'nw_proto': 6,
+ 'nw_src': '10.100.0.0/16',
+ 'table': 0,
+ 'tp_dst': '0x12c/0xffff',
+ 'tp_src': '0x64/0xffff'
+ }, {
+ 'dl_type': 34887,
+ 'mpls_label': '65791',
+ 'table': 31
+ }, {
+ 'dl_dst': '00:01:02:03:06:09',
+ 'dl_type': 34887,
+ 'mpls_label': '65790',
+ 'table': 5
+ }, {
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': '65791',
+ 'table': 5
+ }, {
+ 'dl_type': 2048,
+ 'in_port': 25,
+ 'nw_dst': '10.200.0.0/16',
+ 'nw_proto': 6,
+ 'nw_src': u'10.100.0.0/16',
+ 'table': 0,
+ 'tp_dst': '0x12c/0xffff',
+ 'tp_src': '0x64/0xffff'
+ }, {
+ 'dl_type': 34887,
+ 'mpls_label': '65790',
+ 'table': 31
+ }]
+ )
+ self.assertEqual(
+ self.deleted_groups, [1]
+ )
+
+ def test_init_agent_empty_flowrules(self):
+ self.node_flowrules = []
+ self.init_agent()
+ self.assertItemsEqual(
+ self.added_flows,
+ [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:1',
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': 1,
+ 'priority': 10,
+ 'table': 30
+ }]
+ )
+ self.assertEqual(self.group_mapping, {})
+
+ def test_init_agent_portchain_portpairs(self):
+ self.port_mapping = {
+ '4f72c5fc-37e9-4e6f-8cd8-e8166c4b45c4': {
+ 'port_name': 'ingress',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '57f35c35-dceb-4934-9a78-b40a0a3e16b3': {
+ 'port_name': 'egress',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ }
+ }
+ self.node_flowrules = [{
+ 'nsi': 254,
+ 'ingress': '4f72c5fc-37e9-4e6f-8cd8-e8166c4b45c4',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 34,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:2d:f4',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'sf_node',
+ 'egress': '57f35c35-dceb-4934-9a78-b40a0a3e16b3',
+ 'next_group_id': None,
+ 'host_id': u'test2',
+ 'nsp': 256,
+ 'portchain_id': '0f604e43-c941-4f42-a96c-8bd027e5507d',
+ 'add_fcs': [],
+ 'id': 'b6ebb2c3-4e9c-4146-8a74-f3985173dc44'
+ }]
+ self.init_agent()
+ for port_id in self.port_mapping:
+ self.agent.sfc_treat_devices_added_updated(port_id)
+ self.assertItemsEqual(
+ self.added_flows,
+ [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:1',
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': 1,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': agent.SF_SELECTOR
+ }]
+ )
+ self.assertEqual(self.group_mapping, {})
+
+ def test_init_agent_portchain_flowclassifiers(self):
+ self.port_mapping = {
+ '5aa33c52-535a-48eb-a77c-e02329bb9eb7': {
+ 'port_name': 'src_port',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '079d214c-1aea-439d-bf3c-dad03db47dcb': {
+ 'port_name': 'dst_port',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ }
+ }
+ self.node_flowrules = [{
+ 'nsi': 253,
+ 'ingress': '5aa33c52-535a-48eb-a77c-e02329bb9eb7',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 43,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:ac:22',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.3',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': 'd66efb47-f080-41da-8499-c6e89327ecc0',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '5aa33c52-535a-48eb-a77c-e02329bb9eb7'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '079d214c-1aea-439d-bf3c-dad03db47dcb'
+ }],
+ 'id': '9d8ec269-874a-42b2-825f-d25858341ec2'
+ }, {
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 43,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:e3:b3',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': '079d214c-1aea-439d-bf3c-dad03db47dcb',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': 'd66efb47-f080-41da-8499-c6e89327ecc0',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '5aa33c52-535a-48eb-a77c-e02329bb9eb7'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '079d214c-1aea-439d-bf3c-dad03db47dcb'
+ }],
+ 'id': u'361811ed-2902-4d35-9fe4-a3a2b062ef37'
+ }]
+ self.init_agent()
+ for port_id in self.port_mapping:
+ self.agent.sfc_treat_devices_added_updated(port_id)
+ self.assertItemsEqual(
+ self.added_flows,
+ [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:1',
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': 1,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }]
+ )
+ self.assertEqual(self.group_mapping, {})
+
+ def test_init_agent_portchain_flow_classifiers_port_pairs(self):
+ self.port_mapping = {
+ '2881f577-3828-40f2-855d-2f86d63a4733': {
+ 'port_name': 'dst_port',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '5546e281-319b-4bdd-95c9-37fe4244aeb3': {
+ 'port_name': 'ingress',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ 'c45ccd73-46ad-4d91-b44d-68c15a822521': {
+ 'port_name': 'egress',
+ 'ofport': 43,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ 'd2ebbafb-500e-4926-9751-de73906a1e00': {
+ 'port_name': 'src_port',
+ 'ofport': 44,
+ 'vif_mac': '00:01:02:03:06:10'
+ }
+ }
+ self.node_flowrules = [{
+ 'nsi': 253,
+ 'ingress': '2881f577-3828-40f2-855d-2f86d63a4733',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 67,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:17:0c',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.3',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': 'cddb174c-9e50-4411-b844-41ecb9caf4c4',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': u'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2881f577-3828-40f2-855d-2f86d63a4733'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': 'd2ebbafb-500e-4926-9751-de73906a1e00'
+ }],
+ 'id': '752ca419-6729-461f-993f-fbd44bbd0edb'
+ }, {
+ 'nsi': 254,
+ 'ingress': '5546e281-319b-4bdd-95c9-37fe4244aeb3',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.3',
+ 'ingress': '2881f577-3828-40f2-855d-2f86d63a4733',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:17:0c'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 67,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:ca:de',
+ 'network_type': u'gre',
+ 'local_endpoint': '10.0.0.4',
+ 'node_type': 'sf_node',
+ 'egress': 'c45ccd73-46ad-4d91-b44d-68c15a822521',
+ 'next_group_id': None,
+ 'host_id': 'test4',
+ 'nsp': 256,
+ 'portchain_id': 'cddb174c-9e50-4411-b844-41ecb9caf4c4',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2881f577-3828-40f2-855d-2f86d63a4733'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': 'd2ebbafb-500e-4926-9751-de73906a1e00'
+ }],
+ 'id': 'f70d81ec-1b7c-4ab4-9cf3-da5375ad47e9'
+ }, {
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.4',
+ 'ingress': '5546e281-319b-4bdd-95c9-37fe4244aeb3',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:ca:de'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 67,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:8c:68',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': 'd2ebbafb-500e-4926-9751-de73906a1e00',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': 'cddb174c-9e50-4411-b844-41ecb9caf4c4',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2881f577-3828-40f2-855d-2f86d63a4733'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': 'd2ebbafb-500e-4926-9751-de73906a1e00'
+ }],
+ 'id': 'f52624f0-81d9-4041-81cf-dfe151d3a949'
+ }]
+ self.init_agent()
+ for port_id in self.port_mapping:
+ self.agent.sfc_treat_devices_added_updated(port_id)
+ self.assertItemsEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:1',
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': 1,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,'
+ 'output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 44,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:1',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:17:0c,'
+ 'set_field:67->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 43,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:42',
+ 'dl_dst': '00:01:02:03:06:08',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:ca:de,'
+ 'set_field:67->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ }
+ }
+ )
+
+ def test_init_agent_portchain_multi_port_groups_port_pairs(self):
+ self.port_mapping = {
+ '495d5bcf-f8ef-47d7-995a-5a8ef2e6d1ea': {
+ 'port_name': 'ingress1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '0dd212fb-1e0f-4b1a-abc2-a3a39bbab3ef': {
+ 'port_name': 'egress1',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ '6d7aa494-7796-46ea-9cfe-52d2b0f84217': {
+ 'port_name': 'src_port',
+ 'ofport': 43,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ '028c5816-7d4b-453e-8ec2-f3a084ae992f': {
+ 'port_name': 'ingress2',
+ 'ofport': 44,
+ 'vif_mac': '00:01:02:03:06:10'
+ },
+ '3e4e8d33-334b-4c67-8e04-143eeb6f8351': {
+ 'port_name': 'egress2',
+ 'ofport': 45,
+ 'vif_mac': '00:01:02:03:06:11'
+ },
+ '73d1dbc7-ba46-4b16-85a0-73b106a96fa1': {
+ 'port_name': 'dst_port',
+ 'ofport': 46,
+ 'vif_mac': '00:01:02:03:06:12'
+ },
+ '1778085d-9f81-4e1e-9748-0bafece63344': {
+ 'port_name': 'ingress3',
+ 'ofport': 47,
+ 'vif_mac': '00:01:02:03:06:13'
+ },
+ 'a47cbe65-ea3f-4faa-af27-8212a121c91f': {
+ 'port_name': 'egress3',
+ 'ofport': 48,
+ 'vif_mac': '00:01:02:03:06:14'
+ }
+ }
+ self.node_flowrules = [{
+ 'nsi': 254,
+ 'ingress': '495d5bcf-f8ef-47d7-995a-5a8ef2e6d1ea',
+ 'next_hops': [{
+ 'local_endpoint': u'10.0.0.6',
+ 'ingress': '73d1dbc7-ba46-4b16-85a0-73b106a96fa1',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:51:cc'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 7,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:1d:84',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.4',
+ 'node_type': 'sf_node',
+ 'egress': '0dd212fb-1e0f-4b1a-abc2-a3a39bbab3ef',
+ 'next_group_id': 2,
+ 'host_id': 'test3',
+ 'nsp': 256,
+ 'portchain_id': '0aa6b9fe-6b5e-4b72-91aa-45bce6587ca7',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'a47cbe65-ea3f-4faa-af27-8212a121c91f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '6d7aa494-7796-46ea-9cfe-52d2b0f84217'
+ }],
+ 'id': u'1fe85cf2-41fb-4b30-80de-4ae35d3c2b1c'
+ }, {
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.4',
+ 'ingress': '495d5bcf-f8ef-47d7-995a-5a8ef2e6d1ea',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:1d:84'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 7,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:45:d7',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': '6d7aa494-7796-46ea-9cfe-52d2b0f84217',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': '0aa6b9fe-6b5e-4b72-91aa-45bce6587ca7',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'a47cbe65-ea3f-4faa-af27-8212a121c91f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '6d7aa494-7796-46ea-9cfe-52d2b0f84217'
+ }],
+ 'id': '3c4b700b-e993-4378-b41a-95f609b3c799'
+ }, {
+ 'nsi': 252,
+ 'ingress': '028c5816-7d4b-453e-8ec2-f3a084ae992f',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.3',
+ 'ingress': 'a47cbe65-ea3f-4faa-af27-8212a121c91f',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:54:76'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 7,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:47:34',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.8',
+ 'node_type': 'sf_node',
+ 'egress': '3e4e8d33-334b-4c67-8e04-143eeb6f8351',
+ 'next_group_id': None,
+ 'host_id': 'test8',
+ 'nsp': 256,
+ 'portchain_id': '0aa6b9fe-6b5e-4b72-91aa-45bce6587ca7',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'a47cbe65-ea3f-4faa-af27-8212a121c91f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': u'6d7aa494-7796-46ea-9cfe-52d2b0f84217'
+ }],
+ 'id': '05574d93-104e-425f-8a30-640721f2c749'
+ }, {
+ 'nsi': 253,
+ 'ingress': '73d1dbc7-ba46-4b16-85a0-73b106a96fa1',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.8',
+ 'ingress': '028c5816-7d4b-453e-8ec2-f3a084ae992f',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:47:34'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 7,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:51:cc',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.6',
+ 'node_type': 'sf_node',
+ 'egress': '1778085d-9f81-4e1e-9748-0bafece63344',
+ 'next_group_id': 3,
+ 'host_id': 'test5',
+ 'nsp': 256,
+ 'portchain_id': '0aa6b9fe-6b5e-4b72-91aa-45bce6587ca7',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'a47cbe65-ea3f-4faa-af27-8212a121c91f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '6d7aa494-7796-46ea-9cfe-52d2b0f84217'
+ }],
+ 'id': u'5038a916-93de-4734-a830-d88c9d65566c'
+ }, {
+ 'nsi': 251,
+ 'ingress': 'a47cbe65-ea3f-4faa-af27-8212a121c91f',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 7,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:54:76',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.3',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': '0aa6b9fe-6b5e-4b72-91aa-45bce6587ca7',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'a47cbe65-ea3f-4faa-af27-8212a121c91f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '6d7aa494-7796-46ea-9cfe-52d2b0f84217'
+ }],
+ 'id': '42b8abe6-5bfa-47c5-a992-771e333dae52'
+ }]
+ self.init_agent()
+ for port_id in self.port_mapping:
+ self.agent.sfc_treat_devices_added_updated(port_id)
+ self.assertItemsEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:1',
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': 1,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65789,'
+ 'set_mpls_ttl:253,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 47,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:3',
+ 'dl_type': 34887,
+ 'mpls_label': 65789,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'pop_mpls:0x0800,'
+ 'output:46'
+ ),
+ 'dl_dst': '00:01:02:03:06:12',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:54:76,'
+ 'set_field:7->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65788,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65788,'
+ 'set_mpls_ttl:252,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 45,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:44',
+ 'dl_dst': '00:01:02:03:06:10',
+ 'dl_type': 34887,
+ 'mpls_label': 65789,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 43,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:1',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 42,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:2',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'dl_dst': '00:01:02:03:05:07',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:48',
+ 'dl_dst': '00:01:02:03:06:14',
+ 'dl_type': 34887,
+ 'mpls_label': 65788,
+ 'priority': 1,
+ 'table': 5
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:1d:84,'
+ 'set_field:7->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ },
+ 2: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:51:cc,'
+ 'set_field:7->tun_id,output:[]'
+ ),
+ 'group_id': 2,
+ 'type': 'select'
+ },
+ 3: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:47:34,'
+ 'set_field:7->tun_id,output:[]'
+ ),
+ 'group_id': 3,
+ 'type': 'select'
+ }
+ }
+ )
+
+ def test_init_agent_portchain_port_group_multi_port_pairs(self):
+ self.port_mapping = {
+ '8849af69-117d-4db9-83fa-85329b0efbd6': {
+ 'port_name': 'ingress1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '51f58f0f-6870-4e75-9fd1-13cf3ce29b3e': {
+ 'port_name': 'egress1',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ 'a57a8160-a202-477b-aca1-e7c006bc93a2': {
+ 'port_name': 'src_port',
+ 'ofport': 43,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ '23d02749-7f2b-456d-b9f1-7869300375d4': {
+ 'port_name': 'ingress2',
+ 'ofport': 44,
+ 'vif_mac': '00:01:02:03:06:10'
+ },
+ 'c5dacf1c-f84a-43e0-8873-b2cba77970af': {
+ 'port_name': 'egress2',
+ 'ofport': 45,
+ 'vif_mac': '00:01:02:03:06:11'
+ },
+ '2b17abfa-7afb-4e83-8e15-ad21a6044bb7': {
+ 'port_name': 'dst_port',
+ 'ofport': 46,
+ 'vif_mac': '00:01:02:03:06:12'
+ },
+ 'b299c792-28c8-4f6a-84a0-589163a9b1d4': {
+ 'port_name': 'ingress3',
+ 'ofport': 47,
+ 'vif_mac': '00:01:02:03:06:13'
+ },
+ '60d47d04-42c0-4478-9136-6247fd5d058d': {
+ 'port_name': 'egress3',
+ 'ofport': 48,
+ 'vif_mac': '00:01:02:03:06:14'
+ }
+ }
+ self.node_flowrules = [{
+ 'nsi': 254,
+ 'ingress': '8849af69-117d-4db9-83fa-85329b0efbd6',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.3',
+ 'ingress': '2b17abfa-7afb-4e83-8e15-ad21a6044bb7',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:68:3a'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 68,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:fe:38',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.6',
+ 'node_type': 'sf_node',
+ 'egress': '51f58f0f-6870-4e75-9fd1-13cf3ce29b3e',
+ 'next_group_id': None,
+ 'host_id': 'test6',
+ 'nsp': 256,
+ 'portchain_id': '10f6a764-6963-4b8e-9ae4-a1e5e805915e',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b17abfa-7afb-4e83-8e15-ad21a6044bb7'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': 'a57a8160-a202-477b-aca1-e7c006bc93a2'
+ }],
+ 'id': u'1409e7b8-ed6f-41ae-ba6b-8ef96bbb8da9'
+ }, {
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.4',
+ 'ingress': 'b299c792-28c8-4f6a-84a0-589163a9b1d4',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:58:ee'
+ }, {
+ 'local_endpoint': '10.0.0.6',
+ 'ingress': '8849af69-117d-4db9-83fa-85329b0efbd6',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:fe:38'
+ }, {
+ 'local_endpoint': '10.0.0.8',
+ 'ingress': '23d02749-7f2b-456d-b9f1-7869300375d4',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:32:30'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 68,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:e0:a9',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': 'a57a8160-a202-477b-aca1-e7c006bc93a2',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': '10f6a764-6963-4b8e-9ae4-a1e5e805915e',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b17abfa-7afb-4e83-8e15-ad21a6044bb7'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ 'a57a8160-a202-477b-aca1-e7c006bc93a2')
+ }],
+ 'id': '6c686bd6-a064-4650-ace7-0bd34fa4238a'
+ }, {
+ 'nsi': 254,
+ 'ingress': '23d02749-7f2b-456d-b9f1-7869300375d4',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.3',
+ 'ingress': '2b17abfa-7afb-4e83-8e15-ad21a6044bb7',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:68:3a'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 68,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:32:30',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.8',
+ 'node_type': 'sf_node',
+ 'egress': 'c5dacf1c-f84a-43e0-8873-b2cba77970af',
+ 'next_group_id': None,
+ 'host_id': u'test8',
+ 'nsp': 256,
+ 'portchain_id': '10f6a764-6963-4b8e-9ae4-a1e5e805915e',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b17abfa-7afb-4e83-8e15-ad21a6044bb7'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ 'a57a8160-a202-477b-aca1-e7c006bc93a2')
+ }],
+ 'id': u'1409e7b8-ed6f-41ae-ba6b-8ef96bbb8da9'
+ }, {
+ 'nsi': 253,
+ 'ingress': '2b17abfa-7afb-4e83-8e15-ad21a6044bb7',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 68,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:68:3a',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.3',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': '10f6a764-6963-4b8e-9ae4-a1e5e805915e',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b17abfa-7afb-4e83-8e15-ad21a6044bb7'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ 'a57a8160-a202-477b-aca1-e7c006bc93a2')
+ }],
+ 'id': '12a279c1-cf81-4c1b-bac3-e9690465aeaf'
+ }, {
+ 'nsi': 254,
+ 'ingress': 'b299c792-28c8-4f6a-84a0-589163a9b1d4',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.3',
+ 'ingress': '2b17abfa-7afb-4e83-8e15-ad21a6044bb7',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:68:3a'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 68,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:58:ee',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.4',
+ 'node_type': 'sf_node',
+ 'egress': '60d47d04-42c0-4478-9136-6247fd5d058d',
+ 'next_group_id': None,
+ 'host_id': 'test4',
+ 'nsp': 256,
+ 'portchain_id': '10f6a764-6963-4b8e-9ae4-a1e5e805915e',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b17abfa-7afb-4e83-8e15-ad21a6044bb7'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': 'a57a8160-a202-477b-aca1-e7c006bc93a2'
+ }],
+ 'id': '1409e7b8-ed6f-41ae-ba6b-8ef96bbb8da9'
+ }]
+ self.init_agent()
+ for port_id in self.port_mapping:
+ self.agent.sfc_treat_devices_added_updated(port_id)
+ self.assertItemsEqual(
+ self.added_flows, [{
+ 'priority': 10,
+ 'table': 0,
+ 'dl_type': 34887,
+ 'actions': 'resubmit(,5)'
+ }, {
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'actions': 'resubmit(,30)'
+ }, {
+ 'priority': 0,
+ 'table': 30,
+ 'actions': 'output:1'
+ }, {
+ 'priority': 10,
+ 'table': 30,
+ 'actions': 'resubmit(,31)',
+ 'in_port': 1
+ }, {
+ 'dl_type': 34887,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:68:3a,'
+ 'set_field:68->tun_id,output:[]'
+ ),
+ 'priority': 0,
+ 'mpls_label': 65790,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0',
+ 'table': 31,
+ 'nw_src': '0.0.0.0/0.0.0.0'
+ }, {
+ 'dl_type': 2048,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:2'
+ ),
+ 'priority': 10,
+ 'tp_dst': '0/0x0',
+ 'table': 0,
+ 'tp_src': '0/0x0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'in_port': 42
+ }, {
+ 'dl_type': 34887,
+ 'actions': 'pop_mpls:0x0800,output:6',
+ 'priority': 1,
+ 'mpls_label': 65791,
+ 'table': 5,
+ 'dl_dst': '00:01:02:03:05:07'
+ }, {
+ 'dl_type': 2048,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:2'
+ ),
+ 'priority': 10,
+ 'tp_dst': '0/0x0',
+ 'table': 0,
+ 'tp_src': '0/0x0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'in_port': 45
+ }, {
+ 'dl_type': 34887,
+ 'actions': 'pop_mpls:0x0800,output:44',
+ 'priority': 1,
+ 'mpls_label': 65791,
+ 'table': 5,
+ 'dl_dst': '00:01:02:03:06:10'
+ }, {
+ 'dl_type': 2048,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:2'
+ ),
+ 'priority': 10,
+ 'tp_dst': '0/0x0',
+ 'table': 0,
+ 'tp_src': '0/0x0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'in_port': 48
+ }, {
+ 'dl_type': 34887,
+ 'actions': 'pop_mpls:0x0800,output:47',
+ 'priority': 1,
+ 'mpls_label': 65791,
+ 'table': 5,
+ 'dl_dst': '00:01:02:03:06:13'
+ }, {
+ 'dl_type': 2048,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:2'
+ ),
+ 'priority': 10,
+ 'tp_dst': '0/0x0',
+ 'table': 0,
+ 'tp_src': '0/0x0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'in_port': 43
+ }, {
+ 'priority': 0,
+ 'table': 31,
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'actions': 'group:1'
+ }, {
+ 'dl_type': 34887,
+ 'actions': 'pop_mpls:0x0800,output:46',
+ 'priority': 1,
+ 'mpls_label': 65790,
+ 'table': 5,
+ 'dl_dst': '00:01:02:03:06:12'
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:58:ee,'
+ 'set_field:68->tun_id,output:[],'
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:fe:38,'
+ 'set_field:68->tun_id,output:[],'
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:32:30,'
+ 'set_field:68->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ }
+ }
+ )
+
+ def test_init_agent_portchain_multi_flow_classifiers_port_pairs(self):
+ self.port_mapping = {
+ '7b718ad7-c2cc-4de0-9ac0-d5f4b6e975aa': {
+ 'port_name': 'src_port1',
+ 'ofport': 6,
+ 'vif_mac': '00:01:02:03:05:07'
+ },
+ '9ac01d29-797a-4904-97a0-eecc7661b2ad': {
+ 'port_name': 'ingress',
+ 'ofport': 42,
+ 'vif_mac': '00:01:02:03:06:08'
+ },
+ '02ebda8f-44e5-41ee-8d80-ec47b3c2732e': {
+ 'port_name': 'egress',
+ 'ofport': 43,
+ 'vif_mac': '00:01:02:03:06:09'
+ },
+ '32971131-e44c-4aad-85f9-7d9f10d07393': {
+ 'port_name': 'src_port2',
+ 'ofport': 44,
+ 'vif_mac': '00:01:02:03:06:10'
+ },
+ 'b7c69625-9cde-48dd-8858-5d773b002e73': {
+ 'port_name': 'dst_port1',
+ 'ofport': 45,
+ 'vif_mac': '00:01:02:03:06:11'
+ },
+ '2b7e8e42-b35d-4d49-8397-62088efe144f': {
+ 'port_name': 'dst_port2',
+ 'ofport': 46,
+ 'vif_mac': '00:01:02:03:06:12'
+ }
+ }
+ self.node_flowrules = [{
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.6',
+ 'ingress': '9ac01d29-797a-4904-97a0-eecc7661b2ad',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:52:39'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 82,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:65:d7',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.4',
+ 'node_type': 'src_node',
+ 'egress': '7b718ad7-c2cc-4de0-9ac0-d5f4b6e975aa',
+ 'next_group_id': 1,
+ 'host_id': 'test3',
+ 'nsp': 256,
+ 'portchain_id': 'd92114e8-56df-4bd7-9cf2-fce5ac01c94f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b7e8e42-b35d-4d49-8397-62088efe144f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '7b718ad7-c2cc-4de0-9ac0-d5f4b6e975aa'
+ }],
+ 'id': u'44c469bf-6c48-4f8f-bb4f-de87b44b02b6'
+ }, {
+ 'nsi': 254,
+ 'ingress': '9ac01d29-797a-4904-97a0-eecc7661b2ad',
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.3',
+ 'ingress': 'b7c69625-9cde-48dd-8858-5d773b002e73',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:36:e9'
+ }, {
+ 'local_endpoint': '10.0.0.5',
+ 'ingress': '2b7e8e42-b35d-4d49-8397-62088efe144f',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:51:9a'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 82,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:52:39',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.6',
+ 'node_type': 'sf_node',
+ 'egress': '02ebda8f-44e5-41ee-8d80-ec47b3c2732e',
+ 'next_group_id': None,
+ 'host_id': 'test6',
+ 'nsp': 256,
+ 'portchain_id': 'd92114e8-56df-4bd7-9cf2-fce5ac01c94f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'b7c69625-9cde-48dd-8858-5d773b002e73'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '32971131-e44c-4aad-85f9-7d9f10d07393'
+ }, {
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b7e8e42-b35d-4d49-8397-62088efe144f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': '7b718ad7-c2cc-4de0-9ac0-d5f4b6e975aa'
+ }],
+ 'id': u'c065e0c3-a904-4bac-adf2-f038b717c9c2'
+ }, {
+ 'nsi': 255,
+ 'ingress': None,
+ 'next_hops': [{
+ 'local_endpoint': '10.0.0.6',
+ 'ingress': '9ac01d29-797a-4904-97a0-eecc7661b2ad',
+ 'weight': 1,
+ 'mac_address': '12:34:56:78:52:39'
+ }],
+ 'del_fcs': [],
+ 'segment_id': 82,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:41:cf',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.2',
+ 'node_type': 'src_node',
+ 'egress': '32971131-e44c-4aad-85f9-7d9f10d07393',
+ 'next_group_id': 1,
+ 'host_id': 'test1',
+ 'nsp': 256,
+ 'portchain_id': 'd92114e8-56df-4bd7-9cf2-fce5ac01c94f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'b7c69625-9cde-48dd-8858-5d773b002e73'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '32971131-e44c-4aad-85f9-7d9f10d07393')
+ }],
+ 'id': u'44c469bf-6c48-4f8f-bb4f-de87b44b02b6'
+ }, {
+ 'nsi': 253,
+ 'ingress': 'b7c69625-9cde-48dd-8858-5d773b002e73',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 82,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:36:e9',
+ 'network_type': 'gre',
+ 'local_endpoint': '10.0.0.3',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test2',
+ 'nsp': 256,
+ 'portchain_id': 'd92114e8-56df-4bd7-9cf2-fce5ac01c94f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ 'b7c69625-9cde-48dd-8858-5d773b002e73'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '32971131-e44c-4aad-85f9-7d9f10d07393')
+ }],
+ 'id': '4a61e567-4210-41d9-af82-e01b9da47230'
+ }, {
+ 'nsi': 253,
+ 'ingress': '2b7e8e42-b35d-4d49-8397-62088efe144f',
+ 'next_hops': None,
+ 'del_fcs': [],
+ 'segment_id': 82,
+ 'group_refcnt': 1,
+ 'mac_address': '12:34:56:78:51:9a',
+ 'network_type': 'gre',
+ 'local_endpoint': u'10.0.0.5',
+ 'node_type': 'dst_node',
+ 'egress': None,
+ 'next_group_id': None,
+ 'host_id': 'test4',
+ 'nsp': 256,
+ 'portchain_id': 'd92114e8-56df-4bd7-9cf2-fce5ac01c94f',
+ 'add_fcs': [{
+ 'source_port_range_min': None,
+ 'destination_ip_prefix': None,
+ 'protocol': None,
+ 'ethertype': 'IPv4',
+ 'l7_parameters': {},
+ 'source_port_range_max': None,
+ 'source_ip_prefix': None,
+ 'logical_destination_port': (
+ '2b7e8e42-b35d-4d49-8397-62088efe144f'),
+ 'destination_port_range_min': None,
+ 'destination_port_range_max': None,
+ 'logical_source_port': (
+ '7b718ad7-c2cc-4de0-9ac0-d5f4b6e975aa')
+ }],
+ 'id': '4a61e567-4210-41d9-af82-e01b9da47230'
+ }]
+ self.init_agent()
+ for port_id in self.port_mapping:
+ self.agent.sfc_treat_devices_added_updated(port_id)
+ self.assertItemsEqual(
+ self.added_flows, [{
+ 'actions': 'resubmit(,5)',
+ 'dl_type': 34887,
+ 'priority': 10,
+ 'table': 0
+ }, {
+ 'actions': 'resubmit(,30)',
+ 'dl_type': 34887,
+ 'priority': 10
+ }, {
+ 'actions': 'output:1',
+ 'priority': 0,
+ 'table': 30
+ }, {
+ 'actions': 'resubmit(,31)',
+ 'in_port': 1,
+ 'priority': 10,
+ 'table': 30
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 44,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'group:1',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 0,
+ 'table': 31
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:45',
+ 'dl_dst': '00:01:02:03:06:11',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:36:e9,'
+ 'set_field:82->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65790,'
+ 'set_mpls_ttl:254,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 43,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': (
+ 'mod_dl_dst:12:34:56:78:51:9a,'
+ 'set_field:82->tun_id,output:[]'
+ ),
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 0,
+ 'table': 31,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:42',
+ 'dl_dst': '00:01:02:03:06:08',
+ 'dl_type': 34887,
+ 'mpls_label': 65791,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': 'pop_mpls:0x0800,output:46',
+ 'dl_dst': '00:01:02:03:06:12',
+ 'dl_type': 34887,
+ 'mpls_label': 65790,
+ 'priority': 1,
+ 'table': 5
+ }, {
+ 'actions': (
+ 'push_mpls:0x8847,'
+ 'set_mpls_label:65791,'
+ 'set_mpls_ttl:255,output:2'
+ ),
+ 'dl_type': 2048,
+ 'in_port': 6,
+ 'nw_dst': '0.0.0.0/0.0.0.0',
+ 'nw_src': '0.0.0.0/0.0.0.0',
+ 'priority': 10,
+ 'table': 0,
+ 'tp_dst': '0/0x0',
+ 'tp_src': '0/0x0'
+ }]
+ )
+ self.assertEqual(
+ self.group_mapping, {
+ 1: {
+ 'buckets': (
+ 'bucket=weight=1,'
+ 'mod_dl_dst:12:34:56:78:52:39,'
+ 'set_field:82->tun_id,output:[]'
+ ),
+ 'group_id': 1,
+ 'type': 'select'
+ }
+ }
+ )
diff --git a/networking_sfc/tests/unit/services/sfc/common/__init__.py b/networking_sfc/tests/unit/services/sfc/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/common/__init__.py
diff --git a/networking_sfc/tests/unit/services/sfc/common/test_ovs_ext_lib.py b/networking_sfc/tests/unit/services/sfc/common/test_ovs_ext_lib.py
new file mode 100644
index 0000000..19e20cc
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/common/test_ovs_ext_lib.py
@@ -0,0 +1,93 @@
+# Copyright 2015 Futurewei. All rights reserved.
+#
+# 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 neutron.common import exceptions
+from neutron.tests import base
+
+from networking_sfc.services.sfc.common import ovs_ext_lib
+
+
+class GetPortMaskTestCase(base.BaseTestCase):
+ def setUp(self):
+ super(GetPortMaskTestCase, self).setUp()
+
+ def tearDown(self):
+ super(GetPortMaskTestCase, self).tearDown()
+
+ def test_single_port(self):
+ masks = ovs_ext_lib.get_port_mask(100, 100)
+ self.assertEqual(masks, ['0x64/0xffff'])
+
+ def test_invalid_min_port(self):
+ self.assertRaises(
+ exceptions.InvalidInput,
+ ovs_ext_lib.get_port_mask,
+ 0, 100
+ )
+
+ def test_invalid_max_port(self):
+ self.assertRaises(
+ exceptions.InvalidInput,
+ ovs_ext_lib.get_port_mask,
+ 100, 65536
+ )
+
+ def test_invalid_port_range(self):
+ self.assertRaises(
+ exceptions.InvalidInput,
+ ovs_ext_lib.get_port_mask,
+ 100, 99
+ )
+
+ def test_one_port_mask(self):
+ masks = ovs_ext_lib.get_port_mask(100, 101)
+ self.assertEqual(masks, ['0x64/0xfffe'])
+ masks = ovs_ext_lib.get_port_mask(100, 103)
+ self.assertEqual(masks, ['0x64/0xfffc'])
+ masks = ovs_ext_lib.get_port_mask(32768, 65535)
+ self.assertEqual(masks, ['0x8000/0x8000'])
+
+ def test_multi_port_masks(self):
+ masks = ovs_ext_lib.get_port_mask(101, 102)
+ self.assertEqual(masks, ['0x65/0xffff', '0x66/0xffff'])
+ masks = ovs_ext_lib.get_port_mask(101, 104)
+ self.assertEqual(
+ masks,
+ ['0x65/0xffff', '0x66/0xfffe', '0x68/0xffff']
+ )
+ masks = ovs_ext_lib.get_port_mask(1, 65535)
+ self.assertEqual(
+ masks, [
+ '0x1/0xffff',
+ '0x2/0xfffe',
+ '0x4/0xfffc',
+ '0x8/0xfff8',
+ '0x10/0xfff0',
+ '0x20/0xffe0',
+ '0x40/0xffc0',
+ '0x80/0xff80',
+ '0x100/0xff00',
+ '0x200/0xfe00',
+ '0x400/0xfc00',
+ '0x800/0xf800',
+ '0x1000/0xf000',
+ '0x2000/0xe000',
+ '0x4000/0xc000',
+ '0x8000/0x8000'
+ ]
+ )
+ masks = ovs_ext_lib.get_port_mask(32767, 65535)
+ self.assertEqual(
+ masks, ['0x7fff/0xffff', '0x8000/0x8000']
+ )
diff --git a/networking_sfc/tests/unit/services/sfc/drivers/__init__.py b/networking_sfc/tests/unit/services/sfc/drivers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/drivers/__init__.py
diff --git a/networking_sfc/tests/unit/services/sfc/drivers/ovs/__init__.py b/networking_sfc/tests/unit/services/sfc/drivers/ovs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/drivers/ovs/__init__.py
diff --git a/networking_sfc/tests/unit/services/sfc/test_driver_manager.py b/networking_sfc/tests/unit/services/sfc/test_driver_manager.py
new file mode 100644
index 0000000..c247bf2
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/test_driver_manager.py
@@ -0,0 +1,325 @@
+# Copyright 2015 Futurewei. All rights reserved.
+#
+# 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.
+
+import contextlib
+import mock
+import pkg_resources
+import six
+import stevedore
+
+from oslo_config import cfg
+
+from neutron.tests import base
+
+from networking_sfc.services.sfc.common import config as sfc_config
+from networking_sfc.services.sfc.common import exceptions as sfc_exc
+from networking_sfc.services.sfc import driver_manager as sfc_driver
+
+
+class DriverManagerTestCase(base.BaseTestCase):
+ def setUp(self):
+ super(DriverManagerTestCase, self).setUp()
+
+ @contextlib.contextmanager
+ def driver_manager_context(self, drivers):
+ cfg.CONF.register_opts(sfc_config.SFC_DRIVER_OPTS, 'sfc')
+ backup_driver_names = cfg.CONF.sfc.drivers
+ driver_names = [
+ driver_name for driver_name in six.iterkeys(drivers)
+ ]
+ cfg.CONF.set_override('drivers', driver_names, 'sfc')
+ iter_entry_points = pkg_resources.iter_entry_points
+ find_entry_points = stevedore.ExtensionManager._find_entry_points
+ pkg_resources.iter_entry_points = mock.Mock()
+ stevedore.ExtensionManager._find_entry_points = mock.Mock()
+ driver_entry_points = []
+ for driver_name in driver_names:
+ driver_class = mock.Mock()
+ ep = mock.Mock()
+ ep.name = driver_name
+ ep.resolve.return_value = driver_class
+ driver_class.return_value = drivers[driver_name]
+ drivers[driver_name].native_bulk_support = True
+ driver_entry_points.append(ep)
+ pkg_resources.iter_entry_points.return_value = driver_entry_points
+ stevedore.ExtensionManager._find_entry_points.return_value = (
+ driver_entry_points
+ )
+ yield sfc_driver.SfcDriverManager()
+ cfg.CONF.set_override('drivers', backup_driver_names, 'sfc')
+ pkg_resources.iter_entry_points = iter_entry_points
+ stevedore.ExtensionManager._find_entry_points = find_entry_points
+
+ def test_initialize_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ manager.initialize()
+ mock_driver1.initialize.assert_called_once_with()
+ mock_driver2.initialize.assert_called_once_with()
+
+ def test_create_port_chain_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.create_port_chain(mocked_context)
+ mock_driver1.create_port_chain.assert_called_once_with(
+ mocked_context)
+ mock_driver2.create_port_chain.assert_called_once_with(
+ mocked_context)
+
+ def test_create_port_chain_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.create_port_chain = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.create_port_chain, mocked_context
+ )
+
+ def test_update_port_chain_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.update_port_chain(mocked_context)
+ mock_driver1.update_port_chain.assert_called_once_with(
+ mocked_context)
+ mock_driver2.update_port_chain.assert_called_once_with(
+ mocked_context)
+
+ def test_update_port_chain_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.update_port_chain = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.update_port_chain, mocked_context
+ )
+
+ def test_delete_port_chain_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.delete_port_chain(mocked_context)
+ mock_driver1.delete_port_chain.assert_called_once_with(
+ mocked_context)
+ mock_driver2.delete_port_chain.assert_called_once_with(
+ mocked_context)
+
+ def test_delete_port_chain_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.delete_port_chain = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.delete_port_chain, mocked_context
+ )
+
+ def test_create_port_pair_group_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.create_port_pair_group(mocked_context)
+ mock_driver1.create_port_pair_group.assert_called_once_with(
+ mocked_context)
+ mock_driver2.create_port_pair_group.assert_called_once_with(
+ mocked_context)
+
+ def test_create_port_pair_group_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.create_port_pair_group = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.create_port_pair_group, mocked_context
+ )
+
+ def test_update_port_pair_group_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.update_port_pair_group(mocked_context)
+ mock_driver1.update_port_pair_group.assert_called_once_with(
+ mocked_context)
+ mock_driver2.update_port_pair_group.assert_called_once_with(
+ mocked_context)
+
+ def test_update_port_pair_group_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.update_port_pair_group = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.update_port_pair_group, mocked_context
+ )
+
+ def test_delete_port_pair_group_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.delete_port_pair_group(mocked_context)
+ mock_driver1.delete_port_pair_group.assert_called_once_with(
+ mocked_context)
+ mock_driver2.delete_port_pair_group.assert_called_once_with(
+ mocked_context)
+
+ def test_delete_port_pair_group_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.delete_port_pair_group = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.delete_port_pair_group, mocked_context
+ )
+
+ def test_create_port_pair_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.create_port_pair(mocked_context)
+ mock_driver1.create_port_pair.assert_called_once_with(
+ mocked_context)
+ mock_driver2.create_port_pair.assert_called_once_with(
+ mocked_context)
+
+ def test_create_port_pair_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.create_port_pair = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.create_port_pair, mocked_context
+ )
+
+ def test_update_port_pair_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.update_port_pair(mocked_context)
+ mock_driver1.update_port_pair.assert_called_once_with(
+ mocked_context)
+ mock_driver2.update_port_pair.assert_called_once_with(
+ mocked_context)
+
+ def test_update_port_pair_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.update_port_pair = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.update_port_pair, mocked_context
+ )
+
+ def test_delete_port_pair_called(self):
+ mock_driver1 = mock.Mock()
+ mock_driver2 = mock.Mock()
+ with self.driver_manager_context({
+ 'dummy1': mock_driver1,
+ 'dummy2': mock_driver2
+ }) as manager:
+ mocked_context = mock.Mock()
+ manager.delete_port_pair(mocked_context)
+ mock_driver1.delete_port_pair.assert_called_once_with(
+ mocked_context)
+ mock_driver2.delete_port_pair.assert_called_once_with(
+ mocked_context)
+
+ def test_delete_port_pair_exception(self):
+ mock_driver = mock.Mock()
+ mock_driver.delete_port_pair = mock.Mock(
+ side_effect=sfc_exc.SfcException
+ )
+ with self.driver_manager_context({
+ 'dummy': mock_driver,
+ }) as manager:
+ mocked_context = mock.Mock()
+ self.assertRaises(
+ sfc_exc.SfcDriverError,
+ manager.delete_port_pair, mocked_context
+ )
diff --git a/networking_sfc/tests/unit/services/sfc/test_plugin.py b/networking_sfc/tests/unit/services/sfc/test_plugin.py
new file mode 100644
index 0000000..d265838
--- /dev/null
+++ b/networking_sfc/tests/unit/services/sfc/test_plugin.py
@@ -0,0 +1,468 @@
+# Copyright 2015 Futurewei. All rights reserved.
+#
+# 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.
+
+import copy
+import mock
+
+from networking_sfc.services.sfc.common import context as sfc_ctx
+from networking_sfc.services.sfc.common import exceptions as sfc_exc
+from networking_sfc.tests.unit.db import test_sfc_db
+
+SFC_PLUGIN_KLASS = (
+ "networking_sfc.services.sfc.plugin.SfcPlugin"
+)
+
+
+class SfcPluginTestCase(test_sfc_db.SfcDbPluginTestCase):
+ def setUp(self, core_plugin=None, sfc_plugin=None, ext_mgr=None):
+ if not sfc_plugin:
+ sfc_plugin = SFC_PLUGIN_KLASS
+ self.driver_manager_p = mock.patch(
+ 'networking_sfc.services.sfc.driver_manager.SfcDriverManager'
+ )
+ self.fake_driver_manager_class = self.driver_manager_p.start()
+ self.fake_driver_manager = mock.Mock()
+ self.fake_driver_manager_class.return_value = self.fake_driver_manager
+ self.plugin_context = None
+ super(SfcPluginTestCase, self).setUp(
+ core_plugin=core_plugin, sfc_plugin=sfc_plugin,
+ ext_mgr=ext_mgr
+ )
+
+ def _record_context(self, plugin_context):
+ self.plugin_context = plugin_context
+
+ def test_create_port_chain_driver_manager_called(self):
+ self.fake_driver_manager.create_port_chain = mock.Mock(
+ side_effect=self._record_context)
+ with self.port_pair_group(port_pair_group={}) as pg:
+ with self.port_chain(port_chain={
+ 'port_pair_groups': [pg['port_pair_group']['id']]
+ }) as pc:
+ driver_manager = self.fake_driver_manager
+ driver_manager.create_port_chain.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortChainContext
+ )
+ self.assertIn('port_chain', pc)
+ self.assertEqual(
+ self.plugin_context.current, pc['port_chain'])
+
+ def test_create_port_chain_driver_manager_exception(self):
+ self.fake_driver_manager.create_port_chain = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='create_port_chain'
+ )
+ )
+ with self.port_pair_group(port_pair_group={}) as pg:
+ self._create_port_chain(
+ self.fmt,
+ {'port_pair_groups': [pg['port_pair_group']['id']]},
+ expected_res_status=500)
+ self._test_list_resources('port_chain', [])
+ self.fake_driver_manager.delete_port_chain.assert_called_once_with(
+ mock.ANY
+ )
+
+ def test_update_port_chain_driver_manager_called(self):
+ self.fake_driver_manager.update_port_chain = mock.Mock(
+ side_effect=self._record_context)
+ with self.port_pair_group(port_pair_group={}) as pg:
+ with self.port_chain(port_chain={
+ 'name': 'test1',
+ 'port_pair_groups': [pg['port_pair_group']['id']]
+ }) as pc:
+ req = self.new_update_request(
+ 'port_chains', {'port_chain': {'name': 'test2'}},
+ pc['port_chain']['id']
+ )
+ res = self.deserialize(
+ self.fmt,
+ req.get_response(self.ext_api)
+ )
+ driver_manager = self.fake_driver_manager
+ driver_manager.update_port_chain.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortChainContext
+ )
+ self.assertIn('port_chain', pc)
+ self.assertIn('port_chain', res)
+ self.assertEqual(
+ self.plugin_context.current, res['port_chain'])
+ self.assertEqual(
+ self.plugin_context.original, pc['port_chain'])
+
+ def test_update_port_chain_driver_manager_exception(self):
+ self.fake_driver_manager.update_port_chain = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='update_port_chain'
+ )
+ )
+ with self.port_pair_group(port_pair_group={}) as pg:
+ with self.port_chain(port_chain={
+ 'name': 'test1',
+ 'port_pair_groups': [pg['port_pair_group']['id']]
+ }) as pc:
+ self.assertIn('port_chain', pc)
+ original_port_chain = pc['port_chain']
+ req = self.new_update_request(
+ 'port_chains', {'port_chain': {'name': 'test2'}},
+ pc['port_chain']['id']
+ )
+ updated_port_chain = copy.copy(original_port_chain)
+ updated_port_chain['name'] = 'test2'
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 500)
+ res = self._list('port_chains')
+ self.assertIn('port_chains', res)
+ self.assertItemsEqual(
+ res['port_chains'], [updated_port_chain])
+
+ def test_delete_port_chain_manager_called(self):
+ self.fake_driver_manager.delete_port_chain = mock.Mock(
+ side_effect=self._record_context)
+ with self.port_pair_group(port_pair_group={}) as pg:
+ with self.port_chain(port_chain={
+ 'name': 'test1',
+ 'port_pair_groups': [pg['port_pair_group']['id']]
+ }, do_delete=False) as pc:
+ req = self.new_delete_request(
+ 'port_chains', pc['port_chain']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 204)
+ driver_manager = self.fake_driver_manager
+ driver_manager.delete_port_chain.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortChainContext
+ )
+ self.assertIn('port_chain', pc)
+ self.assertEqual(self.plugin_context.current, pc['port_chain'])
+
+ def test_delete_port_chain_driver_manager_exception(self):
+ self.fake_driver_manager.delete_port_chain = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='delete_port_chain'
+ )
+ )
+ with self.port_pair_group(port_pair_group={
+ }, do_delete=False) as pg:
+ with self.port_chain(port_chain={
+ 'name': 'test1',
+ 'port_pair_groups': [pg['port_pair_group']['id']]
+ }, do_delete=False) as pc:
+ req = self.new_delete_request(
+ 'port_chains', pc['port_chain']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 500)
+ self._test_list_resources('port_chain', [pc])
+
+ def test_create_port_pair_group_driver_manager_called(self):
+ self.fake_driver_manager.create_port_pair_group = mock.Mock(
+ side_effect=self._record_context)
+ with self.port_pair_group(port_pair_group={}) as pc:
+ fake_driver_manager = self.fake_driver_manager
+ fake_driver_manager.create_port_pair_group.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortPairGroupContext
+ )
+ self.assertIn('port_pair_group', pc)
+ self.assertEqual(
+ self.plugin_context.current, pc['port_pair_group'])
+
+ def test_create_port_pair_group_driver_manager_exception(self):
+ self.fake_driver_manager.create_port_pair_group = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='create_port_pair_group'
+ )
+ )
+ self._create_port_pair_group(self.fmt, {}, expected_res_status=500)
+ self._test_list_resources('port_pair_group', [])
+ driver_manager = self.fake_driver_manager
+ driver_manager.delete_port_pair_group.assert_called_once_with(
+ mock.ANY
+ )
+
+ def test_update_port_pair_group_driver_manager_called(self):
+ self.fake_driver_manager.update_port_pair_group = mock.Mock(
+ side_effect=self._record_context)
+ with self.port_pair_group(port_pair_group={
+ 'name': 'test1'
+ }) as pc:
+ req = self.new_update_request(
+ 'port_pair_groups', {'port_pair_group': {'name': 'test2'}},
+ pc['port_pair_group']['id']
+ )
+ res = self.deserialize(
+ self.fmt,
+ req.get_response(self.ext_api)
+ )
+ driver_manager = self.fake_driver_manager
+ driver_manager.update_port_pair_group.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortPairGroupContext
+ )
+ self.assertIn('port_pair_group', pc)
+ self.assertIn('port_pair_group', res)
+ self.assertEqual(
+ self.plugin_context.current, res['port_pair_group'])
+ self.assertEqual(
+ self.plugin_context.original, pc['port_pair_group'])
+
+ def test_update_port_pair_group_driver_manager_exception(self):
+ self.fake_driver_manager.update_port_pair_group = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='update_port_pair_group'
+ )
+ )
+ with self.port_pair_group(port_pair_group={
+ 'name': 'test1'
+ }) as pc:
+ self.assertIn('port_pair_group', pc)
+ original_port_pair_group = pc['port_pair_group']
+ req = self.new_update_request(
+ 'port_pair_groups', {'port_pair_group': {'name': 'test2'}},
+ pc['port_pair_group']['id']
+ )
+ updated_port_pair_group = copy.copy(original_port_pair_group)
+ updated_port_pair_group['name'] = 'test2'
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 500)
+ res = self._list('port_pair_groups')
+ self.assertIn('port_pair_groups', res)
+ self.assertItemsEqual(
+ res['port_pair_groups'], [updated_port_pair_group])
+
+ def test_delete_port_pair_group_manager_called(self):
+ self.fake_driver_manager.delete_port_pair_group = mock.Mock(
+ side_effect=self._record_context)
+ with self.port_pair_group(port_pair_group={
+ 'name': 'test1'
+ }, do_delete=False) as pc:
+ req = self.new_delete_request(
+ 'port_pair_groups', pc['port_pair_group']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 204)
+ driver_manager = self.fake_driver_manager
+ driver_manager.delete_port_pair_group.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortPairGroupContext
+ )
+ self.assertIn('port_pair_group', pc)
+ self.assertEqual(
+ self.plugin_context.current, pc['port_pair_group'])
+
+ def test_delete_port_pair_group_driver_manager_exception(self):
+ self.fake_driver_manager.delete_port_pair_group = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='delete_port_pair_group'
+ )
+ )
+ with self.port_pair_group(port_pair_group={
+ 'name': 'test1'
+ }, do_delete=False) as pc:
+ req = self.new_delete_request(
+ 'port_pair_groups', pc['port_pair_group']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 500)
+ self._test_list_resources('port_pair_group', [pc])
+
+ def test_create_port_pair_driver_manager_called(self):
+ self.fake_driver_manager.create_port_pair = mock.Mock(
+ side_effect=self._record_context)
+ with self.port(
+ name='port1',
+ device_id='default'
+ ) as src_port, self.port(
+ name='port2',
+ device_id='default'
+ ) as dst_port:
+ with self.port_pair(port_pair={
+ 'ingress': src_port['port']['id'],
+ 'egress': dst_port['port']['id']
+ }) as pc:
+ driver_manager = self.fake_driver_manager
+ driver_manager.create_port_pair.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortPairContext
+ )
+ self.assertIn('port_pair', pc)
+ self.assertEqual(self.plugin_context.current, pc['port_pair'])
+
+ def test_create_port_pair_driver_manager_exception(self):
+ self.fake_driver_manager.create_port_pair = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='create_port_pair'
+ )
+ )
+ with self.port(
+ name='port1',
+ device_id='default'
+ ) as src_port, self.port(
+ name='port2',
+ device_id='default'
+ ) as dst_port:
+ self._create_port_pair(
+ self.fmt,
+ {
+ 'ingress': src_port['port']['id'],
+ 'egress': dst_port['port']['id']
+ },
+ expected_res_status=500)
+ self._test_list_resources('port_pair', [])
+ driver_manager = self.fake_driver_manager
+ driver_manager.delete_port_pair.assert_called_once_with(
+ mock.ANY
+ )
+
+ def test_update_port_pair_driver_manager_called(self):
+ self.fake_driver_manager.update_port_pair = mock.Mock(
+ side_effect=self._record_context)
+ with self.port(
+ name='port1',
+ device_id='default'
+ ) as src_port, self.port(
+ name='port2',
+ device_id='default'
+ ) as dst_port:
+ with self.port_pair(port_pair={
+ 'name': 'test1',
+ 'ingress': src_port['port']['id'],
+ 'egress': dst_port['port']['id']
+ }) as pc:
+ req = self.new_update_request(
+ 'port_pairs', {'port_pair': {'name': 'test2'}},
+ pc['port_pair']['id']
+ )
+ res = self.deserialize(
+ self.fmt,
+ req.get_response(self.ext_api)
+ )
+ driver_manager = self.fake_driver_manager
+ driver_manager.update_port_pair.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortPairContext
+ )
+ self.assertIn('port_pair', pc)
+ self.assertIn('port_pair', res)
+ self.assertEqual(
+ self.plugin_context.current, res['port_pair'])
+ self.assertEqual(
+ self.plugin_context.original, pc['port_pair'])
+
+ def test_update_port_pair_driver_manager_exception(self):
+ self.fake_driver_manager.update_port_pair = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='update_port_pair'
+ )
+ )
+ with self.port(
+ name='port1',
+ device_id='default'
+ ) as src_port, self.port(
+ name='port2',
+ device_id='default'
+ ) as dst_port:
+ with self.port_pair(port_pair={
+ 'name': 'test1',
+ 'ingress': src_port['port']['id'],
+ 'egress': dst_port['port']['id']
+ }) as pc:
+ self.assertIn('port_pair', pc)
+ original_port_pair = pc['port_pair']
+ req = self.new_update_request(
+ 'port_pairs', {'port_pair': {'name': 'test2'}},
+ pc['port_pair']['id']
+ )
+ updated_port_pair = copy.copy(original_port_pair)
+ updated_port_pair['name'] = 'test2'
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 500)
+ res = self._list('port_pairs')
+ self.assertIn('port_pairs', res)
+ self.assertItemsEqual(res['port_pairs'], [updated_port_pair])
+
+ def test_delete_port_pair_manager_called(self):
+ self.fake_driver_manager.delete_port_pair = mock.Mock(
+ side_effect=self._record_context)
+ with self.port(
+ name='port1',
+ device_id='default'
+ ) as src_port, self.port(
+ name='port2',
+ device_id='default'
+ ) as dst_port:
+ with self.port_pair(port_pair={
+ 'name': 'test1',
+ 'ingress': src_port['port']['id'],
+ 'egress': dst_port['port']['id']
+ }, do_delete=False) as pc:
+ req = self.new_delete_request(
+ 'port_pairs', pc['port_pair']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 204)
+ fake_driver_manager = self.fake_driver_manager
+ fake_driver_manager.delete_port_pair.assert_called_once_with(
+ mock.ANY
+ )
+ self.assertIsInstance(
+ self.plugin_context, sfc_ctx.PortPairContext
+ )
+ self.assertIn('port_pair', pc)
+ self.assertEqual(self.plugin_context.current, pc['port_pair'])
+
+ def test_delete_port_pair_driver_manager_exception(self):
+ self.fake_driver_manager.delete_port_pair = mock.Mock(
+ side_effect=sfc_exc.SfcDriverError(
+ method='delete_port_pair'
+ )
+ )
+ with self.port(
+ name='port1',
+ device_id='default'
+ ) as src_port, self.port(
+ name='port2',
+ device_id='default'
+ ) as dst_port:
+ with self.port_pair(port_pair={
+ 'name': 'test1',
+ 'ingress': src_port['port']['id'],
+ 'egress': dst_port['port']['id']
+ }, do_delete=False) as pc:
+ req = self.new_delete_request(
+ 'port_pairs', pc['port_pair']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 500)
+ self._test_list_resources('port_pair', [pc])