diff --git a/vmware_nsx/common/config.py b/vmware_nsx/common/config.py index c6415172db..f3e86d24c4 100644 --- a/vmware_nsx/common/config.py +++ b/vmware_nsx/common/config.py @@ -444,6 +444,12 @@ nsx_v3_opts = [ "specifying Transport Zone UUID usable for VLAN " "provider networks, as well as ranges of VLAN " "tags on each available for allocation to networks.")), + cfg.BoolOpt('disable_port_security_for_ens', + default=False, + help=_("When True, port security will be set to False for " + "newly created ENS networks and ports, overriding " + "user settings")), + ] DEFAULT_STATUS_CHECK_INTERVAL = 2000 diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index c8ff55da5c..3f84ea6cf8 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -967,7 +967,11 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, transparent_vlan) physical_net = provider_data['physical_net'] - self._assert_on_ens_with_qos(physical_net, net_data) + 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: @@ -983,9 +987,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, nsx_id = provider_data['physical_net'] else: # Create network on the backend - neutron_net_id = net_data.get('id') or uuidutils.generate_uuid() - # To ensure that the correct tag will be set - net_data['id'] = neutron_net_id # update the network name to indicate the neutron id too. net_name = utils.get_name_and_uuid(net_data['name'] or 'network', neutron_net_id) @@ -1259,12 +1260,19 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, return created_net - def _assert_on_ens_with_qos(self, tz_id, net_data): + def _assert_on_ens_with_qos(self, net_data): qos_id = net_data.get(qos_consts.QOS_POLICY_ID) - if validators.is_attr_set(qos_id) and tz_id and self._is_ens_tz(tz_id): + if validators.is_attr_set(qos_id): 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']) + net_data[psec.PORTSECURITY] = False + def _has_active_port(self, context, network_id): ports_in_use = context.session.query(models_v2.Port).filter_by( network_id=network_id).all() @@ -1367,8 +1375,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, if extern_net: self._assert_on_external_net_with_qos(net_data) else: - self._assert_on_ens_with_qos(self._get_net_tz(context, id), - net_data) + if self._get_net_tz(context, id): + self._assert_on_ens_with_qos(net_data) updated_net = super(NsxV3Plugin, self).update_network(context, id, network) self._extension_manager.process_update_network(context, net_data, @@ -2743,9 +2751,16 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, qos_selected = validators.is_attr_set(port_data.get( qos_consts.QOS_POLICY_ID)) - if is_ens_tz_port and qos_selected: - err_msg = _("Cannot configure QOS on ENS networks") - raise n_exc.InvalidInput(error_message=err_msg) + if is_ens_tz_port: + if qos_selected: + 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: + LOG.warning("Disabling port security for network %s", + port_data['network_id']) + port_data[psec.PORTSECURITY] = False + port_data['security_groups'] = [] # TODO(salv-orlando): Undo logical switch creation on failure with db_api.context_manager.writer.using(context): @@ -3226,9 +3241,10 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, is_ens_tz_port = self._is_ens_tz_port(context, original_port) qos_selected = validators.is_attr_set(port_data.get (qos_consts.QOS_POLICY_ID)) - if is_ens_tz_port and qos_selected: - err_msg = _("Cannot configure QOS on ENS networks") - raise n_exc.InvalidInput(error_message=err_msg) + if is_ens_tz_port: + if qos_selected: + err_msg = _("Cannot configure QOS on ENS networks") + raise n_exc.InvalidInput(error_message=err_msg) dhcp_opts = port_data.get(ext_edo.EXTRADHCPOPTS) self._validate_extra_dhcp_options(dhcp_opts) diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index 77405b6f22..283868b3ab 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -509,6 +509,29 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin): self.assertEqual('NsxENSPortSecurity', res['NeutronError']['type']) + 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') + mock_ens = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_host_switch_mode', return_value='ENS') + mock_tz = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibLogicalSwitch.get', + return_value={'transport_zone_id': 'xxx'}) + mock_tt = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_transport_type', return_value='VLAN') + data = {'network': { + 'name': 'portsec_net', + 'admin_state_up': True, + 'shared': False, + 'tenant_id': 'some_tenant', + 'provider:network_type': 'flat', + 'provider:physical_network': 'xxx', + 'port_security_enabled': True}} + with mock_ens, mock_tz, mock_tt: + self.plugin.create_network(context.get_admin_context(), data) + def test_create_ens_network_with_qos(self): cfg.CONF.set_override('ens_support', True, 'nsx_v3') mock_ens = mock.patch('vmware_nsxlib.v3' @@ -912,6 +935,37 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, self.assertRaises(n_exc.InvalidInput, self.plugin.create_port, self.ctx, data) + def test_create_port_ens_with_sg(self): + cfg.CONF.set_override('disable_port_security_for_ens', True, 'nsx_v3') + with self.network() as network: + with self.subnet(network=network, cidr='10.0.0.0/24'): + mock_ens = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_host_switch_mode', + return_value='ENS') + mock_tz = mock.patch('vmware_nsxlib.v3' + '.core_resources' + '.NsxLibLogicalSwitch.get', + return_value={ + 'transport_zone_id': 'xxx'}) + mock_tt = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_transport_type', + return_value='VLAN') + data = {'port': { + 'network_id': network['network']['id'], + 'tenant_id': self._tenant_id, + 'name': 'sg_port', + 'admin_state_up': True, + 'device_id': 'fake_device', + 'device_owner': 'fake_owner', + 'fixed_ips': [], + 'mac_address': '00:00:00:00:00:01', + 'port_security_enabled': True} + } + with mock_ens, mock_tz, mock_tt: + self.plugin.create_port(self.ctx, data) + def test_update_port_ens_with_qos_fail(self): with self.network() as network: with self.subnet(network=network, cidr='10.0.0.0/24'):