summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/neutron/rootwrap.d/dhcp.filters2
-rw-r--r--etc/neutron/rootwrap.d/l3.filters2
-rw-r--r--neutron/agent/dhcp_agent.py5
-rw-r--r--neutron/agent/securitygroups_rpc.py41
-rw-r--r--neutron/api/rpc/handlers/dhcp_rpc.py8
-rw-r--r--neutron/api/rpc/handlers/securitygroups_rpc.py14
-rw-r--r--neutron/common/ipv6_utils.py7
-rw-r--r--neutron/db/db_base_plugin_v2.py34
-rw-r--r--neutron/db/l3_db.py20
-rw-r--r--neutron/db/l3_hamode_db.py2
-rw-r--r--neutron/db/securitygroups_rpc_base.py53
-rw-r--r--neutron/notifiers/nova.py12
-rw-r--r--neutron/plugins/bigswitch/plugin.py3
-rw-r--r--neutron/plugins/bigswitch/servermanager.py12
-rw-r--r--neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py2
-rw-r--r--neutron/plugins/ml2/db.py72
-rw-r--r--neutron/plugins/ml2/drivers/l2pop/mech_driver.py27
-rw-r--r--neutron/plugins/ml2/drivers/mech_ofagent.py7
-rw-r--r--neutron/plugins/ml2/drivers/mech_openvswitch.py7
-rw-r--r--neutron/plugins/ml2/plugin.py32
-rw-r--r--neutron/plugins/mlnx/common/comm_utils.py3
-rw-r--r--neutron/plugins/nec/nec_plugin.py14
-rw-r--r--neutron/plugins/ryu/ryu_neutron_plugin.py18
-rw-r--r--neutron/plugins/vmware/dbexts/db.py5
-rw-r--r--neutron/plugins/vmware/plugins/base.py12
-rw-r--r--neutron/tests/unit/_test_extension_portbindings.py22
-rw-r--r--neutron/tests/unit/bigswitch/test_servermanager.py12
-rw-r--r--neutron/tests/unit/bigswitch/test_ssl.py4
-rw-r--r--neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py18
-rw-r--r--neutron/tests/unit/db/test_l3_ha_db.py33
-rw-r--r--neutron/tests/unit/ml2/_test_mech_agent.py15
-rw-r--r--neutron/tests/unit/ml2/drivers/test_l2population.py16
-rw-r--r--neutron/tests/unit/ml2/drivers/test_ofagent_mech.py25
-rw-r--r--neutron/tests/unit/ml2/test_mech_openvswitch.py23
-rw-r--r--neutron/tests/unit/ml2/test_security_group.py107
-rw-r--r--neutron/tests/unit/mlnx/test_mlnx_comm_utils.py3
-rw-r--r--neutron/tests/unit/nec/test_portbindings.py6
-rw-r--r--neutron/tests/unit/notifiers/test_notifiers_nova.py17
-rw-r--r--neutron/tests/unit/plumgrid/test_plumgrid_plugin.py1
-rw-r--r--neutron/tests/unit/test_db_plugin.py48
-rw-r--r--neutron/tests/unit/test_dhcp_agent.py15
-rw-r--r--neutron/tests/unit/test_dhcp_rpc.py35
-rw-r--r--neutron/tests/unit/test_security_groups_rpc.py45
-rw-r--r--neutron/tests/unit/vmware/extensions/test_providernet.py9
-rw-r--r--setup.cfg1
45 files changed, 654 insertions, 215 deletions
diff --git a/etc/neutron/rootwrap.d/dhcp.filters b/etc/neutron/rootwrap.d/dhcp.filters
index 26c2ffa86c..7c11d70dbd 100644
--- a/etc/neutron/rootwrap.d/dhcp.filters
+++ b/etc/neutron/rootwrap.d/dhcp.filters
@@ -23,11 +23,9 @@ dhcp_release: CommandFilter, dhcp_release, root
# metadata proxy
metadata_proxy: CommandFilter, neutron-ns-metadata-proxy, root
-metadata_proxy_quantum: CommandFilter, quantum-ns-metadata-proxy, root
# If installed from source (say, by devstack), the prefix will be
# /usr/local instead of /usr/bin.
metadata_proxy_local: CommandFilter, /usr/local/bin/neutron-ns-metadata-proxy, root
-metadata_proxy_local_quantum: CommandFilter, /usr/local/bin/quantum-ns-metadata-proxy, root
# RHEL invocation of the metadata proxy will report /usr/bin/python
kill_metadata: KillFilter, root, python, -9
kill_metadata7: KillFilter, root, python2.7, -9
diff --git a/etc/neutron/rootwrap.d/l3.filters b/etc/neutron/rootwrap.d/l3.filters
index 9a3031822a..d9e4a13c46 100644
--- a/etc/neutron/rootwrap.d/l3.filters
+++ b/etc/neutron/rootwrap.d/l3.filters
@@ -18,11 +18,9 @@ radvd: CommandFilter, radvd, root
# metadata proxy
metadata_proxy: CommandFilter, neutron-ns-metadata-proxy, root
-metadata_proxy_quantum: CommandFilter, quantum-ns-metadata-proxy, root
# If installed from source (say, by devstack), the prefix will be
# /usr/local instead of /usr/bin.
metadata_proxy_local: CommandFilter, /usr/local/bin/neutron-ns-metadata-proxy, root
-metadata_proxy_local_quantum: CommandFilter, /usr/local/bin/quantum-ns-metadata-proxy, root
# RHEL invocation of the metadata proxy will report /usr/bin/python
kill_metadata: KillFilter, root, python, -9
kill_metadata7: KillFilter, root, python2.7, -9
diff --git a/neutron/agent/dhcp_agent.py b/neutron/agent/dhcp_agent.py
index 5a501faa91..c8ea89b021 100644
--- a/neutron/agent/dhcp_agent.py
+++ b/neutron/agent/dhcp_agent.py
@@ -227,9 +227,10 @@ class DhcpAgent(manager.Manager):
self.conf, network)
for subnet in network.subnets:
- if subnet.enable_dhcp and subnet.ip_version == 4:
+ if subnet.enable_dhcp:
if self.call_driver('enable', network):
- if self.conf.use_namespaces and enable_metadata:
+ if (subnet.ip_version == 4 and self.conf.use_namespaces
+ and enable_metadata):
self.enable_isolated_metadata_proxy(network)
enable_metadata = False # Don't trigger twice
self.cache.put(network)
diff --git a/neutron/agent/securitygroups_rpc.py b/neutron/agent/securitygroups_rpc.py
index 17b544502e..3da4d347f0 100644
--- a/neutron/agent/securitygroups_rpc.py
+++ b/neutron/agent/securitygroups_rpc.py
@@ -14,11 +14,14 @@
# under the License.
#
+import functools
+
from oslo.config import cfg
from oslo import messaging
+from neutron.agent import firewall
from neutron.common import topics
-from neutron.openstack.common.gettextutils import _LW
+from neutron.openstack.common.gettextutils import _LI, _LW
from neutron.openstack.common import importutils
from neutron.openstack.common import log as logging
@@ -74,9 +77,9 @@ def _disable_extension(extension, aliases):
def disable_security_group_extension_by_config(aliases):
if not is_firewall_enabled():
- LOG.info(_('Disabled security-group extension.'))
+ LOG.info(_LI('Disabled security-group extension.'))
_disable_extension('security-group', aliases)
- LOG.info(_('Disabled allowed-address-pairs extension.'))
+ LOG.info(_LI('Disabled allowed-address-pairs extension.'))
_disable_extension('allowed-address-pairs', aliases)
@@ -187,10 +190,23 @@ class SecurityGroupAgentRpcMixin(object):
return False
return True
+ def skip_if_noopfirewall_or_firewall_disabled(func):
+ @functools.wraps(func)
+ def decorated_function(self, *args, **kwargs):
+ if (isinstance(self.firewall, firewall.NoopFirewallDriver) or
+ not is_firewall_enabled()):
+ LOG.info(_LI("Skipping method %s as firewall is disabled "
+ "or configured as NoopFirewallDriver."),
+ func.__name__)
+ else:
+ return func(self, *args, **kwargs)
+ return decorated_function
+
+ @skip_if_noopfirewall_or_firewall_disabled
def prepare_devices_filter(self, device_ids):
if not device_ids:
return
- LOG.info(_("Preparing filters for devices %s"), device_ids)
+ LOG.info(_LI("Preparing filters for devices %s"), device_ids)
if self.use_enhanced_rpc:
devices_info = self.plugin_rpc.security_group_info_for_devices(
self.context, list(device_ids))
@@ -220,15 +236,15 @@ class SecurityGroupAgentRpcMixin(object):
remote_sg_id, member_ips)
def security_groups_rule_updated(self, security_groups):
- LOG.info(_("Security group "
- "rule updated %r"), security_groups)
+ LOG.info(_LI("Security group "
+ "rule updated %r"), security_groups)
self._security_group_updated(
security_groups,
'security_groups')
def security_groups_member_updated(self, security_groups):
- LOG.info(_("Security group "
- "member updated %r"), security_groups)
+ LOG.info(_LI("Security group "
+ "member updated %r"), security_groups)
self._security_group_updated(
security_groups,
'security_group_source_groups')
@@ -249,7 +265,7 @@ class SecurityGroupAgentRpcMixin(object):
self.refresh_firewall(devices)
def security_groups_provider_updated(self):
- LOG.info(_("Provider rule updated"))
+ LOG.info(_LI("Provider rule updated"))
if self.defer_refresh_firewall:
# NOTE(salv-orlando): A 'global refresh' might not be
# necessary if the subnet for which the provider rules
@@ -261,7 +277,7 @@ class SecurityGroupAgentRpcMixin(object):
def remove_devices_filter(self, device_ids):
if not device_ids:
return
- LOG.info(_("Remove device filter for %r"), device_ids)
+ LOG.info(_LI("Remove device filter for %r"), device_ids)
with self.firewall.defer_apply():
for device_id in device_ids:
device = self.firewall.ports.get(device_id)
@@ -269,12 +285,13 @@ class SecurityGroupAgentRpcMixin(object):
continue
self.firewall.remove_port_filter(device)
+ @skip_if_noopfirewall_or_firewall_disabled
def refresh_firewall(self, device_ids=None):
- LOG.info(_("Refresh firewall rules"))
+ LOG.info(_LI("Refresh firewall rules"))
if not device_ids:
device_ids = self.firewall.ports.keys()
if not device_ids:
- LOG.info(_("No ports here to refresh firewall"))
+ LOG.info(_LI("No ports here to refresh firewall"))
return
if self.use_enhanced_rpc:
devices_info = self.plugin_rpc.security_group_info_for_devices(
diff --git a/neutron/api/rpc/handlers/dhcp_rpc.py b/neutron/api/rpc/handlers/dhcp_rpc.py
index 56016be708..58317eac4b 100644
--- a/neutron/api/rpc/handlers/dhcp_rpc.py
+++ b/neutron/api/rpc/handlers/dhcp_rpc.py
@@ -60,7 +60,7 @@ class DhcpRpcCallback(n_rpc.RpcCallback):
if action == 'create_port':
return plugin.create_port(context, port)
elif action == 'update_port':
- return plugin.update_port(context, port['id'], port['port'])
+ return plugin.update_port(context, port['id'], port)
else:
msg = _('Unrecognized action')
raise n_exc.Invalid(message=msg)
@@ -282,13 +282,11 @@ class DhcpRpcCallback(n_rpc.RpcCallback):
def update_dhcp_port(self, context, **kwargs):
"""Update the dhcp port."""
host = kwargs.get('host')
- port_id = kwargs.get('port_id')
port = kwargs.get('port')
+ port['id'] = kwargs.get('port_id')
LOG.debug(_('Update dhcp port %(port)s '
'from %(host)s.'),
{'port': port,
'host': host})
plugin = manager.NeutronManager.get_plugin()
- return self._port_action(plugin, context,
- {'id': port_id, 'port': port},
- 'update_port')
+ return self._port_action(plugin, context, port, 'update_port')
diff --git a/neutron/api/rpc/handlers/securitygroups_rpc.py b/neutron/api/rpc/handlers/securitygroups_rpc.py
index 2a748cfbcc..e4a16b2f58 100644
--- a/neutron/api/rpc/handlers/securitygroups_rpc.py
+++ b/neutron/api/rpc/handlers/securitygroups_rpc.py
@@ -36,15 +36,11 @@ class SecurityGroupServerRpcCallback(n_rpc.RpcCallback):
return manager.NeutronManager.get_plugin()
def _get_devices_info(self, devices):
- devices_info = {}
- for device in devices:
- port = self.plugin.get_port_from_device(device)
- if not port:
- continue
- if port['device_owner'].startswith('network:'):
- continue
- devices_info[port['id']] = port
- return devices_info
+ return dict(
+ (port['id'], port)
+ for port in self.plugin.get_ports_from_devices(devices)
+ if port and not port['device_owner'].startswith('network:')
+ )
def security_group_rules_for_devices(self, context, **kwargs):
"""Callback method to return security group rules for each port.
diff --git a/neutron/common/ipv6_utils.py b/neutron/common/ipv6_utils.py
index 96e1ef2344..ec9168ea36 100644
--- a/neutron/common/ipv6_utils.py
+++ b/neutron/common/ipv6_utils.py
@@ -20,6 +20,7 @@ import os
import netaddr
+from neutron.common import constants
from neutron.openstack.common.gettextutils import _LI
from neutron.openstack.common import log
@@ -61,3 +62,9 @@ def is_enabled():
if not _IS_IPV6_ENABLED:
LOG.info(_LI("IPv6 is not enabled on this system."))
return _IS_IPV6_ENABLED
+
+
+def is_slaac_subnet(subnet):
+ """Check if subnet uses SLAAC addressing."""
+ return (subnet['ipv6_address_mode'] == constants.IPV6_SLAAC
+ or subnet['ipv6_address_mode'] == constants.DHCPV6_STATELESS)
diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py
index efb6a61615..70827c58af 100644
--- a/neutron/db/db_base_plugin_v2.py
+++ b/neutron/db/db_base_plugin_v2.py
@@ -177,12 +177,6 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
subnet_id=subnet_id).delete()
@staticmethod
- def _check_if_subnet_uses_eui64(subnet):
- """Check if ipv6 address will be calculated via EUI64."""
- return (subnet['ipv6_address_mode'] == constants.IPV6_SLAAC
- or subnet['ipv6_address_mode'] == constants.DHCPV6_STATELESS)
-
- @staticmethod
def _store_ip_allocation(context, ip_address, network_id, subnet_id,
port_id):
LOG.debug("Allocated IP %(ip_address)s "
@@ -394,7 +388,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
return True
return False
- def _test_fixed_ips_for_port(self, context, network_id, fixed_ips):
+ def _test_fixed_ips_for_port(self, context, network_id, fixed_ips,
+ device_owner):
"""Test fixed IPs for port.
Check that configured subnets are valid prior to allocating any
@@ -449,7 +444,9 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
msg = _('IP address %s is not a valid IP for the defined '
'subnet') % fixed['ip_address']
raise n_exc.InvalidInput(error_message=msg)
- if self._check_if_subnet_uses_eui64(subnet):
+ if (ipv6_utils.is_slaac_subnet(subnet) and device_owner not in
+ (constants.DEVICE_OWNER_ROUTER_INTF,
+ constants.DEVICE_OWNER_DVR_INTERFACE)):
msg = (_("IPv6 address %(address)s can not be directly "
"assigned to a port on subnet %(id)s with "
"%(mode)s address mode") %
@@ -481,7 +478,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
else:
subnet = self._get_subnet(context, fixed['subnet_id'])
if (subnet['ip_version'] == 6 and
- self._check_if_subnet_uses_eui64(subnet)):
+ ipv6_utils.is_slaac_subnet(subnet)):
prefix = subnet['cidr']
ip_address = ipv6_utils.get_ipv6_addr_by_EUI64(
prefix, mac_address)
@@ -496,7 +493,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
return ips
def _update_ips_for_port(self, context, network_id, port_id, original_ips,
- new_ips, mac_address):
+ new_ips, mac_address, device_owner):
"""Add or remove IPs from the port."""
ips = []
# These ips are still on the port and haven't been removed
@@ -517,7 +514,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
prev_ips.append(original_ip)
# Check if the IP's to add are OK
- to_add = self._test_fixed_ips_for_port(context, network_id, new_ips)
+ to_add = self._test_fixed_ips_for_port(context, network_id, new_ips,
+ device_owner)
for ip in original_ips:
LOG.debug(_("Port update. Hold %s"), ip)
NeutronDbPluginV2._delete_ip_allocation(context,
@@ -544,7 +542,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
if fixed_configured:
configured_ips = self._test_fixed_ips_for_port(context,
p["network_id"],
- p['fixed_ips'])
+ p['fixed_ips'],
+ p['device_owner'])
ips = self._allocate_fixed_ips(context,
configured_ips,
p['mac_address'])
@@ -560,7 +559,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
else:
v6.append(subnet)
for subnet in v6:
- if self._check_if_subnet_uses_eui64(subnet):
+ if ipv6_utils.is_slaac_subnet(subnet):
#(dzyu) If true, calculate an IPv6 address
# by mac address and prefix, then remove this
# subnet from the array of subnets that will be passed
@@ -776,7 +775,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
# id together should be equal to 128. Currently neutron supports
# EUI64 interface id only, thus limiting the prefix
# length to be 64 only.
- if self._check_if_subnet_uses_eui64(subnet):
+ if ipv6_utils.is_slaac_subnet(subnet):
if netaddr.IPNetwork(subnet['cidr']).prefixlen != 64:
msg = _('Invalid CIDR %s for IPv6 address mode. '
'OpenStack uses the EUI-64 address format, '
@@ -1084,7 +1083,10 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
s = subnet['subnet']
if s['gateway_ip'] is attributes.ATTR_NOT_SPECIFIED:
- s['gateway_ip'] = str(netaddr.IPAddress(net.first + 1))
+ if s['ip_version'] == 6 and ipv6_utils.is_slaac_subnet(s):
+ s['gateway_ip'] = None
+ else:
+ s['gateway_ip'] = str(netaddr.IPAddress(net.first + 1))
if s['allocation_pools'] == attributes.ATTR_NOT_SPECIFIED:
s['allocation_pools'] = self._allocate_pools_for_subnet(context, s)
@@ -1396,7 +1398,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
added_ips, prev_ips = self._update_ips_for_port(
context, port["network_id"], id,
original["fixed_ips"], p['fixed_ips'],
- original['mac_address'])
+ original['mac_address'], port['device_owner'])
# Update ips if necessary
for ip in added_ips:
diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py
index 0f8a56c0ef..cd4be99253 100644
--- a/neutron/db/l3_db.py
+++ b/neutron/db/l3_db.py
@@ -21,6 +21,7 @@ from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
from neutron.api.v2 import attributes
from neutron.common import constants as l3_constants
from neutron.common import exceptions as n_exc
+from neutron.common import ipv6_utils
from neutron.common import rpc as n_rpc
from neutron.common import utils
from neutron.db import model_base
@@ -169,10 +170,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
return self._make_router_dict(router_db)
def _update_router_db(self, context, router_id, data, gw_info):
- """Update the DB object and related gw info, if available."""
+ """Update the DB object."""
with context.session.begin(subtransactions=True):
- if gw_info != attributes.ATTR_NOT_SPECIFIED:
- self._update_router_gw_info(context, router_id, gw_info)
router_db = self._get_router(context, router_id)
if data:
router_db.update(data)
@@ -188,6 +187,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
if gw_info != attributes.ATTR_NOT_SPECIFIED:
candidates = self._check_router_needs_rescheduling(
context, id, gw_info)
+ # Update the gateway outside of the DB update since it involves L2
+ # calls that don't make sense to rollback and may cause deadlocks
+ # in a transaction.
+ self._update_router_gw_info(context, id, gw_info)
else:
candidates = None
router_db = self._update_router_db(context, id, r, gw_info)
@@ -459,15 +462,20 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase):
def _add_interface_by_subnet(self, context, router, subnet_id, owner):
subnet = self._core_plugin._get_subnet(context, subnet_id)
- if not subnet['gateway_ip']:
+ if (not subnet['gateway_ip']
+ and not ipv6_utils.is_slaac_subnet(subnet)):
msg = _('Subnet for router interface must have a gateway IP')
raise n_exc.BadRequest(resource='router', msg=msg)
self._check_for_dup_router_subnet(context, router,
subnet['network_id'],
subnet_id,
subnet['cidr'])
- fixed_ip = {'ip_address': subnet['gateway_ip'],
- 'subnet_id': subnet['id']}
+ if subnet['gateway_ip']:
+ fixed_ip = {'ip_address': subnet['gateway_ip'],
+ 'subnet_id': subnet['id']}
+ else:
+ fixed_ip = {'subnet_id': subnet['id']}
+
return self._core_plugin.create_port(context, {
'port':
{'tenant_id': subnet['tenant_id'],
diff --git a/neutron/db/l3_hamode_db.py b/neutron/db/l3_hamode_db.py
index a0ed580850..94897dbc83 100644
--- a/neutron/db/l3_hamode_db.py
+++ b/neutron/db/l3_hamode_db.py
@@ -224,7 +224,7 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin):
'shared': False,
'admin_state_up': True,
'status': constants.NET_STATUS_ACTIVE}}
- network = self._core_plugin.create_network(context, args)
+ network = self._core_plugin.create_network(admin_ctx, args)
try:
ha_network = self._create_ha_network_tenant_binding(admin_ctx,
tenant_id,
diff --git a/neutron/db/securitygroups_rpc_base.py b/neutron/db/securitygroups_rpc_base.py
index 2f6606ad56..2f6e2b7fdb 100644
--- a/neutron/db/securitygroups_rpc_base.py
+++ b/neutron/db/securitygroups_rpc_base.py
@@ -19,6 +19,7 @@ from sqlalchemy.orm import exc
from neutron.common import constants as q_const
from neutron.common import ipv6_utils as ipv6
from neutron.common import utils
+from neutron.db import allowedaddresspairs_db as addr_pair
from neutron.db import models_v2
from neutron.db import securitygroups_db as sg_db
from neutron.extensions import securitygroup as ext_sg
@@ -39,7 +40,7 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin):
def get_port_from_device(self, device):
"""Get port dict from device name on an agent.
- Subclass must provide this method.
+ Subclass must provide this method or get_ports_from_devices.
:param device: device name which identifies a port on the agent side.
What is specified in "device" depends on a plugin agent implementation.
@@ -53,9 +54,18 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin):
- security_group_source_groups
- fixed_ips
"""
- raise NotImplementedError(_("%s must implement get_port_from_device.")
+ raise NotImplementedError(_("%s must implement get_port_from_device "
+ "or get_ports_from_devices.")
% self.__class__.__name__)
+ def get_ports_from_devices(self, devices):
+ """Bulk method of get_port_from_device.
+
+ Subclasses may override this to provide better performance for DB
+ queries, backend calls, etc.
+ """
+ return [self.get_port_from_device(device) for device in devices]
+
def create_security_group_rule(self, context, security_group_rule):
bulk_rule = {'security_group_rules': [security_group_rule]}
rule = self.create_security_group_rule_bulk_native(context,
@@ -230,27 +240,32 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin):
if not remote_group_ids:
return ips_by_group
for remote_group_id in remote_group_ids:
- ips_by_group[remote_group_id] = []
+ ips_by_group[remote_group_id] = set()
ip_port = models_v2.IPAllocation.port_id
sg_binding_port = sg_db.SecurityGroupPortBinding.port_id
sg_binding_sgid = sg_db.SecurityGroupPortBinding.security_group_id
+ # Join the security group binding table directly to the IP allocation
+ # table instead of via the Port table skip an unnecessary intermediary
query = context.session.query(sg_binding_sgid,
- models_v2.Port,
- models_v2.IPAllocation.ip_address)
+ models_v2.IPAllocation.ip_address,
+ addr_pair.AllowedAddressPair.ip_address)
query = query.join(models_v2.IPAllocation,
ip_port == sg_binding_port)
- query = query.join(models_v2.Port,
- ip_port == models_v2.Port.id)
+ # Outerjoin because address pairs may be null and we still want the
+ # IP for the port.
+ query = query.outerjoin(
+ addr_pair.AllowedAddressPair,
+ sg_binding_port == addr_pair.AllowedAddressPair.port_id)
query = query.filter(sg_binding_sgid.in_(remote_group_ids))
- for security_group_id, port, ip_address in query:
- ips_by_group[security_group_id].append(ip_address)
- # if there are allowed_address_pairs add them
- if getattr(port, 'allowed_address_pairs', None):
- for address_pair in port.allowed_address_pairs:
- ips_by_group[security_group_id].append(
- address_pair['ip_address'])
+ # Each allowed address pair IP record for a port beyond the 1st
+ # will have a duplicate regular IP in the query response since
+ # the relationship is 1-to-many. Dedup with a set
+ for security_group_id, ip_address, allowed_addr_ip in query:
+ ips_by_group[security_group_id].add(ip_address)
+ if allowed_addr_ip:
+ ips_by_group[security_group_id].add(allowed_addr_ip)
return ips_by_group
def _select_remote_group_ids(self, ports):
@@ -268,7 +283,8 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin):
def _select_dhcp_ips_for_network_ids(self, context, network_ids):
if not network_ids:
return {}
- query = context.session.query(models_v2.Port,
+ query = context.session.query(models_v2.Port.mac_address,
+ models_v2.Port.network_id,
models_v2.IPAllocation.ip_address)
query = query.join(models_v2.IPAllocation)
query = query.filter(models_v2.Port.network_id.in_(network_ids))
@@ -279,14 +295,13 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin):
for network_id in network_ids:
ips[network_id] = []
- for port, ip in query:
+ for mac_address, network_id, ip in query:
if (netaddr.IPAddress(ip).version == 6
and not netaddr.IPAddress(ip).is_link_local()):
- mac_address = port['mac_address']
ip = str(ipv6.get_ipv6_addr_by_EUI64(q_const.IPV6_LLA_PREFIX,
mac_address))
- if ip not in ips[port['network_id']]:
- ips[port['network_id']].append(ip)
+ if ip not in ips[network_id]:
+ ips[network_id].append(ip)
return ips
diff --git a/neutron/notifiers/nova.py b/neutron/notifiers/nova.py
index aa4f1b53e1..1db6bc097e 100644
--- a/neutron/notifiers/nova.py
+++ b/neutron/notifiers/nova.py
@@ -128,6 +128,18 @@ class Notifier(object):
if not cfg.CONF.notify_nova_on_port_data_changes:
return
+ # When neutron re-assigns floating ip from an original instance
+ # port to a new instance port without disassociate it first, an
+ # event should be sent for original instance, that will make nova
+ # know original instance's info, and update database for it.
+ if (action == 'update_floatingip'
+ and returned_obj['floatingip'].get('port_id')
+ and original_obj.get('port_id')):
+ disassociate_returned_obj = {'floatingip': {'port_id': None}}
+ event = self.create_port_changed_event(action, original_obj,
+ disassociate_returned_obj)
+ self.queue_event(event)
+
event = self.create_port_changed_event(action, original_obj,
returned_obj)
self.queue_event(event)
diff --git a/neutron/plugins/bigswitch/plugin.py b/neutron/plugins/bigswitch/plugin.py
index e2e051d751..b52dd3bf5e 100644
--- a/neutron/plugins/bigswitch/plugin.py
+++ b/neutron/plugins/bigswitch/plugin.py
@@ -365,11 +365,12 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
cfg_vif_type = override
port[portbindings.VIF_TYPE] = cfg_vif_type
+ sg_enabled = sg_rpc.is_firewall_enabled()
port[portbindings.VIF_DETAILS] = {
# TODO(rkukura): Replace with new VIF security details
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases,
- portbindings.OVS_HYBRID_PLUG: True
+ portbindings.OVS_HYBRID_PLUG: sg_enabled
}
return port
diff --git a/neutron/plugins/bigswitch/servermanager.py b/neutron/plugins/bigswitch/servermanager.py
index 0a86ff4374..c10ce72bb5 100644
--- a/neutron/plugins/bigswitch/servermanager.py
+++ b/neutron/plugins/bigswitch/servermanager.py
@@ -383,7 +383,8 @@ class ServerPool(object):
a given path.
'''
try:
- cert = ssl.get_server_certificate((server, port))
+ cert = ssl.get_server_certificate((server, port),
+ ssl_version=ssl.PROTOCOL_TLSv1)
except Exception as e:
raise cfg.Error(_('Could not retrieve initial '
'certificate from controller %(server)s. '
@@ -637,8 +638,9 @@ class HTTPSConnectionWithValidation(httplib.HTTPSConnection):
if self.combined_cert:
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=ssl.CERT_REQUIRED,
- ca_certs=self.combined_cert)
+ ca_certs=self.combined_cert,
+ ssl_version=ssl.PROTOCOL_TLSv1)
else:
- self.sock = ssl.wrap_socket(sock, self.key_file,
- self.cert_file,
- cert_reqs=ssl.CERT_NONE)
+ self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
+ cert_reqs=ssl.CERT_NONE,
+ ssl_version=ssl.PROTOCOL_TLSv1)
diff --git a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py b/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py
index 236822d217..16c53660f5 100644
--- a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py
+++ b/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py
@@ -847,8 +847,6 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
LOG.debug(_('_send_delete_port_request: %s'), port['id'])
n1kvclient = n1kv_client.Client()
n1kvclient.delete_n1kv_port(vm_network['name'], port['id'])
- if vm_network['port_count'] == 0:
- n1kvclient.delete_vm_network(vm_network['name'])
def _get_segmentation_id(self, context, id):
"""
diff --git a/neutron/plugins/ml2/db.py b/neutron/plugins/ml2/db.py
index d8caa9384a..40e1c22e52 100644
--- a/neutron/plugins/ml2/db.py
+++ b/neutron/plugins/ml2/db.py
@@ -13,6 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
+
+from sqlalchemy import or_
from sqlalchemy.orm import exc
from oslo.db import exception as db_exc
@@ -30,6 +33,9 @@ from neutron.plugins.ml2 import models
LOG = log.getLogger(__name__)
+# limit the number of port OR LIKE statements in one query
+MAX_PORTS_PER_QUERY = 500
+
def _make_segment_dict(record):
"""Make a segment dictionary out of a DB record."""
@@ -206,32 +212,64 @@ def get_port_from_device_mac(device_mac):
return qry.first()
-def get_port_and_sgs(port_id):
- """Get port from database with security group info."""
+def get_ports_and_sgs(port_ids):
+ """Get ports from database with security group info."""
+
+ # break large queries into smaller parts
+ if len(port_ids) > MAX_PORTS_PER_QUERY:
+ LOG.debug("Number of ports %(pcount)s exceeds the maximum per "
+ "query %(maxp)s. Partitioning queries.",
+ {'pcount': len(port_ids), 'maxp': MAX_PORTS_PER_QUERY})
+ return (get_ports_and_sgs(port_ids[:MAX_PORTS_PER_QUERY]) +
+ get_ports_and_sgs(port_ids[MAX_PORTS_PER_QUERY:]))
+
+ LOG.debug("get_ports_and_sgs() called for port_ids %s", port_ids)
- LOG.debug(_("get_port_and_sgs() called for port_id %s"), port_id)
+ if not port_ids:
+ # if port_ids is empty, avoid querying to DB to ask it for nothing
+ return []
+ ports_to_sg_ids = get_sg_ids_grouped_by_port(port_ids)
+ return [make_port_dict_with_security_groups(port, sec_groups)
+ for port, sec_groups in ports_to_sg_ids.iteritems()]
+
+
+def get_sg_ids_grouped_by_port(port_ids):
+ sg_ids_grouped_by_port = collections.defaultdict(list)
session = db_api.get_session()
sg_binding_port = sg_db.SecurityGroupPortBinding.port_id
with session.begin(subtransactions=True):
+ # partial UUIDs must be individually matched with startswith.
+ # full UUIDs may be matched directly in an IN statement
+ partial_uuids = set(port_id for port_id in port_ids
+ if not uuidutils.is_uuid_like(port_id))
+ full_uuids = set(port_ids) - partial_uuids
+ or_criteria = [models_v2.Port.id.startswith(port_id)
+ for port_id in partial_uuids]
+ if full_uuids:
+ or_criteria.append(models_v2.Port.id.in_(full_uuids))
+
query = session.query(models_v2.Port,
sg_db.SecurityGroupPortBinding.security_group_id)
query = query.outerjoin(sg_db.SecurityGroupPortBinding,
models_v2.Port.id == sg_binding_port)
- query = query.filter(models_v2.Port.id.startswith(port_id))
- port_and_sgs = query.all()
- if not port_and_sgs:
- return
- port = port_and_sgs[0][0]
- plugin = manager.NeutronManager.get_plugin()
- port_dict = plugin._make_port_dict(port)
- port_dict['security_groups'] = [
- sg_id for port_, sg_id in port_and_sgs if sg_id]
- port_dict['security_group_rules'] = []
- port_dict['security_group_source_groups'] = []
- port_dict['fixed_ips'] = [ip['ip_address']
- for ip in port['fixed_ips']]
- return port_dict
+ query = query.filter(or_(*or_criteria))
+
+ for port, sg_id in query:
+ if sg_id:
+ sg_ids_grouped_by_port[port].append(sg_id)
+ return sg_ids_grouped_by_port
+
+
+def make_port_dict_with_security_groups(port, sec_groups):
+ plugin = manager.NeutronManager.get_plugin()
+ port_dict = plugin._make_port_dict(port)
+ port_dict['security_groups'] = sec_groups
+ port_dict['security_group_rules'] = []
+ port_dict['security_group_source_groups'] = []
+ port_dict['fixed_ips'] = [ip['ip_address']
+ for ip in port['fixed_ips']]
+ return port_dict
def get_port_binding_host(port_id):
diff --git a/neutron/plugins/ml2/drivers/l2pop/mech_driver.py b/neutron/plugins/ml2/drivers/l2pop/mech_driver.py
index a98a27fd7d..c85acb1c73 100644
--- a/neutron/plugins/ml2/drivers/l2pop/mech_driver.py
+++ b/neutron/plugins/ml2/drivers/l2pop/mech_driver.py
@@ -38,32 +38,18 @@ class L2populationMechanismDriver(api.MechanismDriver,
LOG.debug(_("Experimental L2 population driver"))
self.rpc_ctx = n_context.get_admin_context_without_session()
self.migrated_ports = {}
- self.remove_fdb_entries = {}
def _get_port_fdb_entries(self, port):
return [[port['mac_address'],
ip['ip_address']] for ip in port['fixed_ips']]
- def delete_port_precommit(self, context):
- port = context.current
- agent_host = context.host
-
- if port['id'] not in self.remove_fdb_entries:
- self.remove_fdb_entries[port['id']] = {}
-
- self.remove_fdb_entries[port['id']][agent_host] = (
- self._update_port_down(context, port, agent_host, 1))
-
def delete_port_postcommit(self, context):
port = context.current
agent_host = context.host
- if port['id'] in self.remove_fdb_entries:
- for agent_host in list(self.remove_fdb_entries[port['id']]):
- self.L2populationAgentNotify.remove_fdb_entries(
- self.rpc_ctx,
- self.remove_fdb_entries[port['id']][agent_host])
- self.remove_fdb_entries[port['id']].pop(agent_host, 0)
- self.remove_fdb_entries.pop(port['id'], 0)
+
+ fdb_entries = self._update_port_down(context, port, agent_host)
+ self.L2populationAgentNotify.remove_fdb_entries(self.rpc_ctx,
+ fdb_entries)
def _get_diff_ips(self, orig, port):
orig_ips = set([ip['ip_address'] for ip in orig['fixed_ips']])
@@ -260,8 +246,7 @@ class L2populationMechanismDriver(api.MechanismDriver,
self.L2populationAgentNotify.add_fdb_entries(self.rpc_ctx,
other_fdb_entries)
- def _update_port_down(self, context, port, agent_host,
- agent_active_ports_count_for_flooding=0):
+ def _update_port_down(self, context, port, agent_host):
port_infos = self._get_port_infos(context, port, agent_host)
if not port_infos:
return
@@ -277,7 +262,7 @@ class L2populationMechanismDriver(api.MechanismDriver,
{'segment_id': segment['segmentation_id'],
'network_type': segment['network_type'],
'ports': {agent_ip: []}}}
- if agent_active_ports == agent_active_ports_count_for_flooding:
+ if agent_active_ports == 0:
# Agent is removing its last activated port in this network,
# other agents needs to be notified to delete their flooding entry.
other_fdb_entries[network_id]['ports'][agent_ip].append(
diff --git a/neutron/plugins/ml2/drivers/mech_ofagent.py b/neutron/plugins/ml2/drivers/mech_ofagent.py
index 012800183f..3b7b7e27ed 100644
--- a/neutron/plugins/ml2/drivers/mech_ofagent.py
+++ b/neutron/plugins/ml2/drivers/mech_ofagent.py
@@ -19,6 +19,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from neutron.agent import securitygroups_rpc
from neutron.common import constants
from neutron.extensions import portbindings
from neutron.openstack.common import log
@@ -40,11 +41,13 @@ class OfagentMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
"""
def __init__(self):
+ sg_enabled = securitygroups_rpc.is_firewall_enabled()
+ vif_details = {portbindings.CAP_PORT_FILTER: sg_enabled,
+ portbindings.OVS_HYBRID_PLUG: sg_enabled}
super(OfagentMechanismDriver, self).__init__(
constants.AGENT_TYPE_OFA,
portbindings.VIF_TYPE_OVS,
- {portbindings.CAP_PORT_FILTER: True,
- portbindings.OVS_HYBRID_PLUG: True})
+ vif_details)
def check_segment_for_agent(self, segment, agent):
bridge_mappings = agent['configurations'].get('bridge_mappings', {})
diff --git a/neutron/plugins/ml2/drivers/mech_openvswitch.py b/neutron/plugins/ml2/drivers/mech_openvswitch.py
index 0565b97301..995abb6632 100644
--- a/neutron/plugins/ml2/drivers/mech_openvswitch.py
+++ b/neutron/plugins/ml2/drivers/mech_openvswitch.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from neutron.agent import securitygroups_rpc
from neutron.common import constants
from neutron.extensions import portbindings
from neutron.openstack.common import log
@@ -33,11 +34,13 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
"""
def __init__(self):
+ sg_enabled = securitygroups_rpc.is_firewall_enabled()
+ vif_details = {portbindings.CAP_PORT_FILTER: sg_enabled,
+ portbindings.OVS_HYBRID_PLUG: sg_enabled}
super(OpenvswitchMechanismDriver, self).__init__(
constants.AGENT_TYPE_OVS,
portbindings.VIF_TYPE_OVS,
- {portbindings.CAP_PORT_FILTER: True,
- portbindings.OVS_HYBRID_PLUG: True})
+ vif_details)
def check_segment_for_agent(self, segment, agent):
mappings = agent['configurations'].get('bridge_mappings', {})
diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py
index d744f19fe1..d29deda6ce 100644
--- a/neutron/plugins/ml2/plugin.py
+++ b/neutron/plugins/ml2/plugin.py
@@ -990,7 +990,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
port = self._make_port_dict(port_db)
network = self.get_network(context, port['network_id'])
- mech_context = None
+ bound_mech_contexts = []
device_owner = port['device_owner']
if device_owner == const.DEVICE_OWNER_DVR_INTERFACE:
bindings = db.get_dvr_port_bindings(context.session, id)
@@ -998,6 +998,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
mech_context = driver_context.DvrPortContext(
self, context, port, network, bind)
self.mechanism_manager.delete_port_precommit(mech_context)
+ bound_mech_contexts.append(mech_context)
else:
mech_context = driver_context.PortContext(self, context, port,
network, binding)
@@ -1005,6 +1006,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
router_info = l3plugin.dvr_deletens_if_no_port(context, id)
removed_routers += router_info
self.mechanism_manager.delete_port_precommit(mech_context)
+ bound_mech_contexts.append(mech_context)
self._delete_port_security_group_bindings(context, id)
if l3plugin:
router_ids = l3plugin.disassociate_floatingips(
@@ -1029,12 +1031,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
{'id': router['router_id'],
'agent': router['agent_id']})
try:
- # for both normal and DVR Interface ports, only one invocation of
- # delete_port_postcommit. We use gather/scatter technique for DVR
- # interface ports, where the bindings are gathered in
- # delete_port_precommit() call earlier and scattered as l2pop
- # rules to cloud nodes in delete_port_postcommit() here
- if mech_context:
+ # Note that DVR Interface ports will have bindings on
+ # multiple hosts, and so will have multiple mech_contexts,
+ # while other ports typically have just one.
+ for mech_context in bound_mech_contexts:
self.mechanism_manager.delete_port_postcommit(mech_context)
except ml2_exc.MechanismDriverError:
# TODO(apech) - One or more mechanism driver failed to
@@ -1156,12 +1156,18 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
port_host = db.get_port_binding_host(port_id)
return (port_host == host)
- def get_port_from_device(self, device):
- port_id = self._device_to_port_id(device)
- port = db.get_port_and_sgs(port_id)
- if port:
- port['device'] = device
- return port
+ def get_ports_from_devices(self, devices):
+ port_ids_to_devices = dict((self._device_to_port_id(device), device)
+ for device in devices)
+ port_ids = port_ids_to_devices.keys()
+ ports = db.get_ports_and_sgs(port_ids)
+ for port in ports:
+ # map back to original requested id
+ port_id = next((port_id for port_id in port_ids
+ if port['id'].startswith(port_id)), None)
+ port['device'] = port_ids_to_devices.get(port_id)
+
+ return ports
def _device_to_port_id(self, device):
# REVISIT(rkukura): Consider calling into MechanismDrivers to
diff --git a/neutron/plugins/mlnx/common/comm_utils.py b/neutron/plugins/mlnx/common/comm_utils.py
index 834b5a2cb1..f426908f28 100644
--- a/neutron/plugins/mlnx/common/comm_utils.py
+++ b/neutron/plugins/mlnx/common/comm_utils.py
@@ -35,7 +35,6 @@ class RetryDecorator(object):
:param retries: number of times to try before giving up
:raises: exceptionToCheck
"""
- sleep_fn = time.sleep
def __init__(self, exceptionToCheck,
interval=cfg.CONF.ESWITCH.request_timeout / 1000,
@@ -56,7 +55,7 @@ class RetryDecorator(object):
except self.exc:
LOG.debug(_("Request timeout - call again after "
"%s seconds"), sleep_interval)
- RetryDecorator.sleep_fn(sleep_interval)
+ time.sleep(sleep_interval)
num_of_iter -= 1
sleep_interval *= self.backoff_rate
diff --git a/neutron/plugins/nec/nec_plugin.py b/neutron/plugins/nec/nec_plugin.py
index 7d26b1b59b..373dfdf24f 100644
--- a/neutron/plugins/nec/nec_plugin.py
+++ b/neutron/plugins/nec/nec_plugin.py
@@ -421,15 +421,11 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
self._cleanup_ofc_tenant(context, tenant_id)
def _get_base_binding_dict(self):
- binding = {
- portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
- portbindings.VIF_DETAILS: {
- # TODO(rkukura): Replace with new VIF security details
- portbindings.CAP_PORT_FILTER:
- 'security-group' in self.supported_extension_aliases,
- portbindings.OVS_HYBRID_PLUG: True
- }
- }
+ sg_enabled = sg_rpc.is_firewall_enabled()
+ vif_details = {portbindings.CAP_PORT_FILTER: sg_enabled,
+ portbindings.OVS_HYBRID_PLUG: sg_enabled}
+ binding = {portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
+ portbindings.VIF_DETAILS: vif_details}
return binding
def _extend_port_dict_binding_portinfo(self, port_res, portinfo):
diff --git a/neutron/plugins/ryu/ryu_neutron_plugin.py b/neutron/plugins/ryu/ryu_neutron_plugin.py
index 8a18228362..c387518f8a 100644
--- a/neutron/plugins/ryu/ryu_neutron_plugin.py
+++ b/neutron/plugins/ryu/ryu_neutron_plugin.py
@@ -107,15 +107,7 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
def __init__(self, configfile=None):
super(RyuNeutronPluginV2, self).__init__()
- self.base_binding_dict = {
- portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
- portbindings.VIF_DETAILS: {
- # TODO(rkukura): Replace with new VIF security details
- portbindings.CAP_PORT_FILTER:
- 'security-group' in self.supported_extension_aliases,
- portbindings.OVS_HYBRID_PLUG: True
- }
- }
+ self.base_binding_dict = self._get_base_binding_dict()
portbindings_base.register_port_dict_function()
self.tunnel_key = db_api_v2.TunnelKey(
cfg.CONF.OVS.tunnel_key_min, cfg.CONF.OVS.tunnel_key_max)
@@ -134,6 +126,14 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
# register known all network list on startup
self._create_all_tenant_network()
+ def _get_base_binding_dict(self):
+ sg_enabled = sg_rpc.is_firewall_enabled()
+ vif_details = {portbindings.CAP_PORT_FILTER: sg_enabled,
+ portbindings.OVS_HYBRID_PLUG: sg_enabled}
+ binding = {portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
+ portbindings.VIF_DETAILS: vif_details}
+ return binding
+
def _setup_rpc(self):
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
diff --git a/neutron/plugins/vmware/dbexts/db.py b/neutron/plugins/vmware/dbexts/db.py
index 6326460046..37dd6a77f7 100644
--- a/neutron/plugins/vmware/dbexts/db.py
+++ b/neutron/plugins/vmware/dbexts/db.py
@@ -33,10 +33,11 @@ def get_network_bindings(session, network_id):
all())
-def get_network_bindings_by_vlanid(session, vlan_id):
+def get_network_bindings_by_vlanid_and_physical_net(session, vlan_id,
+ phy_uuid):
session = session or db.get_session()
return (session.query(models.TzNetworkBinding).
- filter_by(vlan_id=vlan_id).
+ filter_by(vlan_id=vlan_id, phy_uuid=phy_uuid).
all())
diff --git a/neutron/plugins/vmware/plugins/base.py b/neutron/plugins/vmware/plugins/base.py
index 3797891771..773e8b818e 100644
--- a/neutron/plugins/vmware/plugins/base.py
+++ b/neutron/plugins/vmware/plugins/base.py
@@ -756,10 +756,15 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
for segment in segments:
network_type = segment.get(pnet.NETWORK_TYPE)
physical_network = segment.get(pnet.PHYSICAL_NETWORK)
+ physical_network_set = attr.is_attr_set(physical_network)
segmentation_id = segment.get(pnet.SEGMENTATION_ID)
network_type_set = attr.is_attr_set(network_type)
segmentation_id_set = attr.is_attr_set(segmentation_id)
+ # If the physical_network_uuid isn't passed in use the default one.
+ if not physical_network_set:
+ physical_network = cfg.CONF.default_tz_uuid
+
err_msg = None
if not network_type_set:
err_msg = _("%s required") % pnet.NETWORK_TYPE
@@ -782,8 +787,11 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'max_id': constants.MAX_VLAN_TAG})
else:
# Verify segment is not already allocated
- bindings = nsx_db.get_network_bindings_by_vlanid(
- context.session, segmentation_id)
+ bindings = (
+ nsx_db.get_network_bindings_by_vlanid_and_physical_net(
+ context.session, segmentation_id,
+ physical_network)
+ )
if bindings:
raise n_exc.VlanIdInUse(
vlan_id=segmentation_id,
diff --git a/neutron/tests/unit/_test_extension_portbindings.py b/neutron/tests/unit/_test_extension_portbindings.py
index 4f72f58664..54e4c67d71 100644
--- a/neutron/tests/unit/_test_extension_portbindings.py
+++ b/neutron/tests/unit/_test_extension_portbindings.py
@@ -29,19 +29,27 @@ class PortBindingsTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
# VIF_TYPE must be overridden according to plugin vif_type
VIF_TYPE = portbindings.VIF_TYPE_OTHER
- # The plugin supports the port security feature such as
- # security groups and anti spoofing.
- HAS_PORT_FILTER = False
+ # VIF_DETAILS must be overridden according to plugin vif_details
+ VIF_DETAILS = None
def _check_response_portbindings(self, port):
self.assertEqual(port[portbindings.VIF_TYPE], self.VIF_TYPE)
- vif_details = port[portbindings.VIF_DETAILS]
# REVISIT(rkukura): Consider reworking tests to enable ML2 to bind
+
if self.VIF_TYPE not in [portbindings.VIF_TYPE_UNBOUND,
portbindings.VIF_TYPE_BINDING_FAILED]:
- # TODO(rkukura): Replace with new VIF security details
- self.assertEqual(vif_details[portbindings.CAP_PORT_FILTER],
- self.HAS_PORT_FILTER)
+ # NOTE(r-mibu): The following six lines are just for backward
+ # compatibility. In this class, HAS_PORT_FILTER has been replaced
+ # by VIF_DETAILS which can be set expected vif_details to check,
+ # but all replacement of HAS_PORT_FILTER in successor has not been
+ # completed.
+ if self.VIF_DETAILS is None:
+ expected = getattr(self, 'HAS_PORT_FILTER', False)
+ vif_details = port[portbindings.VIF_DETAILS]
+ port_filter = vif_details[portbindings.CAP_PORT_FILTER]
+ self.assertEqual(expected, port_filter)
+ return
+ self.assertEqual(self.VIF_DETAILS, port[portbindings.VIF_DETAILS])
def _check_response_no_portbindings(self, port):
self.assertIn('status', port)
diff --git a/neutron/tests/unit/bigswitch/test_servermanager.py b/neutron/tests/unit/bigswitch/test_servermanager.py
index 43723fe8f9..e8d15efa3b 100644
--- a/neutron/tests/unit/bigswitch/test_servermanager.py
+++ b/neutron/tests/unit/bigswitch/test_servermanager.py
@@ -71,7 +71,8 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
pl.servers._get_combined_cert_for_server,
*('example.org', 443)
)
- sslgetmock.assert_has_calls([mock.call(('example.org', 443))])
+ sslgetmock.assert_has_calls([mock.call(
+ ('example.org', 443), ssl_version=ssl.PROTOCOL_TLSv1)])
def test_consistency_watchdog_stops_with_0_polling_interval(self):
pl = manager.NeutronManager.get_plugin()
@@ -465,7 +466,8 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
('www.example.org', 443), 90, '127.0.0.1'
)])
self.wrap_mock.assert_has_calls([mock.call(
- self.socket_mock(), None, None, cert_reqs=ssl.CERT_NONE
+ self.socket_mock(), None, None, cert_reqs=ssl.CERT_NONE,
+ ssl_version=ssl.PROTOCOL_TLSv1
)])
self.assertEqual(con.sock, self.wrap_mock())
@@ -480,7 +482,8 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
)])
self.wrap_mock.assert_has_calls([mock.call(
self.socket_mock(), None, None, ca_certs='SOMECERTS.pem',
- cert_reqs=ssl.CERT_REQUIRED
+ cert_reqs=ssl.CERT_REQUIRED,
+ ssl_version=ssl.PROTOCOL_TLSv1
)])
self.assertEqual(con.sock, self.wrap_mock())
@@ -500,7 +503,8 @@ class ServerManagerTests(test_rp.BigSwitchProxyPluginV2TestCase):
('www.example.org', 443), 90, '127.0.0.1'
)])
self.wrap_mock.assert_has_calls([mock.call(
- self.socket_mock(), None, None, cert_reqs=ssl.CERT_NONE
+ self.socket_mock(), None, None, cert_reqs=ssl.CERT_NONE,
+ ssl_version=ssl.PROTOCOL_TLSv1
)])
# _tunnel() doesn't take any args
tunnel_mock.assert_has_calls([mock.call()])
diff --git a/neutron/tests/unit/bigswitch/test_ssl.py b/neutron/tests/unit/bigswitch/test_ssl.py
index 6a30744236..f921a4165e 100644
--- a/neutron/tests/unit/bigswitch/test_ssl.py
+++ b/neutron/tests/unit/bigswitch/test_ssl.py
@@ -13,6 +13,7 @@
# under the License.
import contextlib
import os
+import ssl
import mock
from oslo.config import cfg
@@ -106,7 +107,8 @@ class TestSslSticky(test_ssl_certificate_base):
self.getcacerts_m.assert_has_calls([mock.call(self.ca_certs_path)])
# cert should have been fetched via SSL lib
self.sslgetcert_m.assert_has_calls(
- [mock.call((self.servername, 443))]
+ [mock.call((self.servername, 443),
+ ssl_version=ssl.PROTOCOL_TLSv1)]
)
# cert should have been recorded
diff --git a/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py b/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py
index e412dfc7e6..0a64ba1090 100644
--- a/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py
+++ b/neutron/tests/unit/cisco/n1kv/test_n1kv_plugin.py
@@ -793,6 +793,24 @@ class TestN1kvPorts(test_plugin.TestPortsV2,
# for network object clean up to succeed.
client_patch.stop()
+ def test_delete_last_port_vmnetwork_cleanup(self):
+ """Test whether VMNetwork is cleaned up from db on last port delete."""
+ db_session = db.get_session()
+ with self.port() as port:
+ pt = port['port']
+ self.assertIsNotNone(n1kv_db_v2.
+ get_vm_network(db_session,
+ pt['n1kv:profile_id'],
+ pt['network_id']))
+ req = self.new_delete_request('ports', port['port']['id'])
+ req.get_response(self.api)
+ # Verify VMNetwork is cleaned up from the database on port delete.
+ self.assertRaises(c_exc.VMNetworkNotFound,
+ n1kv_db_v2.get_vm_network,
+ db_session,
+ pt['n1kv:profile_id'],
+ pt['network_id'])
+
class TestN1kvPolicyProfiles(N1kvPluginTestCase):
def setUp(self):
diff --git a/neutron/tests/unit/db/test_l3_ha_db.py b/neutron/tests/unit/db/test_l3_ha_db.py
index 4616612bbd..ca2ce82e86 100644
--- a/neutron/tests/unit/db/test_l3_ha_db.py
+++ b/neutron/tests/unit/db/test_l3_ha_db.py
@@ -54,19 +54,25 @@ class L3HATestFramework(testlib_api.SqlTestCase,
self.notif_m = notif_p.start()
cfg.CONF.set_override('allow_overlapping_ips', True)
- def _create_router(self, ha=True, tenant_id='tenant1', distributed=None):
+ def _create_router(self, ha=True, tenant_id='tenant1', distributed=None,
+ ctx=None):
+ if ctx is None:
+ ctx = self.admin_ctx
+ ctx.tenant_id = tenant_id
router = {'name': 'router1', 'admin_state_up': True}
if ha is not None:
router['ha'] = ha
if distributed is not None:
router['distributed'] = distributed
- return self.plugin._create_router_db(self.admin_ctx, router, tenant_id)
+ return self.plugin._create_router_db(ctx, router, tenant_id)
- def _update_router(self, router_id, ha=True, distributed=None):
+ def _update_router(self, router_id, ha=True, distributed=None, ctx=None):
+ if ctx is None:
+ ctx = self.admin_ctx
data = {'ha': ha} if ha is not None else {}
if distributed is not None:
data['distributed'] = distributed
- return self.plugin._update_router_db(self.admin_ctx, router_id,
+ return self.plugin._update_router_db(ctx, router_id,
data, None)
@@ -388,3 +394,22 @@ class L3HATestCase(L3HATestFramework):
routers_after = self.plugin.get_routers(self.admin_ctx)
self.assertEqual(routers_before, routers_after)
+
+
+class L3HAUserTestCase(L3HATestFramework):
+
+ def setUp(self):
+ super(L3HAUserTestCase, self).setUp()
+ self.user_ctx = context.Context('', _uuid())
+ self.plugin = FakeL3Plugin()
+
+ def test_create_ha_router(self):
+ self._create_router(ctx=self.user_ctx)
+
+ def test_update_router(self):
+ router = self._create_router(ctx=self.user_ctx)
+ self._update_router(router['id'], ha=False, ctx=self.user_ctx)
+
+ def test_delete_router(self):
+ router = self._create_router(ctx=self.user_ctx)
+ self.plugin.delete_router(self.user_ctx, router['id'])
diff --git a/neutron/tests/unit/ml2/_test_mech_agent.py b/neutron/tests/unit/ml2/_test_mech_agent.py
index a42eca0c2a..71aeecf13c 100644
--- a/neutron/tests/unit/ml2/_test_mech_agent.py
+++ b/neutron/tests/unit/ml2/_test_mech_agent.py
@@ -120,7 +120,7 @@ class AgentMechanismBaseTestCase(base.BaseTestCase):
# The following must be overridden for the specific mechanism
# driver being tested:
VIF_TYPE = None
- CAP_PORT_FILTER = None
+ VIF_DETAILS = None
AGENT_TYPE = None
AGENTS = None
AGENTS_DEAD = None
@@ -136,8 +136,17 @@ class AgentMechanismBaseTestCase(base.BaseTestCase):
self.assertEqual(context._bound_vif_type, self.VIF_TYPE)
vif_details = context._bound_vif_details
self.assertIsNotNone(vif_details)
- self.assertEqual(vif_details[portbindings.CAP_PORT_FILTER],
- self.CAP_PORT_FILTER)
+ # NOTE(r-mibu): The following five lines are just for backward
+ # compatibility. In this class, HAS_PORT_FILTER has been replaced
+ # by VIF_DETAILS which can be set expected vif_details to check,
+ # but all replacement of HAS_PORT_FILTER in successor has not been
+ # completed.
+ if self.VIF_DETAILS is None:
+ expected = getattr(self, 'CAP_PORT_FILTER', None)
+ port_filter = vif_details[portbindings.CAP_PORT_FILTER]
+ self.assertEqual(expected, port_filter)
+ return
+ self.assertEqual(self.VIF_DETAILS, vif_details)
class AgentMechanismGenericTestCase(AgentMechanismBaseTestCase):
diff --git a/neutron/tests/unit/ml2/drivers/test_l2population.py b/neutron/tests/unit/ml2/drivers/test_l2population.py
index cfe76d3a57..85d8b37a73 100644
--- a/neutron/tests/unit/ml2/drivers/test_l2population.py
+++ b/neutron/tests/unit/ml2/drivers/test_l2population.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import contextlib
import mock
from neutron.common import constants
@@ -24,6 +25,7 @@ from neutron.extensions import providernet as pnet
from neutron import manager
from neutron.openstack.common import timeutils
from neutron.plugins.ml2 import config as config
+from neutron.plugins.ml2.drivers.l2pop import mech_driver as l2pop_mech_driver
from neutron.plugins.ml2 import managers
from neutron.plugins.ml2 import rpc
from neutron.tests.unit import test_db_plugin as test_plugin
@@ -794,3 +796,17 @@ class TestL2PopulationRpcTestCase(test_plugin.NeutronDbPluginV2TestCase):
self.mock_fanout.assert_called_with(
mock.ANY, expected, topic=self.fanout_topic)
+
+ def test_delete_port_invokes_update_device_down(self):
+ l2pop_mech = l2pop_mech_driver.L2populationMechanismDriver()
+ l2pop_mech.L2PopulationAgentNotify = mock.Mock()
+ l2pop_mech.rpc_ctx = mock.Mock()
+ with contextlib.nested(
+ mock.patch.object(l2pop_mech,
+ '_update_port_down',
+ return_value=None),
+ mock.patch.object(l2pop_mech.L2PopulationAgentNotify,
+ 'remove_fdb_entries')) as (upd_port_down,
+ rem_fdb_entries):
+ l2pop_mech.delete_port_postcommit(mock.Mock())
+ self.assertTrue(upd_port_down.called) \ No newline at end of file
diff --git a/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py b/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py
index 3187f296b4..8c62e1e79f 100644
--- a/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py
+++ b/neutron/tests/unit/ml2/drivers/test_ofagent_mech.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo.config import cfg
+
from neutron.common import constants
from neutron.extensions import portbindings
from neutron.plugins.ml2.drivers import mech_ofagent
@@ -21,7 +23,8 @@ from neutron.tests.unit.ml2 import _test_mech_agent as base
class OfagentMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
VIF_TYPE = portbindings.VIF_TYPE_OVS
- CAP_PORT_FILTER = True
+ VIF_DETAILS = {portbindings.CAP_PORT_FILTER: True,
+ portbindings.OVS_HYBRID_PLUG: True}
AGENT_TYPE = constants.AGENT_TYPE_OFA
GOOD_MAPPINGS = {'fake_physical_network': 'fake_interface'}
@@ -49,6 +52,17 @@ class OfagentMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
self.driver.initialize()
+class OfagentMechanismSGDisabledBaseTestCase(OfagentMechanismBaseTestCase):
+ VIF_DETAILS = {portbindings.CAP_PORT_FILTER: False,
+ portbindings.OVS_HYBRID_PLUG: False}
+
+ def setUp(self):
+ cfg.CONF.set_override('enable_security_group',
+ False,
+ group='SECURITYGROUP')
+ super(OfagentMechanismSGDisabledBaseTestCase, self).setUp()
+
+
class OfagentMechanismGenericTestCase(OfagentMechanismBaseTestCase,
base.AgentMechanismGenericTestCase):
pass
@@ -74,12 +88,19 @@ class OfagentMechanismGreTestCase(OfagentMechanismBaseTestCase,
pass
+class OfagentMechanismSGDisabledLocalTestCase(
+ OfagentMechanismSGDisabledBaseTestCase,
+ base.AgentMechanismLocalTestCase):
+ pass
+
+
# The following tests are for deprecated "bridge_mappings".
# TODO(yamamoto): Remove them.
class OfagentMechanismPhysBridgeTestCase(base.AgentMechanismBaseTestCase):
VIF_TYPE = portbindings.VIF_TYPE_OVS
- CAP_PORT_FILTER = True
+ VIF_DETAILS = {portbindings.CAP_PORT_FILTER: True,
+ portbindings.OVS_HYBRID_PLUG: True}
AGENT_TYPE = constants.AGENT_TYPE_OFA
GOOD_MAPPINGS = {'fake_physical_network': 'fake_bridge'}
diff --git a/neutron/tests/unit/ml2/test_mech_openvswitch.py b/neutron/tests/unit/ml2/test_mech_openvswitch.py
index b1af1b7fae..456d6f02cc 100644
--- a/neutron/tests/unit/ml2/test_mech_openvswitch.py
+++ b/neutron/tests/unit/ml2/test_mech_openvswitch.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo.config import cfg
+
from neutron.common import constants
from neutron.extensions import portbindings
from neutron.plugins.ml2.drivers import mech_openvswitch
@@ -21,7 +23,8 @@ from neutron.tests.unit.ml2 import _test_mech_agent as base
class OpenvswitchMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
VIF_TYPE = portbindings.VIF_TYPE_OVS
- CAP_PORT_FILTER = True
+ VIF_DETAILS = {portbindings.CAP_PORT_FILTER: True,
+ portbindings.OVS_HYBRID_PLUG: True}
AGENT_TYPE = constants.AGENT_TYPE_OVS
GOOD_MAPPINGS = {'fake_physical_network': 'fake_bridge'}
@@ -49,6 +52,18 @@ class OpenvswitchMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
self.driver.initialize()
+class OpenvswitchMechanismSGDisabledBaseTestCase(
+ OpenvswitchMechanismBaseTestCase):
+ VIF_DETAILS = {portbindings.CAP_PORT_FILTER: False,
+ portbindings.OVS_HYBRID_PLUG: False}
+
+ def setUp(self):
+ cfg.CONF.set_override('enable_security_group',
+ False,
+ group='SECURITYGROUP')
+ super(OpenvswitchMechanismSGDisabledBaseTestCase, self).setUp()
+
+
class OpenvswitchMechanismGenericTestCase(OpenvswitchMechanismBaseTestCase,
base.AgentMechanismGenericTestCase):
pass
@@ -72,3 +87,9 @@ class OpenvswitchMechanismVlanTestCase(OpenvswitchMechanismBaseTestCase,
class OpenvswitchMechanismGreTestCase(OpenvswitchMechanismBaseTestCase,
base.AgentMechanismGreTestCase):
pass
+
+
+class OpenvswitchMechanismSGDisabledLocalTestCase(
+ OpenvswitchMechanismSGDisabledBaseTestCase,
+ base.AgentMechanismLocalTestCase):
+ pass
diff --git a/neutron/tests/unit/ml2/test_security_group.py b/neutron/tests/unit/ml2/test_security_group.py
index 39c3cc2bae..cc8468ae23 100644
--- a/neutron/tests/unit/ml2/test_security_group.py
+++ b/neutron/tests/unit/ml2/test_security_group.py
@@ -14,11 +14,15 @@
# License for the specific language governing permissions and limitations
# under the License.
+import contextlib
+import math
import mock
from neutron.api.v2 import attributes
+from neutron.common import constants as const
from neutron.extensions import securitygroup as ext_sg
from neutron import manager
+from neutron.tests.unit import test_api_v2
from neutron.tests.unit import test_extension_security_group as test_sg
from neutron.tests.unit import test_security_groups_rpc as test_sg_rpc
@@ -55,38 +59,91 @@ class TestMl2SecurityGroups(Ml2SecurityGroupsTestCase,
plugin = manager.NeutronManager.get_plugin()
plugin.start_rpc_listeners()
- def test_security_group_get_port_from_device(self):
+ def _make_port_with_new_sec_group(self, net_id):
+ sg = self._make_security_group(self.fmt, 'name', 'desc')
+ port = self._make_port(
+ self.fmt, net_id, security_groups=[sg['security_group']['id']])
+ return port['port']
+
+ def test_security_group_get_ports_from_devices(self):
with self.network() as n:
with self.subnet(n):
- with self.security_group() as sg:
- security_group_id = sg['security_group']['id']
- res = self._create_port(self.fmt, n['network']['id'])
- port = self.deserialize(self.fmt, res)
- fixed_ips = port['port']['fixed_ips']
- data = {'port': {'fixed_ips': fixed_ips,
- 'name': port['port']['name'],
- ext_sg.SECURITYGROUPS:
- [security_group_id]}}
-
- req = self.new_update_request('ports', data,
- port['port']['id'])
- res = self.deserialize(self.fmt,
- req.get_response(self.api))
- port_id = res['port']['id']
- plugin = manager.NeutronManager.get_plugin()
- port_dict = plugin.get_port_from_device(port_id)
- self.assertEqual(port_id, port_dict['id'])
- self.assertEqual([security_group_id],
+ port1 = self._make_port_with_new_sec_group(n['network']['id'])
+ port2 = self._make_port_with_new_sec_group(n['network']['id'])
+ plugin = manager.NeutronManager.get_plugin()
+ # should match full ID and starting chars
+ ports = plugin.get_ports_from_devices(
+ [port1['id'], port2['id'][0:8]])
+ self.assertEqual(2, len(ports))
+ for port_dict in ports:
+ p = port1 if port1['id'] == port_dict['id'] else port2
+ self.assertEqual(p['id'], port_dict['id'])
+ self.assertEqual(p['security_groups'],
port_dict[ext_sg.SECURITYGROUPS])
self.assertEqual([], port_dict['security_group_rules'])
- self.assertEqual([fixed_ips[0]['ip_address']],
+ self.assertEqual([p['fixed_ips'][0]['ip_address']],
port_dict['fixed_ips'])
- self._delete('ports', port_id)
+ self._delete('ports', p['id'])
+
+ def test_security_group_get_ports_from_devices_with_bad_id(self):
+ plugin = manager.NeutronManager.get_plugin()
+ ports = plugin.get_ports_from_devices(['bad_device_id'])
+ self.assertFalse(ports)
- def test_security_group_get_port_from_device_with_no_port(self):
+ def test_security_group_no_db_calls_with_no_ports(self):
+ plugin = manager.NeutronManager.get_plugin()
+ with mock.patch(
+ 'neutron.plugins.ml2.db.get_sg_ids_grouped_by_port'
+ ) as get_mock:
+ self.assertFalse(plugin.get_ports_from_devices([]))
+ self.assertFalse(get_mock.called)
+
+ def test_large_port_count_broken_into_parts(self):
+ plugin = manager.NeutronManager.get_plugin()
+ max_ports_per_query = 5
+ ports_to_query = 73
+ for max_ports_per_query in (1, 2, 5, 7, 9, 31):
+ with contextlib.nested(
+ mock.patch('neutron.plugins.ml2.db.MAX_PORTS_PER_QUERY',
+ new=max_ports_per_query),
+ mock.patch('neutron.plugins.ml2.db.get_sg_ids_grouped_by_port',
+ return_value={}),
+ ) as (max_mock, get_mock):
+ plugin.get_ports_from_devices(
+ ['%s%s' % (const.TAP_DEVICE_PREFIX, i)
+ for i in range(ports_to_query)])
+ all_call_args = map(lambda x: x[1][0], get_mock.mock_calls)
+ last_call_args = all_call_args.pop()
+ # all but last should be getting MAX_PORTS_PER_QUERY ports
+ self.assertTrue(
+ all(map(lambda x: len(x) == max_ports_per_query,
+ all_call_args))
+ )
+ remaining = ports_to_query % max_ports_per_query
+ if remaining:
+ self.assertEqual(remaining, len(last_call_args))
+ # should be broken into ceil(total/MAX_PORTS_PER_QUERY) calls
+ self.assertEqual(
+ math.ceil(ports_to_query / float(max_ports_per_query)),
+ get_mock.call_count
+ )
+
+ def test_full_uuids_skip_port_id_lookup(self):
plugin = manager.NeutronManager.get_plugin()
- port_dict = plugin.get_port_from_device('bad_device_id')
- self.assertIsNone(port_dict)
+ # when full UUIDs are provided, the _or statement should only
+ # have one matching 'IN' critiera for all of the IDs
+ with contextlib.nested(
+ mock.patch('neutron.plugins.ml2.db.or_'),
+ mock.patch('neutron.plugins.ml2.db.db_api.get_session')
+ ) as (or_mock, sess_mock):
+ fmock = sess_mock.query.return_value.outerjoin.return_value.filter
+ # return no ports to exit the method early since we are mocking
+ # the query
+ fmock.return_value.all.return_value = []
+ plugin.get_ports_from_devices([test_api_v2._uuid(),
+ test_api_v2._uuid()])
+ # the or_ function should only have one argument
+ or_mock.assert_called_once_with(mock.ANY)
class TestMl2SecurityGroupsXML(TestMl2SecurityGroups):
diff --git a/neutron/tests/unit/mlnx/test_mlnx_comm_utils.py b/neutron/tests/unit/mlnx/test_mlnx_comm_utils.py
index bb8bdcced7..49f2eaceea 100644
--- a/neutron/tests/unit/mlnx/test_mlnx_comm_utils.py
+++ b/neutron/tests/unit/mlnx/test_mlnx_comm_utils.py
@@ -29,8 +29,7 @@ class WrongException(Exception):
class TestRetryDecorator(base.BaseTestCase):
def setUp(self):
super(TestRetryDecorator, self).setUp()
- self.sleep_fn_p = mock.patch.object(comm_utils.RetryDecorator,
- 'sleep_fn')
+ self.sleep_fn_p = mock.patch("time.sleep")
self.sleep_fn = self.sleep_fn_p.start()
def test_no_retry_required(self):
diff --git a/neutron/tests/unit/nec/test_portbindings.py b/neutron/tests/unit/nec/test_portbindings.py
index 9dc61ed54c..a2ceb321b3 100644
--- a/neutron/tests/unit/nec/test_portbindings.py
+++ b/neutron/tests/unit/nec/test_portbindings.py
@@ -28,7 +28,8 @@ from neutron.tests.unit import test_security_groups_rpc as test_sg_rpc
class TestNecPortBinding(test_bindings.PortBindingsTestCase,
test_nec_plugin.NecPluginV2TestCase):
VIF_TYPE = portbindings.VIF_TYPE_OVS
- HAS_PORT_FILTER = True
+ VIF_DETAILS = {portbindings.CAP_PORT_FILTER: True,
+ portbindings.OVS_HYBRID_PLUG: True}
ENABLE_SG = True
FIREWALL_DRIVER = test_sg_rpc.FIREWALL_HYBRID_DRIVER
@@ -41,7 +42,8 @@ class TestNecPortBinding(test_bindings.PortBindingsTestCase,
class TestNecPortBindingNoSG(TestNecPortBinding):
- HAS_PORT_FILTER = False
+ VIF_DETAILS = {portbindings.CAP_PORT_FILTER: False,
+ portbindings.OVS_HYBRID_PLUG: False}
ENABLE_SG = False
FIREWALL_DRIVER = test_sg_rpc.FIREWALL_NOOP_DRIVER
diff --git a/neutron/tests/unit/notifiers/test_notifiers_nova.py b/neutron/tests/unit/notifiers/test_notifiers_nova.py
index 7972ebf55a..db9bc79c31 100644
--- a/neutron/tests/unit/notifiers/test_notifiers_nova.py
+++ b/neutron/tests/unit/notifiers/test_notifiers_nova.py
@@ -303,3 +303,20 @@ class TestNovaNotify(base.BaseTestCase):
self.nova_notifier.queue_event(mock.Mock())
self.assertFalse(self.nova_notifier._waiting_to_send)
send_events.assert_called_once_with()
+
+ def test_reassociate_floatingip_without_disassociate_event(self):
+ returned_obj = {'floatingip':
+ {'port_id': 'f5348a16-609a-4971-b0f0-4b8def5235fb'}}
+ original_obj = {'port_id': '5a39def4-3d3f-473d-9ff4-8e90064b9cc1'}
+ self.nova_notifier._waiting_to_send = True
+ self.nova_notifier.send_network_change(
+ 'update_floatingip', original_obj, returned_obj)
+ self.assertEqual(2, len(self.nova_notifier.pending_events))
+
+ returned_obj_non = {'floatingip': {'port_id': None}}
+ event_dis = self.nova_notifier.create_port_changed_event(
+ 'update_floatingip', original_obj, returned_obj_non)
+ event_assoc = self.nova_notifier.create_port_changed_event(
+ 'update_floatingip', original_obj, returned_obj)
+ self.assertEqual(self.nova_notifier.pending_events[0], event_dis)
+ self.assertEqual(self.nova_notifier.pending_events[1], event_assoc)
diff --git a/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py b/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py
index ff275205b1..b40883976c 100644
--- a/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py
+++ b/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py
@@ -81,6 +81,7 @@ class TestPlumgridPluginSubnetsV2(test_plugin.TestSubnetsV2,
_unsupported = (
'test_create_subnet_default_gw_conflict_allocation_pool_returns_409',
'test_create_subnet_defaults', 'test_create_subnet_gw_values',
+ 'test_create_subnet_ipv6_gw_values',
'test_update_subnet_gateway_in_allocation_pool_returns_409',
'test_update_subnet_allocation_pools',
'test_update_subnet_allocation_pools_invalid_pool_for_cidr')
diff --git a/neutron/tests/unit/test_db_plugin.py b/neutron/tests/unit/test_db_plugin.py
index 74292fac07..24eab08440 100644
--- a/neutron/tests/unit/test_db_plugin.py
+++ b/neutron/tests/unit/test_db_plugin.py
@@ -1419,6 +1419,22 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
self.assertEqual(res.status_int,
webob.exc.HTTPClientError.code)
+ def test_requested_fixed_ip_address_v6_slaac_router_iface(self):
+ with self.subnet(gateway_ip='fe80::1',
+ cidr='fe80::/64',
+ ip_version=6,
+ ipv6_address_mode=constants.IPV6_SLAAC) as subnet:
+ kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'],
+ 'ip_address': 'fe80::1'}]}
+ net_id = subnet['subnet']['network_id']
+ device_owner = constants.DEVICE_OWNER_ROUTER_INTF
+ res = self._create_port(self.fmt, net_id=net_id,
+ device_owner=device_owner, **kwargs)
+ port = self.deserialize(self.fmt, res)
+ self.assertEqual(len(port['port']['fixed_ips']), 1)
+ self.assertEqual(port['port']['fixed_ips'][0]['ip_address'],
+ 'fe80::1')
+
def test_requested_subnet_id_v6_slaac(self):
with self.subnet(gateway_ip='fe80::1',
cidr='2607:f0d0:1002:51::/64',
@@ -2830,6 +2846,38 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
self._test_create_subnet(expected=expected,
gateway_ip=gateway)
+ def test_create_subnet_ipv6_gw_values(self):
+ cidr = '2001::/64'
+ # Gateway is last IP in IPv6 DHCPv6 stateful subnet
+ gateway = '2001::ffff:ffff:ffff:fffe'
+ allocation_pools = [{'start': '2001::1',
+ 'end': '2001::ffff:ffff:ffff:fffd'}]
+ expected = {'gateway_ip': gateway,
+ 'cidr': cidr,
+ 'allocation_pools': allocation_pools}
+ self._test_create_subnet(expected=expected, gateway_ip=gateway,
+ cidr=cidr, ip_version=6,
+ ipv6_ra_mode=constants.DHCPV6_STATEFUL,
+ ipv6_address_mode=constants.DHCPV6_STATEFUL)
+ # Gateway is first IP in IPv6 DHCPv6 stateful subnet
+ gateway = '2001::1'
+ allocation_pools = [{'start': '2001::2',
+ 'end': '2001::ffff:ffff:ffff:fffe'}]
+ expected = {'gateway_ip': gateway,
+ 'cidr': cidr,
+ 'allocation_pools': allocation_pools}
+ self._test_create_subnet(expected=expected, gateway_ip=gateway,
+ cidr=cidr, ip_version=6,
+ ipv6_ra_mode=constants.DHCPV6_STATEFUL,
+ ipv6_address_mode=constants.DHCPV6_STATEFUL)
+ # Gateway not specified for IPv6 SLAAC subnet
+ expected = {'gateway_ip': None,
+ 'cidr': cidr}
+ self._test_create_subnet(expected=expected,
+ cidr=cidr, ip_version=6,
+ ipv6_ra_mode=constants.IPV6_SLAAC,
+ ipv6_address_mode=constants.IPV6_SLAAC)
+
def test_create_subnet_gw_outside_cidr_returns_400(self):
with self.network() as network:
self._create_subnet(self.fmt,
diff --git a/neutron/tests/unit/test_dhcp_agent.py b/neutron/tests/unit/test_dhcp_agent.py
index c6f98643fe..5e02428b0d 100644
--- a/neutron/tests/unit/test_dhcp_agent.py
+++ b/neutron/tests/unit/test_dhcp_agent.py
@@ -64,6 +64,12 @@ fake_subnet3 = dhcp.DictModel(dict(id='bbbbbbbb-1111-2222-bbbbbbbbbbbb',
network_id='12345678-1234-5678-1234567890ab',
cidr='192.168.1.1/24', enable_dhcp=True))
+fake_ipv6_subnet = dhcp.DictModel(dict(id='bbbbbbbb-1111-2222-bbbbbbbbbbbb',
+ network_id='12345678-1234-5678-1234567890ab',
+ cidr='2001:0db8::1:0:0:1/128', enable_dhcp=True,
+ tenant_id=fake_tenant_id,
+ gateway_ip='2001:0db8::1:0:0:1', ip_version=6))
+
fake_meta_subnet = dhcp.DictModel(dict(id='bbbbbbbb-1111-2222-bbbbbbbbbbbb',
network_id='12345678-1234-5678-1234567890ab',
cidr='169.254.169.252/30',
@@ -104,6 +110,12 @@ fake_network = dhcp.NetModel(True, dict(id='12345678-1234-5678-1234567890ab',
subnets=[fake_subnet1, fake_subnet2],
ports=[fake_port1]))
+fake_network_ipv6 = dhcp.NetModel(True, dict(
+ id='12345678-1234-5678-1234567890ab',
+ tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa',
+ admin_state_up=True,
+ subnets=[fake_ipv6_subnet]))
+
isolated_network = dhcp.NetModel(
True, dict(
id='12345678-1234-5678-1234567890ab',
@@ -555,6 +567,9 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
def test_enable_dhcp_helper(self):
self._enable_dhcp_helper(fake_network)
+ def test_enable_dhcp_helper_ipv6_network(self):
+ self._enable_dhcp_helper(fake_network_ipv6)
+
def test_enable_dhcp_helper_down_network(self):
self.plugin.get_network_info.return_value = fake_down_network
self.dhcp.enable_dhcp_helper(fake_down_network.id)
diff --git a/neutron/tests/unit/test_dhcp_rpc.py b/neutron/tests/unit/test_dhcp_rpc.py
index 6a2ed16d7e..2c4c5c9e6e 100644
--- a/neutron/tests/unit/test_dhcp_rpc.py
+++ b/neutron/tests/unit/test_dhcp_rpc.py
@@ -161,13 +161,44 @@ class TestDhcpRpcCallback(base.BaseTestCase):
self.plugin.assert_has_calls(expected)
return retval
+ def test_update_dhcp_port_verify_port_action_port_dict(self):
+ port = {'port': {'network_id': 'foo_network_id',
+ 'device_owner': constants.DEVICE_OWNER_DHCP,
+ 'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]}
+ }
+ expected_port = {'port': {'network_id': 'foo_network_id',
+ 'device_owner': constants.DEVICE_OWNER_DHCP,
+ 'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]
+ },
+ 'id': 'foo_port_id'
+ }
+
+ def _fake_port_action(plugin, context, port, action):
+ self.assertEqual(expected_port, port)
+
+ self.callbacks._port_action = _fake_port_action
+ self.callbacks.update_dhcp_port(mock.Mock(),
+ host='foo_host',
+ port_id='foo_port_id',
+ port=port)
+
def test_update_dhcp_port(self):
+ port = {'port': {'network_id': 'foo_network_id',
+ 'device_owner': constants.DEVICE_OWNER_DHCP,
+ 'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]}
+ }
+ expected_port = {'port': {'network_id': 'foo_network_id',
+ 'device_owner': constants.DEVICE_OWNER_DHCP,
+ 'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]
+ },
+ 'id': 'foo_port_id'
+ }
self.callbacks.update_dhcp_port(mock.Mock(),
host='foo_host',
port_id='foo_port_id',
- port=mock.Mock())
+ port=port)
self.plugin.assert_has_calls(
- mock.call.update_port(mock.ANY, 'foo_port_id', mock.ANY))
+ mock.call.update_port(mock.ANY, 'foo_port_id', expected_port))
def test_get_dhcp_port_existing(self):
port_retval = dict(id='port_id', fixed_ips=[dict(subnet_id='a')])
diff --git a/neutron/tests/unit/test_security_groups_rpc.py b/neutron/tests/unit/test_security_groups_rpc.py
index 7f20c7d9ea..3acc378b1d 100644
--- a/neutron/tests/unit/test_security_groups_rpc.py
+++ b/neutron/tests/unit/test_security_groups_rpc.py
@@ -1021,6 +1021,7 @@ class BaseSecurityGroupAgentRpcTestCase(base.BaseTestCase):
self.agent.root_helper = 'sudo'
self.agent.plugin_rpc = mock.Mock()
self.agent.init_firewall(defer_refresh_firewall=defer_refresh_firewall)
+ self.default_firewall = self.agent.firewall
self.firewall = mock.Mock()
firewall_object = firewall_base.FirewallDriver()
self.firewall.defer_apply.side_effect = firewall_object.defer_apply
@@ -1057,6 +1058,26 @@ class SecurityGroupAgentRpcTestCase(BaseSecurityGroupAgentRpcTestCase):
self.fake_device),
])
+ def test_prepare_devices_filter_with_noopfirewall(self):
+ self.agent.firewall = self.default_firewall
+ self.agent.plugin_rpc.security_group_info_for_devices = mock.Mock()
+ self.agent.plugin_rpc.security_group_rules_for_devices = mock.Mock()
+ self.agent.prepare_devices_filter(['fake_device'])
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_info_for_devices.called)
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_rules_for_devices.called)
+
+ def test_prepare_devices_filter_with_firewall_disabled(self):
+ cfg.CONF.set_override('enable_security_group', False, 'SECURITYGROUP')
+ self.agent.plugin_rpc.security_group_info_for_devices = mock.Mock()
+ self.agent.plugin_rpc.security_group_rules_for_devices = mock.Mock()
+ self.agent.prepare_devices_filter(['fake_device'])
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_info_for_devices.called)
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_rules_for_devices.called)
+
def test_security_groups_rule_updated(self):
self.agent.refresh_firewall = mock.Mock()
self.agent.prepare_devices_filter(['fake_port_id'])
@@ -1111,6 +1132,30 @@ class SecurityGroupAgentRpcTestCase(BaseSecurityGroupAgentRpcTestCase):
self.agent.refresh_firewall([])
self.assertFalse(self.firewall.called)
+ def test_refresh_firewall_with_firewall_disabled(self):
+ cfg.CONF.set_override('enable_security_group', False, 'SECURITYGROUP')
+ self.agent.plugin_rpc.security_group_info_for_devices = mock.Mock()
+ self.agent.plugin_rpc.security_group_rules_for_devices = mock.Mock()
+ self.agent.firewall.defer_apply = mock.Mock()
+ self.agent.refresh_firewall([self.fake_device])
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_info_for_devices.called)
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_rules_for_devices.called)
+ self.assertFalse(self.agent.firewall.defer_apply.called)
+
+ def test_refresh_firewall_with_noopfirewall(self):
+ self.agent.firewall = self.default_firewall
+ self.agent.plugin_rpc.security_group_info_for_devices = mock.Mock()
+ self.agent.plugin_rpc.security_group_rules_for_devices = mock.Mock()
+ self.agent.firewall.defer_apply = mock.Mock()
+ self.agent.refresh_firewall([self.fake_device])
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_info_for_devices.called)
+ self.assertFalse(self.agent.plugin_rpc.
+ security_group_rules_for_devices.called)
+ self.assertFalse(self.agent.firewall.defer_apply.called)
+
class SecurityGroupAgentEnhancedRpcTestCase(
BaseSecurityGroupAgentRpcTestCase):
diff --git a/neutron/tests/unit/vmware/extensions/test_providernet.py b/neutron/tests/unit/vmware/extensions/test_providernet.py
index f6057f1451..6f27011b26 100644
--- a/neutron/tests/unit/vmware/extensions/test_providernet.py
+++ b/neutron/tests/unit/vmware/extensions/test_providernet.py
@@ -47,6 +47,15 @@ class TestProvidernet(test_nsx_plugin.NsxPluginV2TestCase):
self.assertEqual(net['network'][pnet.SEGMENTATION_ID], 411)
self.assertEqual(net['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
+ # Test that we can create another provider network using the same
+ # vlan_id on another physical network.
+ data['network'][pnet.PHYSICAL_NETWORK] = 'physnet2'
+ network_req = self.new_create_request('networks', data, self.fmt)
+ net = self.deserialize(self.fmt, network_req.get_response(self.api))
+ self.assertEqual(net['network'][pnet.NETWORK_TYPE], 'vlan')
+ self.assertEqual(net['network'][pnet.SEGMENTATION_ID], 411)
+ self.assertEqual(net['network'][pnet.PHYSICAL_NETWORK], 'physnet2')
+
class TestMultiProviderNetworks(test_nsx_plugin.NsxPluginV2TestCase):
diff --git a/setup.cfg b/setup.cfg
index 493940d2aa..94bf98cb34 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -141,7 +141,6 @@ neutron.core_plugins =
nuage = neutron.plugins.nuage.plugin:NuagePlugin
metaplugin = neutron.plugins.metaplugin.meta_neutron_plugin:MetaPluginV2
oneconvergence = neutron.plugins.oneconvergence.plugin:OneConvergencePluginV2
- openvswitch = neutron.plugins.openvswitch.ovs_neutron_plugin:OVSNeutronPluginV2
plumgrid = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin:NeutronPluginPLUMgridV2
ryu = neutron.plugins.ryu.ryu_neutron_plugin:RyuNeutronPluginV2
vmware = neutron.plugins.vmware.plugin:NsxPlugin