Enable configuration to decide on vlan tag per TZ
NSX|V3: This feature will enable an admin user to configure a range of VLAN IDs per VLAN Transport Zone, so when they create a VLAN, the VLAN tag will be set accordingly. The configuration is being done in the nsx.ini file, under the relevant section for nsx-v3, the admin will note the tz-id, with either a predefined range(s) (min/max values) or only the transport zone itself (which means that any value can be chosen). The admin user will create the network noting “provider:physical_network”, if they select a VLAN ID, than it will be used, if not - one will be chosen according to the configuration mentioned above. New configuration variable in nsx.ini under nsx_v3: network_vlan_ranges network_vlan_ranges=<TZ_UUID>:<min_val>:<max_val> Change-Id: Id202ca28bda44286deacb5c9969ffd92aa564a90 Signed-off-by: Michal Kelner Mishali <mkelnermishal@vmware.com>
This commit is contained in:
parent
895c25d2df
commit
ab622863d5
@ -0,0 +1,9 @@
|
||||
---
|
||||
prelude: >
|
||||
The NSX-V3 plugin can decide on the VLAN tag for a provider network.
|
||||
features:
|
||||
- |
|
||||
The NSX-V3 plugin can decide on the VLAN tag for a provider network,
|
||||
according to pre-defined configuration set per transport zone UUID,
|
||||
noting a specific range or letting the plugin decide according to
|
||||
min/max constants.
|
@ -438,6 +438,12 @@ nsx_v3_opts = [
|
||||
default=False,
|
||||
help=_("(Optional) Indicates whether ENS transport zones can "
|
||||
"be used")),
|
||||
cfg.ListOpt('network_vlan_ranges',
|
||||
default=[],
|
||||
help=_("List of <TZ UUID>:<vlan_min>:<vlan_max> "
|
||||
"specifying Transport Zone UUID usable for VLAN "
|
||||
"provider networks, as well as ranges of VLAN "
|
||||
"tags on each available for allocation to networks.")),
|
||||
]
|
||||
|
||||
DEFAULT_STATUS_CHECK_INTERVAL = 2000
|
||||
|
@ -51,6 +51,13 @@ def get_network_bindings(session, network_id):
|
||||
all())
|
||||
|
||||
|
||||
def get_network_bindings_by_phy_uuid(session, phy_uuid):
|
||||
session = session or db.get_reader_session()
|
||||
return (session.query(nsx_models.TzNetworkBinding).
|
||||
filter_by(phy_uuid=phy_uuid).
|
||||
all())
|
||||
|
||||
|
||||
def get_network_bindings_by_vlanid_and_physical_net(session, vlan_id,
|
||||
phy_uuid):
|
||||
session = session or db.get_reader_session()
|
||||
|
@ -81,6 +81,7 @@ from oslo_log import log
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import uuidutils
|
||||
from six import moves
|
||||
from sqlalchemy import exc as sql_exc
|
||||
import webob.exc
|
||||
|
||||
@ -249,6 +250,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
self.cfg_group = 'nsx_v3' # group name for nsx_v3 section in nsx.ini
|
||||
self.tier0_groups_dict = {}
|
||||
|
||||
self._network_vlans = n_utils.parse_network_vlan_ranges(
|
||||
cfg.CONF.nsx_v3.network_vlan_ranges)
|
||||
# Initialize the network availability zones, which will be used only
|
||||
# when native_dhcp_metadata is True
|
||||
self.init_availability_zones()
|
||||
@ -803,9 +806,9 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
|
||||
# Validate VLAN id
|
||||
if not vlan_id:
|
||||
err_msg = (_('Segmentation ID must be specified with %s '
|
||||
'network type') %
|
||||
utils.NsxV3NetworkTypes.VLAN)
|
||||
vlan_id = self._generate_segment_id(context,
|
||||
physical_net,
|
||||
network_data)
|
||||
elif not n_utils.is_valid_vlan_tag(vlan_id):
|
||||
err_msg = (_('Segmentation ID %(segmentation_id)s out of '
|
||||
'range (%(min_id)s through %(max_id)s)') %
|
||||
@ -1043,6 +1046,26 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
return (bindings[0].binding_type ==
|
||||
utils.NsxV3NetworkTypes.NSX_NETWORK)
|
||||
|
||||
def _generate_segment_id(self, context, physical_network, net_data):
|
||||
bindings = nsx_db.get_network_bindings_by_phy_uuid(
|
||||
context.session, physical_network)
|
||||
vlan_ranges = self._network_vlans.get(physical_network, [])
|
||||
if vlan_ranges:
|
||||
vlan_ids = set()
|
||||
for vlan_min, vlan_max in vlan_ranges:
|
||||
vlan_ids |= set(moves.range(vlan_min, vlan_max + 1))
|
||||
else:
|
||||
vlan_min = const.MIN_VLAN_TAG
|
||||
vlan_max = const.MAX_VLAN_TAG
|
||||
vlan_ids = set(moves.range(vlan_min, vlan_max + 1))
|
||||
used_ids_in_range = set([binding.vlan_id for binding in bindings
|
||||
if binding.vlan_id in vlan_ids])
|
||||
free_ids = list(vlan_ids ^ used_ids_in_range)
|
||||
if len(free_ids) == 0:
|
||||
raise n_exc.NoNetworkAvailable()
|
||||
net_data[pnet.SEGMENTATION_ID] = free_ids[0]
|
||||
return net_data[pnet.SEGMENTATION_ID]
|
||||
|
||||
def create_network(self, context, network):
|
||||
net_data = network['network']
|
||||
external = net_data.get(extnet_apidef.EXTERNAL)
|
||||
|
@ -19,6 +19,7 @@ from neutron.db import models_v2
|
||||
from neutron.extensions import address_scope
|
||||
from neutron.extensions import l3
|
||||
from neutron.extensions import securitygroup as secgrp
|
||||
from neutron.plugins.common import utils as n_utils
|
||||
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
||||
from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
|
||||
from neutron.tests.unit.extensions import test_address_scope
|
||||
@ -29,6 +30,7 @@ from neutron.tests.unit.extensions \
|
||||
import test_l3_ext_gw_mode as test_ext_gw_mode
|
||||
from neutron.tests.unit.scheduler \
|
||||
import test_dhcp_agent_scheduler as test_dhcpagent
|
||||
from neutron.tests.unit import testlib_api
|
||||
from neutron_lib.api.definitions import external_net as extnet_apidef
|
||||
from neutron_lib.api.definitions import extraroute as xroute_apidef
|
||||
from neutron_lib.api.definitions import l3_ext_gw_mode as l3_egm_apidef
|
||||
@ -546,6 +548,57 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin):
|
||||
data = self.deserialize('json', result)
|
||||
self.assertEqual('vlan', data['network'].get(pnet.NETWORK_TYPE))
|
||||
|
||||
def _test_generate_tag(self, vlan_id):
|
||||
net_type = 'vlan'
|
||||
name = 'phys_net'
|
||||
plugin = directory.get_plugin()
|
||||
plugin._network_vlans = n_utils.parse_network_vlan_ranges(
|
||||
cfg.CONF.nsx_v3.network_vlan_ranges)
|
||||
expected = [('subnets', []), ('name', name),
|
||||
('admin_state_up', True),
|
||||
('status', 'ACTIVE'),
|
||||
('shared', False),
|
||||
(pnet.NETWORK_TYPE, net_type),
|
||||
(pnet.PHYSICAL_NETWORK,
|
||||
'fb69d878-958e-4f32-84e4-50286f26226b'),
|
||||
(pnet.SEGMENTATION_ID, vlan_id)]
|
||||
providernet_args = {pnet.NETWORK_TYPE: net_type,
|
||||
pnet.PHYSICAL_NETWORK:
|
||||
'fb69d878-958e-4f32-84e4-50286f26226b'}
|
||||
|
||||
with mock.patch('vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
|
||||
'get_transport_type', return_value='VLAN'):
|
||||
with self.network(name=name, providernet_args=providernet_args,
|
||||
arg_list=(pnet.NETWORK_TYPE,
|
||||
pnet.PHYSICAL_NETWORK)) as net:
|
||||
for k, v in expected:
|
||||
self.assertEqual(net['network'][k], v)
|
||||
|
||||
def test_create_phys_vlan_generate(self):
|
||||
cfg.CONF.set_override('network_vlan_ranges',
|
||||
'fb69d878-958e-4f32-84e4-50286f26226b',
|
||||
'nsx_v3')
|
||||
self._test_generate_tag(1)
|
||||
|
||||
def test_create_phys_vlan_generate_range(self):
|
||||
cfg.CONF.set_override('network_vlan_ranges',
|
||||
'fb69d878-958e-4f32-84e4-'
|
||||
'50286f26226b:100:110',
|
||||
'nsx_v3')
|
||||
self._test_generate_tag(100)
|
||||
|
||||
def test_create_phys_vlan_network_outofrange_returns_503(self):
|
||||
cfg.CONF.set_override('network_vlan_ranges',
|
||||
'fb69d878-958e-4f32-84e4-'
|
||||
'50286f26226b:9:10',
|
||||
'nsx_v3')
|
||||
self._test_generate_tag(9)
|
||||
self._test_generate_tag(10)
|
||||
with testlib_api.ExpectedException(exc.HTTPClientError) as ctx_manager:
|
||||
self._test_generate_tag(11)
|
||||
|
||||
self.assertEqual(ctx_manager.exception.code, 503)
|
||||
|
||||
|
||||
class TestSubnetsV2(test_plugin.TestSubnetsV2, NsxV3PluginTestCaseMixin):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user