from neutron.db import models_v2
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_rpc_base as sg_db_rpc
+from neutron.extensions import multiprovidernet as mpnet
from neutron.extensions import portbindings
from neutron.extensions import providernet as provider
from neutron.openstack.common import excutils
_supported_extension_aliases = ["provider", "router", "extraroute",
"binding", "quotas", "security-group",
"agent", "l3_agent_scheduler",
- "dhcp_agent_scheduler", "ext-gw-mode"]
+ "dhcp_agent_scheduler", "ext-gw-mode",
+ "multi-provider"]
@property
def supported_extension_aliases(self):
fanout=False)
self.conn.consume_in_thread()
- def _process_provider_create(self, context, attrs):
- network_type = self._get_attribute(attrs, provider.NETWORK_TYPE)
- physical_network = self._get_attribute(attrs,
+ def _process_provider_segment(self, segment):
+ network_type = self._get_attribute(segment, provider.NETWORK_TYPE)
+ physical_network = self._get_attribute(segment,
provider.PHYSICAL_NETWORK)
- segmentation_id = self._get_attribute(attrs, provider.SEGMENTATION_ID)
+ segmentation_id = self._get_attribute(segment,
+ provider.SEGMENTATION_ID)
if attributes.is_attr_set(network_type):
segment = {api.NETWORK_TYPE: network_type,
api.PHYSICAL_NETWORK: physical_network,
api.SEGMENTATION_ID: segmentation_id}
self.type_manager.validate_provider_segment(segment)
-
return segment
- if (attributes.is_attr_set(attrs.get(provider.PHYSICAL_NETWORK)) or
- attributes.is_attr_set(attrs.get(provider.SEGMENTATION_ID))):
- msg = _("network_type required if other provider attributes "
- "specified")
- raise exc.InvalidInput(error_message=msg)
+ msg = _("network_type required")
+ raise exc.InvalidInput(error_message=msg)
+
+ def _process_provider_create(self, network):
+ segments = []
+
+ if any(attributes.is_attr_set(network.get(f))
+ for f in (provider.NETWORK_TYPE, provider.PHYSICAL_NETWORK,
+ provider.SEGMENTATION_ID)):
+ # Verify that multiprovider and provider attributes are not set
+ # at the same time.
+ if attributes.is_attr_set(network.get(mpnet.SEGMENTS)):
+ raise mpnet.SegmentsSetInConjunctionWithProviders()
+
+ network_type = self._get_attribute(network, provider.NETWORK_TYPE)
+ physical_network = self._get_attribute(network,
+ provider.PHYSICAL_NETWORK)
+ segmentation_id = self._get_attribute(network,
+ provider.SEGMENTATION_ID)
+ segments = [{provider.NETWORK_TYPE: network_type,
+ provider.PHYSICAL_NETWORK: physical_network,
+ provider.SEGMENTATION_ID: segmentation_id}]
+ elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)):
+ segments = network[mpnet.SEGMENTS]
+ else:
+ return
+
+ return [self._process_provider_segment(s) for s in segments]
def _get_attribute(self, attrs, key):
value = attrs.get(key)
network[provider.PHYSICAL_NETWORK] = None
network[provider.SEGMENTATION_ID] = None
elif len(segments) > 1:
- network[provider.NETWORK_TYPE] = TYPE_MULTI_SEGMENT
- network[provider.PHYSICAL_NETWORK] = None
- network[provider.SEGMENTATION_ID] = None
+ network[mpnet.SEGMENTS] = [
+ {provider.NETWORK_TYPE: segment[api.NETWORK_TYPE],
+ provider.PHYSICAL_NETWORK: segment[api.PHYSICAL_NETWORK],
+ provider.SEGMENTATION_ID: segment[api.SEGMENTATION_ID]}
+ for segment in segments]
else:
segment = segments[0]
network[provider.NETWORK_TYPE] = segment[api.NETWORK_TYPE]
# TODO(apech): Need to override bulk operations
def create_network(self, context, network):
- attrs = network['network']
- segment = self._process_provider_create(context, attrs)
- tenant_id = self._get_tenant_id_for_create(context, attrs)
+ net_data = network['network']
+ segments = self._process_provider_create(net_data)
+ tenant_id = self._get_tenant_id_for_create(context, net_data)
session = context.session
with session.begin(subtransactions=True):
self._ensure_default_security_group(context, tenant_id)
- if segment:
- self.type_manager.reserve_provider_segment(session, segment)
- else:
- segment = self.type_manager.allocate_tenant_segment(session)
result = super(Ml2Plugin, self).create_network(context, network)
- id = result['id']
- self._process_l3_create(context, result, attrs)
+ network_id = result['id']
+ self._process_l3_create(context, result, net_data)
# REVISIT(rkukura): Consider moving all segment management
# to TypeManager.
- db.add_network_segment(session, id, segment)
+ if segments:
+ for segment in segments:
+ self.type_manager.reserve_provider_segment(session,
+ segment)
+ db.add_network_segment(session, network_id, segment)
+ else:
+ segment = self.type_manager.allocate_tenant_segment(session)
+ db.add_network_segment(session, network_id, segment)
self._extend_network_dict_provider(context, result)
mech_context = driver_context.NetworkContext(self, context,
result)
# License for the specific language governing permissions and limitations
# under the License.
+from neutron.extensions import multiprovidernet as mpnet
from neutron.extensions import portbindings
-from neutron.plugins.ml2 import config as config
+from neutron.extensions import providernet as pnet
+from neutron.plugins.ml2 import config
from neutron.tests.unit import _test_extension_portbindings as test_bindings
from neutron.tests.unit import test_db_plugin as test_plugin
from neutron.tests.unit import test_extension_ext_gw_mode
# driver apis.
config.cfg.CONF.set_override('mechanism_drivers',
['logger', 'test'],
- 'ml2')
+ group='ml2')
+ self.physnet = 'physnet1'
+ self.vlan_range = '1:100'
+ self.phys_vrange = ':'.join([self.physnet, self.vlan_range])
+ config.cfg.CONF.set_override('network_vlan_ranges', [self.phys_vrange],
+ group='ml2_type_vlan')
self.addCleanup(config.cfg.CONF.reset)
super(Ml2PluginV2TestCase, self).setUp(PLUGIN_NAME)
self.port_create_status = 'DOWN'
class TestMl2ExtGwModeSupport(Ml2PluginV2TestCase,
test_extension_ext_gw_mode.ExtGwModeTestCase):
pass
+
+
+class TestMultiSegmentNetworks(Ml2PluginV2TestCase):
+
+ def setUp(self, plugin=None):
+ super(TestMultiSegmentNetworks, self).setUp()
+
+ def test_create_network_provider(self):
+ data = {'network': {'name': 'net1',
+ pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 1,
+ 'tenant_id': 'tenant_one'}}
+ network_req = self.new_create_request('networks', data)
+ network = self.deserialize(self.fmt,
+ network_req.get_response(self.api))
+ self.assertEqual(network['network'][pnet.NETWORK_TYPE], 'vlan')
+ self.assertEqual(network['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
+ self.assertEqual(network['network'][pnet.SEGMENTATION_ID], 1)
+ self.assertNotIn(mpnet.SEGMENTS, network['network'])
+
+ def test_create_network_single_multiprovider(self):
+ data = {'network': {'name': 'net1',
+ mpnet.SEGMENTS:
+ [{pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 1}],
+ 'tenant_id': 'tenant_one'}}
+ net_req = self.new_create_request('networks', data)
+ network = self.deserialize(self.fmt, net_req.get_response(self.api))
+ self.assertEqual(network['network'][pnet.NETWORK_TYPE], 'vlan')
+ self.assertEqual(network['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
+ self.assertEqual(network['network'][pnet.SEGMENTATION_ID], 1)
+ self.assertNotIn(mpnet.SEGMENTS, network['network'])
+
+ # Tests get_network()
+ net_req = self.new_show_request('networks', network['network']['id'])
+ network = self.deserialize(self.fmt, net_req.get_response(self.api))
+ self.assertEqual(network['network'][pnet.NETWORK_TYPE], 'vlan')
+ self.assertEqual(network['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
+ self.assertEqual(network['network'][pnet.SEGMENTATION_ID], 1)
+ self.assertNotIn(mpnet.SEGMENTS, network['network'])
+
+ def test_create_network_multiprovider(self):
+ data = {'network': {'name': 'net1',
+ mpnet.SEGMENTS:
+ [{pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 1},
+ {pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 2}],
+ 'tenant_id': 'tenant_one'}}
+ network_req = self.new_create_request('networks', data)
+ network = self.deserialize(self.fmt,
+ network_req.get_response(self.api))
+ tz = network['network'][mpnet.SEGMENTS]
+ for tz in data['network'][mpnet.SEGMENTS]:
+ for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
+ pnet.SEGMENTATION_ID]:
+ self.assertEqual(tz.get(field), tz.get(field))
+
+ # Tests get_network()
+ net_req = self.new_show_request('networks', network['network']['id'])
+ network = self.deserialize(self.fmt, net_req.get_response(self.api))
+ tz = network['network'][mpnet.SEGMENTS]
+ for tz in data['network'][mpnet.SEGMENTS]:
+ for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
+ pnet.SEGMENTATION_ID]:
+ self.assertEqual(tz.get(field), tz.get(field))
+
+ def test_create_network_with_provider_and_multiprovider_fail(self):
+ data = {'network': {'name': 'net1',
+ mpnet.SEGMENTS:
+ [{pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 1}],
+ pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 1,
+ 'tenant_id': 'tenant_one'}}
+
+ network_req = self.new_create_request('networks', data)
+ res = network_req.get_response(self.api)
+ self.assertEqual(res.status_int, 400)
+
+ def test_create_network_duplicate_segments(self):
+ data = {'network': {'name': 'net1',
+ mpnet.SEGMENTS:
+ [{pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 1},
+ {pnet.NETWORK_TYPE: 'vlan',
+ pnet.PHYSICAL_NETWORK: 'physnet1',
+ pnet.SEGMENTATION_ID: 1}],
+ 'tenant_id': 'tenant_one'}}
+ network_req = self.new_create_request('networks', data)
+ res = network_req.get_response(self.api)
+ self.assertEqual(res.status_int, 400)