refactor port binding codes

Bug #1195047

This patch:
1. removes the iteration in get_ports to call extend_dict_binding
2. uses a unified way for plugins to do this kind of stuff

ml2 will enhance the binding so that it can have different binding
for port according to port's host.
mlnx and bigswitch are also exceptions due to the dynamic binding info.

Change-Id: I5a77eb7395e14482a856e033f536f72a1bf82e06
This commit is contained in:
Yong Sheng Gong 2013-07-23 13:21:24 +08:00
parent e4ddee8e82
commit 76fc0addc9
10 changed files with 139 additions and 109 deletions

View File

@ -0,0 +1,43 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 UnitedStack Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# @author: Yong Sheng Gong, UnitedStack Inc.
from neutron.api.v2 import attributes
from neutron.db import db_base_plugin_v2
class PortBindingBaseMixin(object):
base_binding_dict = None
def _process_portbindings_create_and_update(self, context, port_data,
port):
self.extend_port_dict_binding(port, None)
def extend_port_dict_binding(self, port_res, port_db):
if self.base_binding_dict:
port_res.update(self.base_binding_dict)
def _extend_port_dict_binding(plugin, port_res, port_db):
if not isinstance(plugin, PortBindingBaseMixin):
return
plugin.extend_port_dict_binding(port_res, port_db)
def register_port_dict_function():
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
attributes.PORTS, [_extend_port_dict_binding])

View File

@ -23,11 +23,8 @@ from neutron.api.v2 import attributes
from neutron.db import db_base_plugin_v2
from neutron.db import model_base
from neutron.db import models_v2
from neutron.db import portbindings_base
from neutron.extensions import portbindings
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class PortBindingPort(model_base.BASEV2):
@ -42,7 +39,7 @@ class PortBindingPort(model_base.BASEV2):
cascade='delete'))
class PortBindingMixin(object):
class PortBindingMixin(portbindings_base.PortBindingBaseMixin):
extra_binding_dict = None
def _port_model_hook(self, context, original_model, query):
@ -77,7 +74,7 @@ class PortBindingMixin(object):
host = port_data.get(portbindings.HOST_ID)
host_set = attributes.is_attr_set(host)
if not host_set:
_extend_port_dict_binding_host(self, port, None)
self._extend_port_dict_binding_host(port, None)
return
with context.session.begin(subtransactions=True):
bind_port = context.session.query(
@ -87,7 +84,7 @@ class PortBindingMixin(object):
host=host))
else:
bind_port.host = host
_extend_port_dict_binding_host(self, port, host)
self._extend_port_dict_binding_host(port, host)
def get_port_host(self, context, port_id):
with context.session.begin(subtransactions=True):
@ -95,21 +92,22 @@ class PortBindingMixin(object):
PortBindingPort).filter_by(port_id=port_id).first()
return bind_port and bind_port.host or None
def _extend_port_dict_binding_host(self, port_res, host):
super(PortBindingMixin, self).extend_port_dict_binding(
port_res, None)
port_res[portbindings.HOST_ID] = host
def _extend_port_dict_binding_host(plugin, port_res, host):
port_res[portbindings.HOST_ID] = host
if plugin.extra_binding_dict:
port_res.update(plugin.extra_binding_dict)
return port_res
def extend_port_dict_binding(self, port_res, port_db):
host = (port_db.portbinding and port_db.portbinding.host or None)
self._extend_port_dict_binding_host(port_res, host)
def _extend_port_dict_binding(plugin, port_res, port_db):
if not isinstance(plugin, PortBindingMixin):
return
host = (port_db.portbinding and port_db.portbinding.host or None)
return _extend_port_dict_binding_host(
plugin, port_res, host)
plugin.extend_port_dict_binding(port_res, port_db)
# Register dict extend functions for ports
# Register dict extend functions for ports
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
attributes.PORTS, [_extend_port_dict_binding])

View File

@ -41,6 +41,7 @@ from neutron.db import db_base_plugin_v2
from neutron.db import dhcp_rpc_base
from neutron.db import extraroute_db
from neutron.db import l3_rpc_base
from neutron.db import portbindings_base
from neutron.db import securitygroups_rpc_base as sg_db_rpc
from neutron.extensions import portbindings
from neutron.extensions import securitygroup as ext_sg
@ -199,7 +200,8 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
extraroute_db.ExtraRoute_db_mixin,
sg_db_rpc.SecurityGroupServerRpcMixin,
agentschedulers_db.L3AgentSchedulerDbMixin,
agentschedulers_db.DhcpAgentSchedulerDbMixin):
agentschedulers_db.DhcpAgentSchedulerDbMixin,
portbindings_base.PortBindingBaseMixin):
"""BrocadePluginV2 is a Neutron plugin.
Provides L2 Virtual Network functionality using VDX. Upper
@ -220,6 +222,8 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
self.physical_interface = (cfg.CONF.PHYSICAL_INTERFACE.
physical_interface)
self.base_binding_dict = self._get_base_binding_dict()
portbindings_base.register_port_dict_function()
db.configure_db()
self.ctxt = context.get_admin_context()
self.ctxt.session = db.get_session()
@ -359,6 +363,9 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
neutron_port = super(BrocadePluginV2, self).create_port(context,
port)
self._process_portbindings_create_and_update(context,
port['port'],
neutron_port)
interface_mac = neutron_port['mac_address']
port_id = neutron_port['id']
@ -384,7 +391,7 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
vlan_id, tenant_id, admin_state_up)
# apply any extensions
return self._extend_port_dict_binding(context, neutron_port)
return neutron_port
def delete_port(self, context, port_id):
with context.session.begin(subtransactions=True):
@ -408,10 +415,12 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
port['port'],
port['port'][ext_sg.SECURITYGROUPS])
port_updated = True
port_data = port['port']
port = super(BrocadePluginV2, self).update_port(
context, port_id, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
if original_port['admin_state_up'] != port['admin_state_up']:
port_updated = True
@ -425,27 +434,7 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
if port_updated:
self._notify_port_updated(context, port)
return self._extend_port_dict_binding(context, port)
def get_port(self, context, port_id, fields=None):
with context.session.begin(subtransactions=True):
port = super(BrocadePluginV2, self).get_port(
context, port_id, fields)
self._extend_port_dict_binding(context, port)
return self._fields(port, fields)
def get_ports(self, context, filters=None, fields=None):
res_ports = []
with context.session.begin(subtransactions=True):
ports = super(BrocadePluginV2, self).get_ports(context,
filters,
fields)
for port in ports:
self._extend_port_dict_binding(context, port)
res_ports.append(self._fields(port, fields))
return res_ports
return port
def _notify_port_updated(self, context, port):
port_id = port['id']
@ -454,12 +443,13 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
bport.physical_interface,
bport.vlan_id)
def _extend_port_dict_binding(self, context, port):
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_BRIDGE
port[portbindings.CAPABILITIES] = {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}
return port
def _get_base_binding_dict(self):
binding = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_BRIDGE,
portbindings.CAPABILITIES: {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}}
return binding
def get_plugin_version(self):
"""Get version number of the plugin."""

View File

@ -23,6 +23,7 @@ from neutron.common import exceptions as q_exc
from neutron.common import topics
from neutron.db import db_base_plugin_v2
from neutron.db import l3_gwmode_db
from neutron.db import portbindings_base
from neutron.db import quota_db # noqa
from neutron.extensions import portbindings
from neutron.extensions import providernet as provider
@ -141,7 +142,8 @@ class VlanNetworkProvider(BaseNetworkProvider):
class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
l3_gwmode_db.L3_NAT_db_mixin):
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_base.PortBindingBaseMixin):
# This attribute specifies whether the plugin supports or not
# bulk operations. Name mangling is used in order to ensure it
@ -153,7 +155,9 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
def __init__(self, configfile=None):
self._db = hyperv_db.HyperVPluginDB()
self._db.initialize()
self.base_binding_dict = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_HYPERV}
portbindings_base.register_port_dict_function()
self._set_tenant_network_type()
self._parse_network_vlan_ranges()
@ -287,29 +291,22 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
return [self._fields(net, fields) for net in nets]
def _extend_port_dict_binding(self, context, port):
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_HYPERV
return port
def create_port(self, context, port):
port_data = port['port']
port = super(HyperVNeutronPlugin, self).create_port(context, port)
return self._extend_port_dict_binding(context, port)
def get_port(self, context, id, fields=None):
port = super(HyperVNeutronPlugin, self).get_port(context, id, fields)
return self._fields(self._extend_port_dict_binding(context, port),
fields)
def get_ports(self, context, filters=None, fields=None):
ports = super(HyperVNeutronPlugin, self).get_ports(
context, filters, fields)
return [self._fields(self._extend_port_dict_binding(context, port),
fields) for port in ports]
self._process_portbindings_create_and_update(context,
port_data,
port)
return port
def update_port(self, context, id, port):
original_port = super(HyperVNeutronPlugin, self).get_port(
context, id)
port_data = port['port']
port = super(HyperVNeutronPlugin, self).update_port(context, id, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
if original_port['admin_state_up'] != port['admin_state_up']:
binding = self._db.get_network_binding(
None, port['network_id'])
@ -317,7 +314,7 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
binding.network_type,
binding.segmentation_id,
binding.physical_network)
return self._extend_port_dict_binding(context, port)
return port
def delete_port(self, context, id, l3_port_check=True):
# if needed, check to see if this is a port owned by

View File

@ -232,7 +232,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
return self._aliases
def __init__(self):
self.extra_binding_dict = {
self.base_binding_dict = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_BRIDGE,
portbindings.CAPABILITIES: {
portbindings.CAP_PORT_FILTER:

View File

@ -170,7 +170,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
def _extend_port_dict_binding(self, context, port):
# TODO(rkukura): Implement based on host_id, agents, and
# MechanismDrivers. Also set CAPABILITIES. Use
# extra_binding_dict if applicable, or maybe a new hook so
# base_binding_dict if applicable, or maybe a new hook so
# base handles field processing and get_port and get_ports
# don't need to be overridden.
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_UNBOUND

View File

@ -30,6 +30,7 @@ from neutron.db import dhcp_rpc_base
from neutron.db import extraroute_db
from neutron.db import l3_gwmode_db
from neutron.db import l3_rpc_base
from neutron.db import portbindings_base
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_rpc_base as sg_db_rpc
from neutron.extensions import portbindings
@ -68,7 +69,8 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
sg_db_rpc.SecurityGroupServerRpcMixin,
agentschedulers_db.L3AgentSchedulerDbMixin,
agentschedulers_db.DhcpAgentSchedulerDbMixin,
packet_filter.PacketFilterMixin):
packet_filter.PacketFilterMixin,
portbindings_base.PortBindingBaseMixin):
"""NECPluginV2 controls an OpenFlow Controller.
The Neutron NECPluginV2 maps L2 logical networks to L2 virtualized networks
@ -98,9 +100,11 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
return self._aliases
def __init__(self):
ndb.initialize()
self.ofc = ofc_manager.OFCManager()
self.base_binding_dict = self._get_base_binding_dict()
portbindings_base.register_port_dict_function()
# Set the plugin default extension path
# if no api_extensions_path is specified.
if not config.CONF.api_extensions_path:
@ -347,27 +351,32 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
reason = _("delete_ofc_tenant() failed due to %s") % exc
LOG.warn(reason)
def _extend_port_dict_binding(self, context, port):
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_OVS
port[portbindings.CAPABILITIES] = {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}
return port
def _get_base_binding_dict(self):
binding = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
portbindings.CAPABILITIES: {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}}
return binding
def create_port(self, context, port):
"""Create a new port entry on DB, then try to activate it."""
LOG.debug(_("NECPluginV2.create_port() called, port=%s ."), port)
port_data = port['port']
with context.session.begin(subtransactions=True):
self._ensure_default_security_group_on_port(context, port)
sgids = self._get_security_groups_on_port(context, port)
port = super(NECPluginV2, self).create_port(context, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
self._process_port_create_security_group(
context, port, sgids)
self.notify_security_groups_member_updated(context, port)
self._update_resource_status(context, "port", port['id'],
OperationalStatus.BUILD)
self.activate_port_if_ready(context, port)
return self._extend_port_dict_binding(context, port)
return port
def update_port(self, context, id, port):
"""Update port, and handle packetfilters associated with the port.
@ -382,6 +391,9 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
with context.session.begin(subtransactions=True):
old_port = super(NECPluginV2, self).get_port(context, id)
new_port = super(NECPluginV2, self).update_port(context, id, port)
self._process_portbindings_create_and_update(context,
port['port'],
new_port)
need_port_update_notify = self.update_security_group_on_port(
context, id, port, old_port, new_port)
@ -397,7 +409,7 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
else:
self.deactivate_port(context, old_port)
return self._extend_port_dict_binding(context, new_port)
return new_port
def delete_port(self, context, id, l3_port_check=True):
"""Delete port and packet_filters associated with the port."""
@ -426,21 +438,6 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
super(NECPluginV2, self).delete_port(context, id)
self.notify_security_groups_member_updated(context, port)
def get_port(self, context, id, fields=None):
with context.session.begin(subtransactions=True):
port = super(NECPluginV2, self).get_port(context, id, fields)
self._extend_port_dict_binding(context, port)
return self._fields(port, fields)
def get_ports(self, context, filters=None, fields=None):
with context.session.begin(subtransactions=True):
ports = super(NECPluginV2, self).get_ports(context, filters,
fields)
# TODO(amotoki) filter by security group
for port in ports:
self._extend_port_dict_binding(context, port)
return [self._fields(port, fields) for port in ports]
class NECPluginV2AgentNotifierApi(proxy.RpcProxy,
sg_rpc.SecurityGroupAgentRpcApiMixin):

View File

@ -200,7 +200,7 @@ class NvpPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
self.nvp_opts.concurrent_connections,
self.nvp_opts.nvp_gen_timeout)
self.extra_binding_dict = {
self.base_binding_dict = {
pbin.VIF_TYPE: pbin.VIF_TYPE_OVS,
pbin.CAPABILITIES: {
pbin.CAP_PORT_FILTER:

View File

@ -263,7 +263,7 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
return self._aliases
def __init__(self, configfile=None):
self.extra_binding_dict = {
self.base_binding_dict = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
portbindings.CAPABILITIES: {
portbindings.CAP_PORT_FILTER:

View File

@ -32,7 +32,9 @@ from neutron.db import extraroute_db
from neutron.db import l3_gwmode_db
from neutron.db import l3_rpc_base
from neutron.db import models_v2
from neutron.db import portbindings_base
from neutron.db import securitygroups_rpc_base as sg_db_rpc
from neutron.extensions import portbindings
from neutron.openstack.common import log as logging
from neutron.openstack.common import rpc
from neutron.openstack.common.rpc import proxy
@ -88,10 +90,12 @@ class AgentNotifierApi(proxy.RpcProxy,
class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
sg_db_rpc.SecurityGroupServerRpcMixin):
sg_db_rpc.SecurityGroupServerRpcMixin,
portbindings_base.PortBindingBaseMixin):
_supported_extension_aliases = ["router", "ext-gw-mode",
"extraroute", "security-group"]
"extraroute", "security-group",
"binding"]
@property
def supported_extension_aliases(self):
@ -102,6 +106,12 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
return self._aliases
def __init__(self, configfile=None):
self.base_binding_dict = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
portbindings.CAPABILITIES: {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}}
portbindings_base.register_port_dict_function()
db.configure_db()
self.tunnel_key = db_api_v2.TunnelKey(
cfg.CONF.OVS.tunnel_key_min, cfg.CONF.OVS.tunnel_key_max)
@ -185,10 +195,14 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
def create_port(self, context, port):
session = context.session
port_data = port['port']
with session.begin(subtransactions=True):
self._ensure_default_security_group_on_port(context, port)
sgids = self._get_security_groups_on_port(context, port)
port = super(RyuNeutronPluginV2, self).create_port(context, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
self._process_port_create_security_group(
context, port, sgids)
self.notify_security_groups_member_updated(context, port)
@ -219,6 +233,9 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
context, id)
updated_port = super(RyuNeutronPluginV2, self).update_port(
context, id, port)
self._process_portbindings_create_and_update(context,
port['port'],
updated_port)
need_port_update_notify = self.update_security_group_on_port(
context, id, port, original_port, updated_port)
@ -234,15 +251,3 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
if deleted:
db_api_v2.set_port_status(session, id, q_const.PORT_STATUS_DOWN)
return updated_port
def get_port(self, context, id, fields=None):
with context.session.begin(subtransactions=True):
port = super(RyuNeutronPluginV2, self).get_port(context, id,
fields)
return self._fields(port, fields)
def get_ports(self, context, filters=None, fields=None):
with context.session.begin(subtransactions=True):
ports = super(RyuNeutronPluginV2, self).get_ports(
context, filters, fields)
return [self._fields(port, fields) for port in ports]