summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Koderer <marc@koderer.com>2016-04-14 11:40:56 +0200
committerBen Swartzlander <ben@swartzlander.org>2016-09-01 20:58:18 +0000
commit8328ebde247a844d79c4a94aa67fcfd7665b3c61 (patch)
tree02aacf0ff6fde28035b213b14f6f30d2f1c9fd47
parent345b8021ec0f61f96794bc8937028364731e557c (diff)
Add multi-segment support3.0.0.0b3
Neutron ML2 mechanisms allows multiple network segments. A net-show call with a multi-segment setup won't return a single network-type or segmentation id. Instead it returns a list of it with a certain hierarchy. Co-Authored-By: Daniel Gonzalez <daniel@gonzalez-nothnagel.de> Change-Id: I3570752920d897c11cacb9e4a0b0d012ae2ce13a Partially-Implements: bp manila-hpb-support
Notes
Notes (review): Code-Review+2: Tom Barron <tpb@dyncloud.net> Code-Review+2: xing-yang <xing.yang@emc.com> Code-Review+1: Goutham Pacha Ravi <gouthampravi@gmail.com> Code-Review+2: Ben Swartzlander <ben@swartzlander.org> Workflow+1: Ben Swartzlander <ben@swartzlander.org> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Thu, 01 Sep 2016 22:47:17 +0000 Reviewed-on: https://review.openstack.org/277731 Project: openstack/manila Branch: refs/heads/master
-rw-r--r--manila/network/neutron/neutron_network_plugin.py88
-rw-r--r--manila/tests/network/neutron/test_neutron_plugin.py232
-rw-r--r--releasenotes/notes/multi-segment-support-fa171a8e3201d54e.yaml3
3 files changed, 311 insertions, 12 deletions
diff --git a/manila/network/neutron/neutron_network_plugin.py b/manila/network/neutron/neutron_network_plugin.py
index 32a8b07..86566be 100644
--- a/manila/network/neutron/neutron_network_plugin.py
+++ b/manila/network/neutron/neutron_network_plugin.py
@@ -29,6 +29,16 @@ from manila import utils
29 29
30LOG = log.getLogger(__name__) 30LOG = log.getLogger(__name__)
31 31
32neutron_network_plugin_opts = [
33 cfg.StrOpt(
34 'neutron_physical_net_name',
35 help="The name of the physical network to determine which net segment "
36 "is used. This opt is optional and will only be used for "
37 "networks configured with multiple segments.",
38 default=None,
39 deprecated_group='DEFAULT'),
40]
41
32neutron_single_network_plugin_opts = [ 42neutron_single_network_plugin_opts = [
33 cfg.StrOpt( 43 cfg.StrOpt(
34 'neutron_net_id', 44 'neutron_net_id',
@@ -95,6 +105,9 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
95 self._neutron_api_args = args 105 self._neutron_api_args = args
96 self._neutron_api_kwargs = kwargs 106 self._neutron_api_kwargs = kwargs
97 self._label = kwargs.pop('label', 'user') 107 self._label = kwargs.pop('label', 'user')
108 CONF.register_opts(
109 neutron_network_plugin_opts,
110 group=self.neutron_api.config_group_name)
98 111
99 @property 112 @property
100 def label(self): 113 def label(self):
@@ -108,6 +121,10 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
108 **self._neutron_api_kwargs) 121 **self._neutron_api_kwargs)
109 return self._neutron_api 122 return self._neutron_api
110 123
124 def _store_neutron_net_info(self, context, share_network):
125 self._save_neutron_network_data(context, share_network)
126 self._save_neutron_subnet_data(context, share_network)
127
111 def allocate_network(self, context, share_server, share_network=None, 128 def allocate_network(self, context, share_server, share_network=None,
112 **kwargs): 129 **kwargs):
113 """Allocate network resources using given network information. 130 """Allocate network resources using given network information.
@@ -128,8 +145,7 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
128 raise exception.NetworkBadConfigurationException(reason=msg) 145 raise exception.NetworkBadConfigurationException(reason=msg)
129 146
130 self._verify_share_network(share_server['id'], share_network) 147 self._verify_share_network(share_server['id'], share_network)
131 self._save_neutron_network_data(context, share_network) 148 self._store_neutron_net_info(context, share_network)
132 self._save_neutron_subnet_data(context, share_network)
133 149
134 allocation_count = kwargs.get('count', 1) 150 allocation_count = kwargs.get('count', 1)
135 device_owner = kwargs.get('device_owner', 'share') 151 device_owner = kwargs.get('device_owner', 'share')
@@ -181,8 +197,8 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
181 'mac_address': port['mac_address'], 197 'mac_address': port['mac_address'],
182 'status': constants.STATUS_ACTIVE, 198 'status': constants.STATUS_ACTIVE,
183 'label': self.label, 199 'label': self.label,
184 'network_type': share_network['network_type'], 200 'network_type': share_network.get('network_type'),
185 'segmentation_id': share_network['segmentation_id'], 201 'segmentation_id': share_network.get('segmentation_id'),
186 'ip_version': share_network['ip_version'], 202 'ip_version': share_network['ip_version'],
187 'cidr': share_network['cidr'], 203 'cidr': share_network['cidr'],
188 'mtu': share_network['mtu'], 204 'mtu': share_network['mtu'],
@@ -203,13 +219,43 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
203 extensions = self.neutron_api.list_extensions() 219 extensions = self.neutron_api.list_extensions()
204 return neutron_constants.PROVIDER_NW_EXT in extensions 220 return neutron_constants.PROVIDER_NW_EXT in extensions
205 221
222 def _is_neutron_multi_segment(self, share_network, net_info=None):
223 if net_info is None:
224 net_info = self.neutron_api.get_network(
225 share_network['neutron_net_id'])
226 return 'segments' in net_info
227
206 def _save_neutron_network_data(self, context, share_network): 228 def _save_neutron_network_data(self, context, share_network):
207 net_info = self.neutron_api.get_network( 229 net_info = self.neutron_api.get_network(
208 share_network['neutron_net_id']) 230 share_network['neutron_net_id'])
231 segmentation_id = None
232 network_type = None
233
234 if self._is_neutron_multi_segment(share_network, net_info):
235 # we have a multi segment network and need to identify the
236 # lowest segment used for binding
237 phy_nets = []
238 phy = self.neutron_api.configuration.neutron_physical_net_name
239 if not phy:
240 msg = "Cannot identify segment used for binding. Please add "
241 "neutron_physical_net_name in configuration."
242 raise exception.NetworkBadConfigurationException(reason=msg)
243 for segment in net_info['segments']:
244 phy_nets.append(segment['provider:physical_network'])
245 if segment['provider:physical_network'] == phy:
246 segmentation_id = segment['provider:segmentation_id']
247 network_type = segment['provider:network_type']
248 if not (segmentation_id and network_type):
249 msg = ("No matching neutron_physical_net_name found for %s "
250 "(found: %s)." % (phy, phy_nets))
251 raise exception.NetworkBadConfigurationException(reason=msg)
252 else:
253 network_type = net_info['provider:network_type']
254 segmentation_id = net_info['provider:segmentation_id']
209 255
210 provider_nw_dict = { 256 provider_nw_dict = {
211 'network_type': net_info['provider:network_type'], 257 'network_type': network_type,
212 'segmentation_id': net_info['provider:segmentation_id'], 258 'segmentation_id': segmentation_id,
213 'mtu': net_info['mtu'], 259 'mtu': net_info['mtu'],
214 } 260 }
215 share_network.update(provider_nw_dict) 261 share_network.update(provider_nw_dict)
@@ -377,6 +423,23 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
377 "local_link_information": local_links} 423 "local_link_information": local_links}
378 return arguments 424 return arguments
379 425
426 def _store_neutron_net_info(self, context, share_network):
427 """Store the Neutron network info.
428
429 In case of dynamic multi segments the segment is determined while
430 binding the port. Therefore this method will return for multi segments
431 network without storing network information.
432
433 Instead, multi segments network will wait until ports are bound and
434 then store network information (see allocate_network()).
435 """
436 if self._is_neutron_multi_segment(share_network):
437 # In case of dynamic multi segment the segment is determined while
438 # binding the port
439 return
440 super(NeutronBindNetworkPlugin, self)._store_neutron_net_info(
441 context, share_network)
442
380 def allocate_network(self, context, share_server, share_network=None, 443 def allocate_network(self, context, share_server, share_network=None,
381 **kwargs): 444 **kwargs):
382 ports = super(NeutronBindNetworkPlugin, self).allocate_network( 445 ports = super(NeutronBindNetworkPlugin, self).allocate_network(
@@ -389,6 +452,19 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
389 # order to update the ports with the correct binding. 452 # order to update the ports with the correct binding.
390 if self.config.neutron_vnic_type != 'normal': 453 if self.config.neutron_vnic_type != 'normal':
391 self._wait_for_ports_bind(ports, share_server) 454 self._wait_for_ports_bind(ports, share_server)
455 if self._is_neutron_multi_segment(share_network):
456 # update segment information after port bind
457 super(NeutronBindNetworkPlugin, self)._store_neutron_net_info(
458 context, share_network)
459 for num, port in enumerate(ports):
460 port_info = {
461 'network_type': share_network['network_type'],
462 'segmentation_id': share_network['segmentation_id'],
463 'cidr': share_network['cidr'],
464 'ip_version': share_network['ip_version'],
465 }
466 ports[num] = self.db.network_allocation_update(
467 context, port['id'], port_info)
392 return ports 468 return ports
393 469
394 470
diff --git a/manila/tests/network/neutron/test_neutron_plugin.py b/manila/tests/network/neutron/test_neutron_plugin.py
index c2293da..55682b6 100644
--- a/manila/tests/network/neutron/test_neutron_plugin.py
+++ b/manila/tests/network/neutron/test_neutron_plugin.py
@@ -73,8 +73,8 @@ fake_neutron_network = {
73 73
74fake_share_network = { 74fake_share_network = {
75 'id': 'fake nw info id', 75 'id': 'fake nw info id',
76 'neutron_subnet_id': 'fake subnet id', 76 'neutron_subnet_id': fake_neutron_network['subnets'][0],
77 'neutron_net_id': 'fake net id', 77 'neutron_net_id': fake_neutron_network['id'],
78 'project_id': 'fake project id', 78 'project_id': 'fake project id',
79 'status': 'test_subnet_status', 79 'status': 'test_subnet_status',
80 'name': 'fake name', 80 'name': 'fake name',
@@ -111,6 +111,77 @@ fake_network_allocation = {
111 'mtu': 1509, 111 'mtu': 1509,
112} 112}
113 113
114fake_nw_info = {
115 'segments': [
116 {
117 'provider:network_type': 'vlan',
118 'provider:physical_network': 'net1',
119 'provider:segmentation_id': 3926,
120 },
121 {
122 'provider:network_type': 'vxlan',
123 'provider:physical_network': None,
124 'provider:segmentation_id': 2000,
125 },
126 ],
127 'mtu': 1509,
128}
129
130fake_neutron_network_multi = {
131 'admin_state_up': True,
132 'availability_zone_hints': [],
133 'availability_zones': ['nova'],
134 'description': '',
135 'id': 'fake net id',
136 'ipv4_address_scope': None,
137 'ipv6_address_scope': None,
138 'name': 'test_neutron_network',
139 'port_security_enabled': True,
140 'router:external': False,
141 'shared': False,
142 'status': 'ACTIVE',
143 'subnets': ['fake subnet id',
144 'fake subnet id 2'],
145 'segments': fake_nw_info['segments'],
146 'mtu': fake_nw_info['mtu'],
147}
148
149fake_share_network_multi = {
150 'id': 'fake nw info id',
151 'neutron_subnet_id': fake_neutron_network_multi['subnets'][0],
152 'neutron_net_id': fake_neutron_network_multi['id'],
153 'project_id': 'fake project id',
154 'status': 'test_subnet_status',
155 'name': 'fake name',
156 'description': 'fake description',
157 'security_services': [],
158 'ip_version': 4,
159 'cidr': 'fake_cidr',
160 'gateway': 'fake_gateway',
161 'mtu': fake_neutron_network_multi['mtu'],
162}
163
164fake_network_allocation_multi = {
165 'id': fake_neutron_port['id'],
166 'share_server_id': fake_share_server['id'],
167 'ip_address': fake_neutron_port['fixed_ips'][0]['ip_address'],
168 'mac_address': fake_neutron_port['mac_address'],
169 'status': constants.STATUS_ACTIVE,
170 'label': 'user',
171 'network_type': None,
172 'segmentation_id': None,
173 'ip_version': fake_share_network_multi['ip_version'],
174 'cidr': fake_share_network_multi['cidr'],
175 'gateway': 'fake_gateway',
176 'mtu': fake_share_network_multi['mtu'],
177}
178
179fake_binding_profile = {
180 'neutron_switch_id': 'fake switch id',
181 'neutron_port_id': 'fake port id',
182 'neutron_switch_info': 'fake switch info'
183}
184
114 185
115class NeutronNetworkPluginTest(test.TestCase): 186class NeutronNetworkPluginTest(test.TestCase):
116 187
@@ -311,6 +382,58 @@ class NeutronNetworkPluginTest(test.TestCase):
311 share_nw_update_dict) 382 share_nw_update_dict)
312 383
313 @mock.patch.object(db_api, 'share_network_update', mock.Mock()) 384 @mock.patch.object(db_api, 'share_network_update', mock.Mock())
385 def test_save_neutron_network_data_multi_segment(self):
386 share_nw_update_dict = {
387 'network_type': 'vlan',
388 'segmentation_id': 3926,
389 'mtu': 1509
390 }
391 config_data = {
392 'DEFAULT': {
393 'neutron_physical_net_name': 'net1',
394 }
395 }
396
397 self.mock_object(self.plugin.neutron_api, 'get_network')
398 self.plugin.neutron_api.get_network.return_value = fake_nw_info
399
400 with test_utils.create_temp_config_with_opts(config_data):
401 self.plugin._save_neutron_network_data(self.fake_context,
402 fake_share_network)
403
404 self.plugin.neutron_api.get_network.assert_called_once_with(
405 fake_share_network['neutron_net_id'])
406 self.plugin.db.share_network_update.assert_called_once_with(
407 self.fake_context,
408 fake_share_network['id'],
409 share_nw_update_dict)
410
411 @mock.patch.object(db_api, 'share_network_update', mock.Mock())
412 def test_save_neutron_network_data_multi_segment_without_ident(self):
413 config_data = {
414 'DEFAULT': {
415 'neutron_physical_net_name': 'net100',
416 }
417 }
418
419 self.mock_object(self.plugin.neutron_api, 'get_network')
420 self.plugin.neutron_api.get_network.return_value = fake_nw_info
421
422 with test_utils.create_temp_config_with_opts(config_data):
423 self.assertRaises(exception.NetworkBadConfigurationException,
424 self.plugin._save_neutron_network_data,
425 self.fake_context, fake_share_network)
426
427 @mock.patch.object(db_api, 'share_network_update', mock.Mock())
428 def test_save_neutron_network_data_multi_segment_without_cfg(self):
429 self.mock_object(self.plugin.neutron_api, 'get_network')
430 self.plugin.neutron_api.get_network.return_value = fake_nw_info
431
432 self.assertRaises(exception.NetworkBadConfigurationException,
433 self.plugin._save_neutron_network_data,
434 self.fake_context, fake_share_network)
435
436 @mock.patch.object(db_api, 'share_network_update', mock.Mock())
314 def test_save_neutron_subnet_data(self): 437 def test_save_neutron_subnet_data(self):
315 neutron_subnet_info = { 438 neutron_subnet_info = {
316 'cidr': '10.0.0.0/24', 439 'cidr': '10.0.0.0/24',
@@ -543,6 +666,7 @@ class NeutronBindNetworkPluginTest(test.TestCase):
543 self.bind_plugin = self._get_neutron_network_plugin_instance() 666 self.bind_plugin = self._get_neutron_network_plugin_instance()
544 self.bind_plugin.db = db_api 667 self.bind_plugin.db = db_api
545 self.sleep_mock = self.mock_object(time, 'sleep') 668 self.sleep_mock = self.mock_object(time, 'sleep')
669 self.fake_share_network_multi = dict(fake_share_network_multi)
546 670
547 def _get_neutron_network_plugin_instance(self, config_data=None): 671 def _get_neutron_network_plugin_instance(self, config_data=None):
548 if config_data is None: 672 if config_data is None:
@@ -593,8 +717,6 @@ class NeutronBindNetworkPluginTest(test.TestCase):
593 [fake_neut_port1, fake_neut_port2], 717 [fake_neut_port1, fake_neut_port2],
594 fake_share_server) 718 fake_share_server)
595 719
596 @mock.patch.object(db_api, 'network_allocation_create',
597 mock.Mock(return_values=fake_network_allocation))
598 @mock.patch.object(db_api, 'share_network_get', 720 @mock.patch.object(db_api, 'share_network_get',
599 mock.Mock(return_value=fake_share_network)) 721 mock.Mock(return_value=fake_share_network))
600 @mock.patch.object(db_api, 'share_server_get', 722 @mock.patch.object(db_api, 'share_server_get',
@@ -611,6 +733,10 @@ class NeutronBindNetworkPluginTest(test.TestCase):
611 self.mock_object(neutron_host_id_opts, 'default') 733 self.mock_object(neutron_host_id_opts, 'default')
612 neutron_host_id_opts.default = 'foohost1' 734 neutron_host_id_opts.default = 'foohost1'
613 self.mock_object(db_api, 'network_allocation_create') 735 self.mock_object(db_api, 'network_allocation_create')
736 db_api.network_allocation_create.return_value = fake_network_allocation
737 self.mock_object(self.bind_plugin.neutron_api, 'get_network')
738 self.bind_plugin.neutron_api.get_network.return_value = (
739 fake_neutron_network)
614 740
615 with mock.patch.object(self.bind_plugin.neutron_api, 'create_port', 741 with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
616 mock.Mock(return_value=fake_neutron_port)): 742 mock.Mock(return_value=fake_neutron_port)):
@@ -641,6 +767,96 @@ class NeutronBindNetworkPluginTest(test.TestCase):
641 self.bind_plugin._wait_for_ports_bind.assert_called_once_with( 767 self.bind_plugin._wait_for_ports_bind.assert_called_once_with(
642 [db_api.network_allocation_create()], fake_share_server) 768 [db_api.network_allocation_create()], fake_share_server)
643 769
770 @mock.patch.object(db_api, 'network_allocation_create',
771 mock.Mock(return_values=fake_network_allocation_multi))
772 @mock.patch.object(db_api, 'share_network_get',
773 mock.Mock(return_value=fake_share_network_multi))
774 @mock.patch.object(db_api, 'share_server_get',
775 mock.Mock(return_value=fake_share_server))
776 def test_allocate_network_multi_segment(self):
777 network_allocation_update_data = {
778 'network_type':
779 fake_nw_info['segments'][0]['provider:network_type'],
780 'segmentation_id':
781 fake_nw_info['segments'][0]['provider:segmentation_id'],
782 }
783 network_update_data = dict(network_allocation_update_data)
784 network_update_data['mtu'] = fake_nw_info['mtu']
785 fake_network_allocation_multi_updated = dict(
786 fake_network_allocation_multi)
787 fake_network_allocation_multi_updated.update(
788 network_allocation_update_data)
789 fake_share_network_multi_updated = dict(fake_share_network_multi)
790 fake_share_network_multi_updated.update(network_update_data)
791 config_data = {
792 'DEFAULT': {
793 'neutron_net_id': 'fake net id',
794 'neutron_subnet_id': 'fake subnet id',
795 'neutron_physical_net_name': 'net1',
796 }
797 }
798 self.bind_plugin = self._get_neutron_network_plugin_instance(
799 config_data)
800 self.bind_plugin.db = db_api
801
802 self.mock_object(self.bind_plugin, '_has_provider_network_extension')
803 self.bind_plugin._has_provider_network_extension.return_value = True
804 save_subnet_data = self.mock_object(self.bind_plugin,
805 '_save_neutron_subnet_data')
806 self.mock_object(self.bind_plugin, '_wait_for_ports_bind')
807 neutron_host_id_opts = plugin.neutron_bind_network_plugin_opts[1]
808 self.mock_object(neutron_host_id_opts, 'default')
809 neutron_host_id_opts.default = 'foohost1'
810
811 self.mock_object(db_api, 'network_allocation_create')
812 db_api.network_allocation_create.return_value = (
813 fake_network_allocation_multi)
814 self.mock_object(db_api, 'network_allocation_update')
815 db_api.network_allocation_update.return_value = (
816 fake_network_allocation_multi_updated)
817 self.mock_object(self.bind_plugin.neutron_api, 'get_network')
818 self.bind_plugin.neutron_api.get_network.return_value = (
819 fake_neutron_network_multi)
820 self.mock_object(db_api, 'share_network_update')
821
822 with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
823 mock.Mock(return_value=fake_neutron_port)):
824 self.bind_plugin.allocate_network(
825 self.fake_context,
826 fake_share_server,
827 self.fake_share_network_multi,
828 allocation_info={'count': 1})
829
830 self.bind_plugin._has_provider_network_extension.assert_any_call()
831 save_subnet_data.assert_called_once_with(
832 self.fake_context,
833 fake_share_network_multi_updated)
834 expected_kwargs = {
835 'binding:vnic_type': 'baremetal',
836 'host_id': 'foohost1',
837 'network_id': fake_share_network_multi['neutron_net_id'],
838 'subnet_id': fake_share_network_multi['neutron_subnet_id'],
839 'device_owner': 'manila:share',
840 'device_id': fake_share_network_multi['id']
841 }
842 self.bind_plugin.neutron_api.create_port.assert_called_once_with(
843 fake_share_network_multi['project_id'], **expected_kwargs)
844 db_api.network_allocation_create.assert_called_once_with(
845 self.fake_context,
846 fake_network_allocation_multi)
847 db_api.share_network_update.assert_called_once_with(
848 self.fake_context,
849 fake_share_network_multi['id'],
850 network_update_data)
851 network_allocation_update_data['cidr'] = (
852 fake_share_network_multi['cidr'])
853 network_allocation_update_data['ip_version'] = (
854 fake_share_network_multi['ip_version'])
855 db_api.network_allocation_update.assert_called_once_with(
856 self.fake_context,
857 fake_neutron_port['id'],
858 network_allocation_update_data)
859
644 @ddt.data({ 860 @ddt.data({
645 'neutron_binding_profiles': None, 861 'neutron_binding_profiles': None,
646 'binding_profiles': {} 862 'binding_profiles': {}
@@ -821,6 +1037,7 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
821 'DEFAULT': { 1037 'DEFAULT': {
822 'neutron_net_id': fake_net_id, 1038 'neutron_net_id': fake_net_id,
823 'neutron_subnet_id': fake_subnet_id, 1039 'neutron_subnet_id': fake_subnet_id,
1040 'neutron_physical_net_name': 'net1',
824 } 1041 }
825 } 1042 }
826 fake_net = {'subnets': ['fake1', 'fake2', fake_subnet_id]} 1043 fake_net = {'subnets': ['fake1', 'fake2', fake_subnet_id]}
@@ -836,8 +1053,8 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
836 'port1', 'port2'] 1053 'port1', 'port2']
837 instance = self._get_neutron_network_plugin_instance() 1054 instance = self._get_neutron_network_plugin_instance()
838 share_server = 'fake_share_server' 1055 share_server = 'fake_share_server'
839 share_network = 'fake_share_network' 1056 share_network = {'neutron_net_id': {}}
840 share_network_upd = 'updated_fake_share_network' 1057 share_network_upd = {'neutron_net_id': {'upd': True}}
841 count = 2 1058 count = 2
842 device_owner = 'fake_device_owner' 1059 device_owner = 'fake_device_owner'
843 self.mock_object( 1060 self.mock_object(
@@ -1279,6 +1496,9 @@ class NeutronBindNetworkPluginWithNormalTypeTest(test.TestCase):
1279 self.mock_object(neutron_host_id_opts, 'default') 1496 self.mock_object(neutron_host_id_opts, 'default')
1280 neutron_host_id_opts.default = 'foohost1' 1497 neutron_host_id_opts.default = 'foohost1'
1281 self.mock_object(db_api, 'network_allocation_create') 1498 self.mock_object(db_api, 'network_allocation_create')
1499 multi_seg = self.mock_object(
1500 self.bind_plugin, '_is_neutron_multi_segment')
1501 multi_seg.return_value = False
1282 1502
1283 with mock.patch.object(self.bind_plugin.neutron_api, 'create_port', 1503 with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
1284 mock.Mock(return_value=fake_neutron_port)): 1504 mock.Mock(return_value=fake_neutron_port)):
diff --git a/releasenotes/notes/multi-segment-support-fa171a8e3201d54e.yaml b/releasenotes/notes/multi-segment-support-fa171a8e3201d54e.yaml
new file mode 100644
index 0000000..359845e
--- /dev/null
+++ b/releasenotes/notes/multi-segment-support-fa171a8e3201d54e.yaml
@@ -0,0 +1,3 @@
1---
2features:
3 - Added port binding support for neutron networks with multiple segments.