]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Replace binding:capabilities with binding:vif_details
authorBob Kukura <rkukura@redhat.com>
Tue, 4 Feb 2014 04:18:44 +0000 (23:18 -0500)
committerBob Kukura <rkukura@redhat.com>
Mon, 24 Feb 2014 03:56:45 +0000 (22:56 -0500)
In addition to binding:vif_type, the neutron core plugin needs to
supply various information to nova's VIF driver, such as VIF security
details and PCI details when SR-IOV is being used. This information is
read-only, requires admin privileges, and is not intended for normal
users. Rather than add separate mechanisms throughout the stack for
each such requirement, the binding:capabilities port attibute, which
is a dictionary and is not currently not used by nova, is renamed to
binding:vif_details to serve as a general-purpose mechanism for
supplying binding-specific details to the VIF driver.

This patch does not remove or replace the CAP_PORT_FILTER boolean
previously used in binding:capabilities. A separate patch should
implement the specific key/value pairs carried by binding:vif_details
to implement VIF security. Another patch will implement the key/value
pairs needed for SR-IOV.

The ML2 plugin now allows the bound mechanism driver to supply the
binding:vif_details dictionary content, instead of just the
CAP_PORT_FILTER boolean previously carried by the binding:capabilities
attribute.

DocImpact: Need to update portbinding extension API, but no impact on
user or administrator documentation.

Implements: blueprint vif-details
Related-Bug: 1112912
Change-Id: I34be746fcfa73c70f72b4f9add8eff3ac88c723f

28 files changed:
etc/policy.json
neutron/db/migration/alembic_migrations/versions/50d5ba354c23_ml2_binding_vif_details.py [new file with mode: 0644]
neutron/extensions/portbindings.py
neutron/plugins/bigswitch/plugin.py
neutron/plugins/brocade/NeutronPlugin.py
neutron/plugins/linuxbridge/lb_neutron_plugin.py
neutron/plugins/midonet/plugin.py
neutron/plugins/ml2/db.py
neutron/plugins/ml2/driver_api.py
neutron/plugins/ml2/driver_context.py
neutron/plugins/ml2/drivers/mech_agent.py
neutron/plugins/ml2/drivers/mech_hyperv.py
neutron/plugins/ml2/drivers/mech_linuxbridge.py
neutron/plugins/ml2/drivers/mech_openvswitch.py
neutron/plugins/ml2/managers.py
neutron/plugins/ml2/models.py
neutron/plugins/ml2/plugin.py
neutron/plugins/mlnx/mlnx_plugin.py
neutron/plugins/nec/nec_plugin.py
neutron/plugins/nicira/NeutronPlugin.py
neutron/plugins/openvswitch/ovs_neutron_plugin.py
neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py
neutron/plugins/ryu/ryu_neutron_plugin.py
neutron/policy.py
neutron/tests/unit/_test_extension_portbindings.py
neutron/tests/unit/ml2/_test_mech_agent.py
neutron/tests/unit/ml2/drivers/mechanism_test.py
neutron/tests/unit/ml2/test_port_binding.py

index bd0bc9274c704bc4d730b54575ed580944c2a897..f2dfa0f4b49e3a7806a3e8b4b6140044281adcb0 100644 (file)
@@ -52,7 +52,7 @@
     "get_port": "rule:admin_or_owner",
     "get_port:queue_id": "rule:admin_only",
     "get_port:binding:vif_type": "rule:admin_only",
-    "get_port:binding:capabilities": "rule:admin_only",
+    "get_port:binding:vif_details": "rule:admin_only",
     "get_port:binding:host_id": "rule:admin_only",
     "get_port:binding:profile": "rule:admin_only",
     "get_port:binding:vnic_type": "rule:admin_or_owner",
diff --git a/neutron/db/migration/alembic_migrations/versions/50d5ba354c23_ml2_binding_vif_details.py b/neutron/db/migration/alembic_migrations/versions/50d5ba354c23_ml2_binding_vif_details.py
new file mode 100644 (file)
index 0000000..fc50807
--- /dev/null
@@ -0,0 +1,59 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2014 OpenStack Foundation
+#
+#    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.
+#
+
+"""ml2 binding:vif_details
+
+Revision ID: 50d5ba354c23
+Revises: 27cc183af192
+Create Date: 2014-02-11 23:21:59.577972
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '50d5ba354c23'
+down_revision = '27cc183af192'
+
+# Change to ['*'] if this migration applies to all plugins
+
+migration_for_plugins = [
+    'neutron.plugins.ml2.plugin.Ml2Plugin'
+]
+
+from alembic import op
+import sqlalchemy as sa
+
+from neutron.db import migration
+
+
+def upgrade(active_plugins=None, options=None):
+    if not migration.should_run(active_plugins, migration_for_plugins):
+        return
+
+    op.add_column('ml2_port_bindings',
+                  sa.Column('vif_details', sa.String(length=4095),
+                            nullable=False, server_default=''))
+    op.drop_column('ml2_port_bindings', 'cap_port_filter')
+
+
+def downgrade(active_plugins=None, options=None):
+    if not migration.should_run(active_plugins, migration_for_plugins):
+        return
+
+    op.add_column('ml2_port_bindings',
+                  sa.Column('cap_port_filter', sa.Boolean(),
+                            nullable=False, server_default=False))
+    op.drop_column('ml2_port_bindings', 'vif_details')
index 4ed38fc239023556d659275ea64a5ccc9da3a33e..6c1ed7ed407ea3a0974d72cb41458a26390a4983 100644 (file)
@@ -22,6 +22,10 @@ from neutron.api.v2 import attributes
 VNIC_TYPE = 'binding:vnic_type'
 # The service will return the vif type for the specific port.
 VIF_TYPE = 'binding:vif_type'
+# The service may return a dictionary containing additional
+# information needed by the interface driver. The set of items
+# returned may depend on the value of VIF_TYPE.
+VIF_DETAILS = 'binding:vif_details'
 # In some cases different implementations may be run on different hosts.
 # The host on which the port will be allocated.
 HOST_ID = 'binding:host_id'
@@ -29,11 +33,16 @@ HOST_ID = 'binding:host_id'
 # on the specific host to pass and receive vif port specific information to
 # the plugin.
 PROFILE = 'binding:profile'
-# The capabilities will be a dictionary that enables pass information about
-# functionalies neutron provides. The following value should be provided.
+
+# The keys below are used in the VIF_DETAILS attribute to convey
+# information to the VIF driver.
+
+# TODO(rkukura): Replace CAP_PORT_FILTER, which nova no longer
+# understands, with the new set of VIF security details to be used in
+# the VIF_DETAILS attribute.
+#
 #  - port_filter : Boolean value indicating Neutron provides port filtering
 #                  features such as security group and anti MAC/IP spoofing
-CAPABILITIES = 'binding:capabilities'
 CAP_PORT_FILTER = 'port_filter'
 
 VIF_TYPE_UNBOUND = 'unbound'
@@ -63,6 +72,10 @@ EXTENDED_ATTRIBUTES_2_0 = {
                    'default': attributes.ATTR_NOT_SPECIFIED,
                    'enforce_policy': True,
                    'is_visible': True},
+        VIF_DETAILS: {'allow_post': False, 'allow_put': False,
+                      'default': attributes.ATTR_NOT_SPECIFIED,
+                      'enforce_policy': True,
+                      'is_visible': True},
         VNIC_TYPE: {'allow_post': True, 'allow_put': True,
                     'default': VNIC_NORMAL,
                     'is_visible': True,
@@ -77,10 +90,6 @@ EXTENDED_ATTRIBUTES_2_0 = {
                   'enforce_policy': True,
                   'validate': {'type:dict_or_none': None},
                   'is_visible': True},
-        CAPABILITIES: {'allow_post': False, 'allow_put': False,
-                       'default': attributes.ATTR_NOT_SPECIFIED,
-                       'enforce_policy': True,
-                       'is_visible': True},
     }
 }
 
@@ -112,7 +121,7 @@ class Portbindings(extensions.ExtensionDescriptor):
 
     @classmethod
     def get_updated(cls):
-        return "2012-11-14T10:00:00-00:00"
+        return "2014-02-03T10:00:00-00:00"
 
     def get_extended_resources(self, version):
         if version == "2.0":
index a80385d4f86d002b873d2bd00690c9d1a9addff9..fb4421a2a31bc73e43645b248ec0a9e1d55fc248 100644 (file)
@@ -300,7 +300,8 @@ class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2,
                 cfg_vif_type = override
         port[portbindings.VIF_TYPE] = cfg_vif_type
 
-        port[portbindings.CAPABILITIES] = {
+        port[portbindings.VIF_DETAILS] = {
+            # TODO(rkukura): Replace with new VIF security details
             portbindings.CAP_PORT_FILTER:
             'security-group' in self.supported_extension_aliases}
         return port
index f5a04ad205a5a78ed841cbf7fff29bb99b7c3cc8..ed27f2881ac388dc1b9cba46a8329abee01c7024 100644 (file)
@@ -478,7 +478,8 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
     def _get_base_binding_dict(self):
         binding = {
             portbindings.VIF_TYPE: portbindings.VIF_TYPE_BRIDGE,
-            portbindings.CAPABILITIES: {
+            portbindings.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 portbindings.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
         return binding
index c06ce6a76edcd9d3cbb9229a1c9e025fa168ea73..4cd1f8155ed0bb914af24285fb79dc6bdf4a616a 100644 (file)
@@ -255,7 +255,8 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         super(LinuxBridgePluginV2, self).__init__()
         self.base_binding_dict = {
             portbindings.VIF_TYPE: portbindings.VIF_TYPE_BRIDGE,
-            portbindings.CAPABILITIES: {
+            portbindings.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 portbindings.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
         self._parse_network_vlan_ranges()
index 984736dcbc673f986f76c1af2cd7480f88bc2959..2977b9b3dd8754781fb2b7b2ce93a0c0a1b16a70 100644 (file)
@@ -234,7 +234,8 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
 
         self.base_binding_dict = {
             portbindings.VIF_TYPE: portbindings.VIF_TYPE_MIDONET,
-            portbindings.CAPABILITIES: {
+            portbindings.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 portbindings.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
 
index 0a2d981a5fc075815ea25c978d5485e3955d204d..00475070dc18e24b06715ee734099de21f0ed02a 100644 (file)
@@ -66,8 +66,7 @@ def ensure_port_binding(session, port_id):
             record = models.PortBinding(
                 port_id=port_id,
                 host='',
-                vif_type=portbindings.VIF_TYPE_UNBOUND,
-                cap_port_filter=False)
+                vif_type=portbindings.VIF_TYPE_UNBOUND)
             session.add(record)
         return record
 
index d7663042b9a851e5c904e3b1118d6927f091c59e..f6167e761cd4d32380bdf8d7633e9bc1bf2b2bf8 100644 (file)
@@ -246,12 +246,12 @@ class PortContext(object):
         pass
 
     @abstractmethod
-    def set_binding(self, segment_id, vif_type, cap_port_filter):
+    def set_binding(self, segment_id, vif_type, vif_details):
         """Set the binding for the port.
 
         :param segment_id: Network segment bound for the port.
         :param vif_type: The VIF type for the bound port.
-        :param cap_port_filter: True if the bound port filters.
+        :param vif_details: Dictionary with details for VIF driver.
 
         Called by MechanismDriver.bind_port to indicate success and
         specify binding details to use for port. The segment_id must
index 7468192f7472c97aa654b421959c4e83db212d1e..89f4e61ac7fe814e12c0541e4ebf493d64fca59d 100644 (file)
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from neutron.openstack.common import jsonutils
 from neutron.plugins.ml2 import db
 from neutron.plugins.ml2 import driver_api as api
 
@@ -103,12 +104,8 @@ class PortContext(MechanismDriverContext, api.PortContext):
                                        filters={'agent_type': [agent_type],
                                                 'host': [self._binding.host]})
 
-    def set_binding(self, segment_id, vif_type, cap_port_filter):
-        # REVISIT(rkukura): Pass extensible list of capabilities? Move
-        # vif_type and capabilities to methods on the bound mechanism
-        # driver?
-
+    def set_binding(self, segment_id, vif_type, vif_details):
         # TODO(rkukura) Verify binding allowed, segment in network
         self._binding.segment = segment_id
         self._binding.vif_type = vif_type
-        self._binding.cap_port_filter = cap_port_filter
+        self._binding.vif_details = jsonutils.dumps(vif_details)
index 2081057dad755675e307c49a96fa28f16b63cf3c..319055a891674cbdcadeb25656d807ab305b6c0b 100644 (file)
@@ -34,21 +34,19 @@ class AgentMechanismDriverBase(api.MechanismDriver):
     running on the port's host, and that agent to have connectivity to
     at least one segment of the port's network.
 
-    MechanismDrivers using this base class must pass the agent type
-    and VIF type constants to __init__(), and must implement
+    MechanismDrivers using this base class must pass the agent type to
+    __init__(), and must implement try_to_bind_segment_for_agent() and
     check_segment_for_agent().
     """
 
-    def __init__(self, agent_type, vif_type, cap_port_filter,
+    def __init__(self, agent_type,
                  supported_vnic_types=[portbindings.VNIC_NORMAL]):
         """Initialize base class for specific L2 agent type.
 
         :param agent_type: Constant identifying agent type in agents_db
-        :param vif_type: Value for binding:vif_type to when bound
+        :param supported_vnic_types: The binding:vnic_type values we can bind
         """
         self.agent_type = agent_type
-        self.vif_type = vif_type
-        self.cap_port_filter = cap_port_filter
         self.supported_vnic_types = supported_vnic_types
 
     def initialize(self):
@@ -69,10 +67,8 @@ class AgentMechanismDriverBase(api.MechanismDriver):
             LOG.debug(_("Checking agent: %s"), agent)
             if agent['alive']:
                 for segment in context.network.network_segments:
-                    if self.check_segment_for_agent(segment, agent):
-                        context.set_binding(segment[api.ID],
-                                            self.vif_type,
-                                            self.cap_port_filter)
+                    if self.try_to_bind_segment_for_agent(context, segment,
+                                                          agent):
                         LOG.debug(_("Bound using segment: %s"), segment)
                         return
             else:
@@ -99,6 +95,25 @@ class AgentMechanismDriverBase(api.MechanismDriver):
                   {'port': context.current['id'],
                    'network': context.network.current['id']})
 
+    @abstractmethod
+    def try_to_bind_segment_for_agent(self, context, segment, agent):
+        """Try to bind with segment for agent.
+
+        :param context: PortContext instance describing the port
+        :param segment: segment dictionary describing segment to bind
+        :param agent: agents_db entry describing agent to bind
+        :returns: True iff segment has been bound for agent
+
+        Called inside transaction during bind_port() so that derived
+        MechanismDrivers can use agent_db data along with built-in
+        knowledge of the corresponding agent's capabilities to attempt
+        to bind to the specified network segment for the agent.
+
+        If the segment can be bound for the agent, this function must
+        call context.set_binding() with appropriate values and then
+        return True. Otherwise, it must return False.
+        """
+
     @abstractmethod
     def check_segment_for_agent(self, segment, agent):
         """Check if segment can be bound for agent.
@@ -107,9 +122,49 @@ class AgentMechanismDriverBase(api.MechanismDriver):
         :param agent: agents_db entry describing agent to bind
         :returns: True iff segment can be bound for agent
 
-        Called inside transaction during bind_port() and
-        validate_port_binding() so that derived MechanismDrivers can
-        use agent_db data along with built-in knowledge of the
-        corresponding agent's capabilities to determine whether or not
-        the specified network segment can be bound for the agent.
+        Called inside transaction during validate_port_binding() so
+        that derived MechanismDrivers can use agent_db data along with
+        built-in knowledge of the corresponding agent's capabilities
+        to determine whether or not the specified network segment can
+        be bound for the agent.
         """
+
+
+@six.add_metaclass(ABCMeta)
+class SimpleAgentMechanismDriverBase(AgentMechanismDriverBase):
+    """Base class for simple drivers using an L2 agent.
+
+    The SimpleAgentMechanismDriverBase provides common code for
+    mechanism drivers that integrate the ml2 plugin with L2 agents,
+    where the binding:vif_type and binding:vif_details values are the
+    same for all bindings. Port binding with this driver requires the
+    driver's associated agent to be running on the port's host, and
+    that agent to have connectivity to at least one segment of the
+    port's network.
+
+    MechanismDrivers using this base class must pass the agent type
+    and the values for binding:vif_type and binding:vif_details to
+    __init__(). They must implement check_segment_for_agent() as
+    defined in AgentMechanismDriverBase, which will be called during
+    both binding establishment and validation.
+    """
+
+    def __init__(self, agent_type, vif_type, vif_details,
+                 supported_vnic_types=[portbindings.VNIC_NORMAL]):
+        """Initialize base class for specific L2 agent type.
+
+        :param agent_type: Constant identifying agent type in agents_db
+        :param vif_type: Value for binding:vif_type when bound
+        :param vif_details: Dictionary with details for VIF driver when bound
+        :param supported_vnic_types: The binding:vnic_type values we can bind
+        """
+        super(SimpleAgentMechanismDriverBase, self).__init__(
+            agent_type, supported_vnic_types)
+        self.vif_type = vif_type
+        self.vif_details = vif_details
+
+    def try_to_bind_segment_for_agent(self, context, segment, agent):
+        if self.check_segment_for_agent(segment, agent):
+            context.set_binding(segment[api.ID],
+                                self.vif_type,
+                                self.vif_details)
index 87cf6c22c433865af572b01ee817de01575594f5..b384d3425ec9ae1e8bee201129bfff7fb4d9a041 100644 (file)
@@ -24,7 +24,7 @@ from neutron.plugins.ml2.drivers import mech_agent
 LOG = log.getLogger(__name__)
 
 
-class HypervMechanismDriver(mech_agent.AgentMechanismDriverBase):
+class HypervMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
     """Attach to networks using hyperv L2 agent.
 
     The HypervMechanismDriver integrates the ml2 plugin with the
@@ -37,7 +37,7 @@ class HypervMechanismDriver(mech_agent.AgentMechanismDriverBase):
         super(HypervMechanismDriver, self).__init__(
             constants.AGENT_TYPE_HYPERV,
             portbindings.VIF_TYPE_HYPERV,
-            False)
+            {portbindings.CAP_PORT_FILTER: False})
 
     def check_segment_for_agent(self, segment, agent):
         mappings = agent['configurations'].get('vswitch_mappings', {})
index 233737f46a42c179d7d68199f1201a53ea245b94..b304ad4bab1b3df1a62189a05d059656120e1a1b 100644 (file)
@@ -22,7 +22,7 @@ from neutron.plugins.ml2.drivers import mech_agent
 LOG = log.getLogger(__name__)
 
 
-class LinuxbridgeMechanismDriver(mech_agent.AgentMechanismDriverBase):
+class LinuxbridgeMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
     """Attach to networks using linuxbridge L2 agent.
 
     The LinuxbridgeMechanismDriver integrates the ml2 plugin with the
@@ -36,7 +36,7 @@ class LinuxbridgeMechanismDriver(mech_agent.AgentMechanismDriverBase):
         super(LinuxbridgeMechanismDriver, self).__init__(
             constants.AGENT_TYPE_LINUXBRIDGE,
             portbindings.VIF_TYPE_BRIDGE,
-            True)
+            {portbindings.CAP_PORT_FILTER: True})
 
     def check_segment_for_agent(self, segment, agent):
         mappings = agent['configurations'].get('interface_mappings', {})
index f98ddf28867febd01f34330227157e614a8f9e94..b070bb9e7c9be310eccd9f746ef170ad593a5f1e 100644 (file)
@@ -22,7 +22,7 @@ from neutron.plugins.ml2.drivers import mech_agent
 LOG = log.getLogger(__name__)
 
 
-class OpenvswitchMechanismDriver(mech_agent.AgentMechanismDriverBase):
+class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
     """Attach to networks using openvswitch L2 agent.
 
     The OpenvswitchMechanismDriver integrates the ml2 plugin with the
@@ -36,7 +36,7 @@ class OpenvswitchMechanismDriver(mech_agent.AgentMechanismDriverBase):
         super(OpenvswitchMechanismDriver, self).__init__(
             constants.AGENT_TYPE_OVS,
             portbindings.VIF_TYPE_OVS,
-            True)
+            {portbindings.CAP_PORT_FILTER: True})
 
     def check_segment_for_agent(self, segment, agent):
         mappings = agent['configurations'].get('bridge_mappings', {})
index 424f9f5d096dadcc44f6192799ac13e1a4f8ea6c..516beddb449a2c40350a73ebda650f546809e34a 100644 (file)
@@ -450,14 +450,14 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
                     LOG.debug(_("Bound port: %(port)s, host: %(host)s, "
                                 "vnic_type: %(vnic_type)s, "
                                 "driver: %(driver)s, vif_type: %(vif_type)s, "
-                                "cap_port_filter: %(cap_port_filter)s, "
+                                "vif_details: %(vif_details)s, "
                                 "segment: %(segment)s"),
                               {'port': context._port['id'],
                                'host': binding.host,
+                               'vnic_type': binding.vnic_type,
                                'driver': binding.driver,
                                'vif_type': binding.vif_type,
-                               'vnic_type': binding.vnic_type,
-                               'cap_port_filter': binding.cap_port_filter,
+                               'vif_details': binding.vif_details,
                                'segment': binding.segment})
                     return
             except Exception:
@@ -509,6 +509,6 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
                                 "unbind_port"),
                               driver.name)
         binding.vif_type = portbindings.VIF_TYPE_UNBOUND
-        binding.cap_port_filter = False
+        binding.vif_details = ''
         binding.driver = None
         binding.segment = None
index f17fa1cdb588bb7de02fed5463863dff4ca07899..26aa11cff2f08460e8616ef6cde885d3658a8df2 100644 (file)
@@ -57,7 +57,7 @@ class PortBinding(model_base.BASEV2):
     vnic_type = sa.Column(sa.String(64), nullable=False,
                           default=portbindings.VNIC_NORMAL)
     vif_type = sa.Column(sa.String(64), nullable=False)
-    cap_port_filter = sa.Column(sa.Boolean, nullable=False)
+    vif_details = sa.Column(sa.String(4095), nullable=False, default='')
     driver = sa.Column(sa.String(64))
     segment = sa.Column(sa.String(36),
                         sa.ForeignKey('ml2_network_segments.id',
index 67d788548ba6e9ad2b59b85136ac6290d2dd615f..ddb5d62943d83c041e99bf486f51d9ac66c34673 100644 (file)
@@ -40,6 +40,7 @@ from neutron import manager
 from neutron.openstack.common import db as os_db
 from neutron.openstack.common import excutils
 from neutron.openstack.common import importutils
+from neutron.openstack.common import jsonutils
 from neutron.openstack.common import log
 from neutron.openstack.common import rpc as c_rpc
 from neutron.plugins.common import constants as service_constants
@@ -242,8 +243,18 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
         port[portbindings.HOST_ID] = binding.host
         port[portbindings.VNIC_TYPE] = binding.vnic_type
         port[portbindings.VIF_TYPE] = binding.vif_type
-        port[portbindings.CAPABILITIES] = {
-            portbindings.CAP_PORT_FILTER: binding.cap_port_filter}
+        port[portbindings.VIF_DETAILS] = self._get_vif_details(binding)
+
+    def _get_vif_details(self, binding):
+        if binding.vif_details:
+            try:
+                return jsonutils.loads(binding.vif_details)
+            except Exception:
+                LOG.error(_("Serialized vif_details DB value '%(value)s' "
+                            "for port %(port)s is invalid"),
+                          {'value': binding.vif_details,
+                           'port': binding.port_id})
+        return {}
 
     def _delete_port_binding(self, mech_context):
         binding = mech_context._binding
index cee2e4b3d8e978ce29935fc018294635df562484..28ceac7f284020602ad4bbb751ebba59bf54ff70 100644 (file)
@@ -102,7 +102,8 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
         self.vnic_type = cfg.CONF.ESWITCH.vnic_type
         self.base_binding_dict = {
             portbindings.VIF_TYPE: self.vnic_type,
-            portbindings.CAPABILITIES: {
+            portbindings.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 portbindings.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
         self._setup_rpc()
index 1b04af5307fb12ed9b44de4710754bd48f16a970..4f8dcad18406560159e994cab4f8ddefbaa5db1c 100644 (file)
@@ -381,7 +381,8 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
     def _get_base_binding_dict(self):
         binding = {
             portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
-            portbindings.CAPABILITIES: {
+            portbindings.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 portbindings.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
         return binding
index a6f145909f7145f0a5d94975481da419cfaf5001..f047624919837aa820c3de8aac75d86ef87f4910 100644 (file)
@@ -183,7 +183,8 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
 
         self.base_binding_dict = {
             pbin.VIF_TYPE: pbin.VIF_TYPE_OVS,
-            pbin.CAPABILITIES: {
+            pbin.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 pbin.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
 
index fde00edeb1e8c89898f209d91d29799438c09f46..55b7827b9f231d65b4984ae46a58a9cef12613e2 100644 (file)
@@ -297,7 +297,8 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         super(OVSNeutronPluginV2, self).__init__()
         self.base_binding_dict = {
             portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
-            portbindings.CAPABILITIES: {
+            portbindings.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 portbindings.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
         self._parse_network_vlan_ranges()
index 1f8f99c0d94128b8432c6b0b41f14eea7a7895a9..664ca8003b49c63e0592ef724258657d8d10077b 100644 (file)
@@ -545,7 +545,8 @@ class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2,
 
     def _port_viftype_binding(self, context, port):
         port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_IOVISOR
-        port[portbindings.CAPABILITIES] = {
+        port[portbindings.VIF_DETAILS] = {
+            # TODO(rkukura): Replace with new VIF security details
             portbindings.CAP_PORT_FILTER:
             'security-group' in self.supported_extension_aliases}
         return port
index c81b2069f03f673db8cd37b4df9011661197c433..01ca69996aff2945bd450e07e330b8958d75aae6 100644 (file)
@@ -112,7 +112,8 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
         super(RyuNeutronPluginV2, self).__init__()
         self.base_binding_dict = {
             portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
-            portbindings.CAPABILITIES: {
+            portbindings.VIF_DETAILS: {
+                # TODO(rkukura): Replace with new VIF security details
                 portbindings.CAP_PORT_FILTER:
                 'security-group' in self.supported_extension_aliases}}
         portbindings_base.register_port_dict_function()
index 6906373c985f694b761e7db22608907c54b75e9f..fbd43fd0f6bd8d394008128b637733e13fdc0dc4 100644 (file)
@@ -46,7 +46,7 @@ DEPRECATED_POLICY_MAP = {
     'extension:router':
     ['network:router:external'],
     'extension:port_binding':
-    ['port:binding:vif_type', 'port:binding:capabilities',
+    ['port:binding:vif_type', 'port:binding:vif_details',
      'port:binding:profile', 'port:binding:host_id']
 }
 DEPRECATED_ACTION_MAP = {
index 5e52629a574318767426c4804ee99bd1f8370163..4852d565304f79a0c19c58527e5ea62e3e822725 100644 (file)
@@ -39,15 +39,19 @@ class PortBindingsTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
     HAS_PORT_FILTER = False
 
     def _check_response_portbindings(self, port):
-        self.assertEqual(port['binding:vif_type'], self.VIF_TYPE)
-        port_cap = port[portbindings.CAPABILITIES]
-        self.assertEqual(port_cap[portbindings.CAP_PORT_FILTER],
-                         self.HAS_PORT_FILTER)
+        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)
 
     def _check_response_no_portbindings(self, port):
         self.assertIn('status', port)
         self.assertNotIn(portbindings.VIF_TYPE, port)
-        self.assertNotIn(portbindings.CAPABILITIES, port)
+        self.assertNotIn(portbindings.VIF_DETAILS, port)
 
     def _get_non_admin_context(self):
         return context.Context(user_id=None,
index 876cb1d754259acf1711442d1334921797250c80..0714b58907dac00f4ecd37a433a8d4c493c27439 100644 (file)
@@ -46,8 +46,7 @@ class FakePortContext(api.PortContext):
         self._network_context = FakeNetworkContext(segments)
         self._bound_segment_id = None
         self._bound_vif_type = None
-        self._bound_vnic_type = portbindings.VNIC_NORMAL
-        self._bound_cap_port_filter = None
+        self._bound_vif_details = None
 
     @property
     def current(self):
@@ -74,10 +73,10 @@ class FakePortContext(api.PortContext):
         else:
             return []
 
-    def set_binding(self, segment_id, vif_type, cap_port_filter):
+    def set_binding(self, segment_id, vif_type, vif_details):
         self._bound_segment_id = segment_id
         self._bound_vif_type = vif_type
-        self._bound_cap_port_filter = cap_port_filter
+        self._bound_vif_details = vif_details
 
 
 class AgentMechanismBaseTestCase(base.BaseTestCase):
@@ -93,12 +92,15 @@ class AgentMechanismBaseTestCase(base.BaseTestCase):
     def _check_unbound(self, context):
         self.assertIsNone(context._bound_segment_id)
         self.assertIsNone(context._bound_vif_type)
-        self.assertIsNone(context._bound_cap_port_filter)
+        self.assertIsNone(context._bound_vif_details)
 
     def _check_bound(self, context, segment):
         self.assertEqual(context._bound_segment_id, segment[api.ID])
         self.assertEqual(context._bound_vif_type, self.VIF_TYPE)
-        self.assertEqual(context._bound_cap_port_filter, self.CAP_PORT_FILTER)
+        vif_details = context._bound_vif_details
+        self.assertIsNotNone(vif_details)
+        self.assertEqual(vif_details[portbindings.CAP_PORT_FILTER],
+                         self.CAP_PORT_FILTER)
 
 
 class AgentMechanismGenericTestCase(AgentMechanismBaseTestCase):
index 24a40550456ab5271587cd4a353b52306414b92f..0b3d98af71e848844a9052caa59011e12520c701 100644 (file)
@@ -116,9 +116,11 @@ class TestMechanismDriver(api.MechanismDriver):
         host = context.current.get(portbindings.HOST_ID, None)
         segment = context.network.network_segments[0][api.ID]
         if host == "host-ovs-no_filter":
-            context.set_binding(segment, portbindings.VIF_TYPE_OVS, False)
+            context.set_binding(segment, portbindings.VIF_TYPE_OVS,
+                                {portbindings.CAP_PORT_FILTER: False})
         elif host == "host-bridge-filter":
-            context.set_binding(segment, portbindings.VIF_TYPE_BRIDGE, True)
+            context.set_binding(segment, portbindings.VIF_TYPE_BRIDGE,
+                                {portbindings.CAP_PORT_FILTER: True})
 
     def validate_port_binding(self, context):
         self._check_port_context(context, False)
index c9f784f26c88cacac956a5985b0d1517098982ab..86e066892df2e20a419af5450dccea089af43428 100644 (file)
@@ -41,17 +41,20 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase):
         self.port_create_status = 'DOWN'
         self.plugin = manager.NeutronManager.get_plugin()
 
-    def _check_response(self, port, vif_type, has_port_filter):
-        self.assertEqual(port['binding:vif_type'], vif_type)
-        port_cap = port[portbindings.CAPABILITIES]
-        self.assertEqual(port_cap[portbindings.CAP_PORT_FILTER],
-                         has_port_filter)
+    def _check_response(self, port, vif_type, has_port_filter, bound):
+        self.assertEqual(port[portbindings.VIF_TYPE], vif_type)
+        vif_details = port[portbindings.VIF_DETAILS]
+        if bound:
+            # TODO(rkukura): Replace with new VIF security details
+            self.assertEqual(vif_details[portbindings.CAP_PORT_FILTER],
+                             has_port_filter)
 
     def _test_port_binding(self, host, vif_type, has_port_filter, bound):
         host_arg = {portbindings.HOST_ID: host}
         with self.port(name='name', arg_list=(portbindings.HOST_ID,),
                        **host_arg) as port:
-            self._check_response(port['port'], vif_type, has_port_filter)
+            self._check_response(port['port'], vif_type, has_port_filter,
+                                 bound)
             port_id = port['port']['id']
             details = self.plugin.callbacks.get_device_details(
                 None, agent_id="theAgentId", device=port_id)
@@ -95,9 +98,10 @@ class PortBindingTestCase(test_plugin.NeutronDbPluginV2TestCase):
                                             neutron_context=neutron_context)
                 port_data = updated_port['port']
                 if new_host is not None:
-                    self.assertEqual(port_data['binding:host_id'], new_host)
+                    self.assertEqual(port_data[portbindings.HOST_ID],
+                                     new_host)
                 else:
-                    self.assertEqual(port_data['binding:host_id'], host)
+                    self.assertEqual(port_data[portbindings.HOST_ID], host)
                 if new_host is not None and new_host != host:
                     notify_mock.assert_called_once_with(mock.ANY)
                 else: