Merge "NSX|V3: Support security features for ENS switches"
This commit is contained in:
commit
91100ffd5a
@ -145,6 +145,8 @@ NSX_V3_FW_DEFAULT_NS_GROUP = 'os_default_section_ns_group'
|
||||
NSX_V3_DEFAULT_SECTION = 'OS-Default-Section'
|
||||
NSX_V3_EXCLUDED_PORT_NSGROUP_NAME = 'neutron_excluded_port_nsgroup'
|
||||
NSX_V3_NON_VIF_PROFILE = 'nsx-default-switch-security-non-vif-profile'
|
||||
NSX_V3_NON_VIF_ENS_PROFILE = \
|
||||
'nsx-default-switch-security-non-vif-profile-for-ens'
|
||||
NSX_V3_SERVER_SSL_PROFILE = 'nsx-default-server-ssl-profile'
|
||||
NSX_V3_CLIENT_SSL_PROFILE = 'nsx-default-client-ssl-profile'
|
||||
# Default UUID for the global OS rule
|
||||
@ -592,6 +594,13 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
NSX_V3_NON_VIF_PROFILE)[0]
|
||||
self._no_switch_security = profile_client.build_switch_profile_ids(
|
||||
profile_client, no_switch_security_prof)[0]
|
||||
if self._ens_psec_supported():
|
||||
no_switch_security_prof = profile_client.find_by_display_name(
|
||||
NSX_V3_NON_VIF_ENS_PROFILE)[0]
|
||||
self._no_switch_security_ens = (
|
||||
profile_client.build_switch_profile_ids(
|
||||
profile_client, no_switch_security_prof)[0])
|
||||
|
||||
self.server_ssl_profile = None
|
||||
self.client_ssl_profile = None
|
||||
# Only create LB profiles when nsxv3 version >= 2.1.0
|
||||
@ -1075,21 +1084,14 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
transparent_vlan):
|
||||
provider_data = self._validate_provider_create(context, net_data, az,
|
||||
transparent_vlan)
|
||||
|
||||
physical_net = provider_data['physical_net']
|
||||
neutron_net_id = net_data.get('id') or uuidutils.generate_uuid()
|
||||
net_data['id'] = neutron_net_id
|
||||
if self._is_ens_tz(physical_net):
|
||||
self._assert_on_ens_with_qos(net_data)
|
||||
self._ensure_override_ens_with_portsecurity(net_data)
|
||||
if (provider_data['switch_mode'] ==
|
||||
self.nsxlib.transport_zone.HOST_SWITCH_MODE_ENS):
|
||||
if not cfg.CONF.nsx_v3.ens_support:
|
||||
raise NotImplementedError(_("ENS support is disabled"))
|
||||
if net_data.get(psec.PORTSECURITY):
|
||||
raise nsx_exc.NsxENSPortSecurity()
|
||||
# set the default port security to False
|
||||
net_data[psec.PORTSECURITY] = False
|
||||
self._assert_on_ens_with_qos(net_data)
|
||||
self._validate_ens_net_portsecurity(net_data)
|
||||
|
||||
if (provider_data['is_provider_net'] and
|
||||
provider_data['net_type'] == utils.NsxV3NetworkTypes.NSX_NETWORK):
|
||||
@ -1395,11 +1397,26 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
err_msg = _("Cannot configure QOS on ENS networks")
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
def _ensure_override_ens_with_portsecurity(self, net_data):
|
||||
if cfg.CONF.nsx_v3.disable_port_security_for_ens:
|
||||
if net_data[psec.PORTSECURITY]:
|
||||
LOG.warning("Disabling port security for network %s",
|
||||
net_data['id'])
|
||||
def _ens_psec_supported(self):
|
||||
return self.nsxlib.feature_supported(
|
||||
nsxlib_consts.FEATURE_ENS_WITH_SEC)
|
||||
|
||||
def _validate_ens_net_portsecurity(self, net_data):
|
||||
"""Validate/Update the port security of the new network for ENS TZ"""
|
||||
if not self._ens_psec_supported():
|
||||
if cfg.CONF.nsx_v3.disable_port_security_for_ens:
|
||||
# Override the port-security to False
|
||||
if net_data[psec.PORTSECURITY]:
|
||||
LOG.warning("Disabling port security for network %s",
|
||||
net_data['id'])
|
||||
# Set the port security to False
|
||||
net_data[psec.PORTSECURITY] = False
|
||||
|
||||
elif net_data.get(psec.PORTSECURITY):
|
||||
# Port security enabled is not allowed
|
||||
raise nsx_exc.NsxENSPortSecurity()
|
||||
else:
|
||||
# Update the default port security to False if not set
|
||||
net_data[psec.PORTSECURITY] = False
|
||||
|
||||
def _has_active_port(self, context, network_id):
|
||||
@ -1518,7 +1535,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
if psec.PORTSECURITY in net_data:
|
||||
# do not allow to enable port security on ENS networks
|
||||
if (net_data[psec.PORTSECURITY] and
|
||||
not original_net[psec.PORTSECURITY] and is_ens_net):
|
||||
not original_net[psec.PORTSECURITY] and is_ens_net and
|
||||
not self._ens_psec_supported()):
|
||||
raise nsx_exc.NsxENSPortSecurity()
|
||||
self._process_network_port_security_update(
|
||||
context, net_data, updated_net)
|
||||
@ -2336,7 +2354,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
mac_learning_profile_set = True
|
||||
profiles.append(self._get_port_security_profile_id())
|
||||
if device_owner == const.DEVICE_OWNER_DHCP:
|
||||
if (not is_ens_tz_port and
|
||||
if ((not is_ens_tz_port or self._ens_psec_supported()) and
|
||||
not cfg.CONF.nsx_v3.native_dhcp_metadata):
|
||||
profiles.append(self._dhcp_profile)
|
||||
|
||||
@ -2353,12 +2371,16 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
profiles.append(qos_profile_id)
|
||||
|
||||
# Add mac_learning profile if it exists and is configured
|
||||
if (not is_ens_tz_port and self._mac_learning_profile and
|
||||
if ((not is_ens_tz_port or self._ens_psec_supported()) and
|
||||
self._mac_learning_profile and
|
||||
(mac_learning_profile_set or
|
||||
(validators.is_attr_set(port_data.get(mac_ext.MAC_LEARNING)) and
|
||||
port_data.get(mac_ext.MAC_LEARNING) is True))):
|
||||
profiles.append(self._mac_learning_profile)
|
||||
profiles.append(self._no_switch_security)
|
||||
if is_ens_tz_port:
|
||||
profiles.append(self._no_switch_security_ens)
|
||||
else:
|
||||
profiles.append(self._no_switch_security)
|
||||
|
||||
name = self._build_port_name(context, port_data)
|
||||
nsx_net_id = self._get_network_nsx_id(context, port_data['network_id'])
|
||||
@ -2432,7 +2454,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
context, port_data)
|
||||
port_data[psec.PORTSECURITY] = port_security
|
||||
# No port security is allowed if the port belongs to an ENS TZ
|
||||
if port_security and is_ens_tz_port:
|
||||
if (port_security and is_ens_tz_port and
|
||||
not self._ens_psec_supported()):
|
||||
raise nsx_exc.NsxENSPortSecurity()
|
||||
self._process_port_port_security_create(
|
||||
context, port_data, neutron_db)
|
||||
@ -2854,7 +2877,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
err_msg = _("Cannot configure QOS on ENS networks")
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
if cfg.CONF.nsx_v3.disable_port_security_for_ens:
|
||||
if (cfg.CONF.nsx_v3.disable_port_security_for_ens and
|
||||
not self._ens_psec_supported()):
|
||||
LOG.warning("Disabling port security for network %s",
|
||||
port_data['network_id'])
|
||||
port_data[psec.PORTSECURITY] = False
|
||||
@ -2925,7 +2949,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
'disabled')
|
||||
LOG.error(msg)
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
if is_ens_tz_port and not port_data.get(mac_ext.MAC_LEARNING):
|
||||
if (is_ens_tz_port and not self._ens_psec_supported() and
|
||||
not port_data.get(mac_ext.MAC_LEARNING)):
|
||||
msg = _('Cannot disable Mac learning for ENS TZ')
|
||||
LOG.error(msg)
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
@ -2936,7 +2961,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
# ATTR_NOT_SPECIFIED
|
||||
port_data.pop(mac_ext.MAC_LEARNING)
|
||||
# For a ENZ TZ mac learning is always enabled
|
||||
if is_ens_tz_port and mac_ext.MAC_LEARNING not in port_data:
|
||||
if (is_ens_tz_port and not self._ens_psec_supported() and
|
||||
mac_ext.MAC_LEARNING not in port_data):
|
||||
# Set the default and add to the DB
|
||||
port_data[mac_ext.MAC_LEARNING] = True
|
||||
self._create_mac_learning_state(context, port_data)
|
||||
@ -3122,7 +3148,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
|
||||
if updated_port[psec.PORTSECURITY] and psec.PORTSECURITY in port_data:
|
||||
# No port security is allowed if the port belongs to an ENS TZ
|
||||
if is_ens_tz_port:
|
||||
if is_ens_tz_port and not self._ens_psec_supported():
|
||||
raise nsx_exc.NsxENSPortSecurity()
|
||||
|
||||
# No port security is allowed if the port has a direct vnic type
|
||||
@ -3270,7 +3296,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
|
||||
# Update the DHCP profile
|
||||
if (updated_device_owner == const.DEVICE_OWNER_DHCP and
|
||||
not self._is_ens_tz_net(context, updated_port['network_id']) and
|
||||
(not is_ens_tz_port or self._ens_psec_supported()) and
|
||||
not cfg.CONF.nsx_v3.native_dhcp_metadata):
|
||||
switch_profile_ids.append(self._dhcp_profile)
|
||||
|
||||
@ -3293,11 +3319,15 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
validators.is_attr_set(address_pairs) and address_pairs and
|
||||
psec_is_on)
|
||||
# Add mac_learning profile if it exists and is configured
|
||||
if (not is_ens_tz_port and self._mac_learning_profile and
|
||||
if ((not is_ens_tz_port or self._ens_psec_supported()) and
|
||||
self._mac_learning_profile and
|
||||
(mac_learning_profile_set or
|
||||
updated_port.get(mac_ext.MAC_LEARNING) is True)):
|
||||
switch_profile_ids.append(self._mac_learning_profile)
|
||||
switch_profile_ids.append(self._no_switch_security)
|
||||
if is_ens_tz_port:
|
||||
switch_profile_ids.append(self._no_switch_security_ens)
|
||||
else:
|
||||
switch_profile_ids.append(self._no_switch_security)
|
||||
|
||||
try:
|
||||
self.nsxlib.logical_port.update(
|
||||
@ -3414,7 +3444,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
self._extend_nsx_port_dict_binding(context, updated_port)
|
||||
mac_learning_state = updated_port.get(mac_ext.MAC_LEARNING)
|
||||
if mac_learning_state is not None:
|
||||
if (not mac_learning_state and is_ens_tz_port):
|
||||
if (not mac_learning_state and is_ens_tz_port and
|
||||
not self._ens_psec_supported()):
|
||||
msg = _('Mac learning cannot be disabled with ENS TZ')
|
||||
LOG.error(msg)
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
@ -522,6 +522,24 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin):
|
||||
self.assertEqual('NsxENSPortSecurity',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_create_ens_network_with_port_sec_supported(self):
|
||||
cfg.CONF.set_override('ens_support', True, 'nsx_v3')
|
||||
providernet_args = {psec.PORTSECURITY: True}
|
||||
with mock.patch("vmware_nsxlib.v3.NsxLib.get_version",
|
||||
return_value='2.4.0'),\
|
||||
mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone."
|
||||
"get_host_switch_mode", return_value="ENS"),\
|
||||
mock.patch(
|
||||
"vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get",
|
||||
return_value={'transport_zone_id': 'xxx'}):
|
||||
result = self._create_network(fmt='json', name='ens_net',
|
||||
admin_state_up=True,
|
||||
providernet_args=providernet_args,
|
||||
arg_list=(psec.PORTSECURITY,))
|
||||
res = self.deserialize('json', result)
|
||||
# should succeed
|
||||
self.assertTrue(res['network'][psec.PORTSECURITY])
|
||||
|
||||
def test_create_ens_network_disable_default_port_security(self):
|
||||
cfg.CONF.set_override('ens_support', True, 'nsx_v3')
|
||||
cfg.CONF.set_override('disable_port_security_for_ens', True, 'nsx_v3')
|
||||
@ -629,6 +647,30 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin):
|
||||
self.assertEqual('NsxENSPortSecurity',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_update_ens_network_psec_supported(self):
|
||||
cfg.CONF.set_override('ens_support', True, 'nsx_v3')
|
||||
providernet_args = {psec.PORTSECURITY: False}
|
||||
with mock.patch("vmware_nsxlib.v3.NsxLib.get_version",
|
||||
return_value='2.4.0'),\
|
||||
mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone."
|
||||
"get_host_switch_mode", return_value="ENS"),\
|
||||
mock.patch(
|
||||
"vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get",
|
||||
return_value={'transport_zone_id': 'xxx'}):
|
||||
|
||||
result = self._create_network(fmt='json', name='ens_net',
|
||||
admin_state_up=True,
|
||||
providernet_args=providernet_args,
|
||||
arg_list=(psec.PORTSECURITY,))
|
||||
net = self.deserialize('json', result)
|
||||
net_id = net['network']['id']
|
||||
args = {'network': {psec.PORTSECURITY: True}}
|
||||
req = self.new_update_request('networks', args,
|
||||
net_id, fmt='json')
|
||||
res = self.deserialize('json', req.get_response(self.api))
|
||||
# should succeed
|
||||
self.assertTrue(res['network'][psec.PORTSECURITY])
|
||||
|
||||
def test_create_transparent_vlan_network(self):
|
||||
providernet_args = {vlan_apidef.VLANTRANSPARENT: True}
|
||||
with mock.patch(
|
||||
@ -1535,6 +1577,25 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin,
|
||||
self.assertEqual('NsxENSPortSecurity',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_create_ens_port_with_port_sec_supported(self):
|
||||
with self.subnet() as subnet,\
|
||||
mock.patch("vmware_nsxlib.v3.NsxLib.get_version",
|
||||
return_value='2.4.0'),\
|
||||
mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone."
|
||||
"get_host_switch_mode", return_value="ENS"),\
|
||||
mock.patch(
|
||||
"vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get",
|
||||
return_value={'transport_zone_id': 'xxx'}):
|
||||
args = {'port': {'network_id': subnet['subnet']['network_id'],
|
||||
'tenant_id': subnet['subnet']['tenant_id'],
|
||||
'fixed_ips': [{'subnet_id':
|
||||
subnet['subnet']['id']}],
|
||||
psec.PORTSECURITY: True}}
|
||||
port_req = self.new_create_request('ports', args)
|
||||
res = self.deserialize('json', port_req.get_response(self.api))
|
||||
# should succeed
|
||||
self.assertTrue(res['port'][psec.PORTSECURITY])
|
||||
|
||||
def test_update_ens_port(self):
|
||||
with self.subnet() as subnet,\
|
||||
mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone."
|
||||
@ -1557,6 +1618,29 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin,
|
||||
self.assertEqual('NsxENSPortSecurity',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_update_ens_port_psec_supported(self):
|
||||
with self.subnet() as subnet,\
|
||||
mock.patch("vmware_nsxlib.v3.NsxLib.get_version",
|
||||
return_value='2.4.0'),\
|
||||
mock.patch("vmware_nsxlib.v3.core_resources.NsxLibTransportZone."
|
||||
"get_host_switch_mode", return_value="ENS"),\
|
||||
mock.patch(
|
||||
"vmware_nsxlib.v3.core_resources.NsxLibLogicalSwitch.get",
|
||||
return_value={'transport_zone_id': 'xxx'}):
|
||||
args = {'port': {'network_id': subnet['subnet']['network_id'],
|
||||
'tenant_id': subnet['subnet']['tenant_id'],
|
||||
'fixed_ips': [{'subnet_id':
|
||||
subnet['subnet']['id']}],
|
||||
psec.PORTSECURITY: False}}
|
||||
port_req = self.new_create_request('ports', args)
|
||||
port = self.deserialize(self.fmt, port_req.get_response(self.api))
|
||||
port_id = port['port']['id']
|
||||
args = {'port': {psec.PORTSECURITY: True}}
|
||||
req = self.new_update_request('ports', args, port_id)
|
||||
res = self.deserialize('json', req.get_response(self.api))
|
||||
# should succeed
|
||||
self.assertTrue(res['port'][psec.PORTSECURITY])
|
||||
|
||||
def test_update_dhcp_port_device_owner(self):
|
||||
cfg.CONF.set_override('native_dhcp_metadata', True, 'nsx_v3')
|
||||
with self.subnet():
|
||||
|
Loading…
Reference in New Issue
Block a user