]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
BSN: Bind external ports in ML2 driver
authorKevin Benton <blak111@gmail.com>
Thu, 21 Aug 2014 16:12:15 +0000 (09:12 -0700)
committerKevin Benton <blak111@gmail.com>
Tue, 2 Sep 2014 15:03:36 +0000 (08:03 -0700)
Add a binding capability to the Big Switch ML2 mechanism
driver to mark external ports as bound. Ports with the
owner type 'neutron:external_port' will be assigned to the first
VLAN segment available in the network. The port update operation
will then carry the HOST ID with the identifier to the backend
for the necessary fabric configuration.

Implements: blueprint bsn-ml2-ext-attach
Change-Id: I7b749ba5ef9a47b45be24f77656a10ed38e5e6ae

neutron/plugins/ml2/drivers/mech_bigswitch/driver.py
neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py

index 75f25cea924bad0253d61f68f6fb70b05edfadd8..dc8c12c33974e233d3e9d84386539cf4bf474ec8 100644 (file)
@@ -34,6 +34,7 @@ from neutron.plugins.common import constants as pconst
 from neutron.plugins.ml2 import driver_api as api
 
 
+EXTERNAL_PORT_OWNER = 'neutron:external_port'
 LOG = log.getLogger(__name__)
 
 # time in seconds to maintain existence of vswitch response
@@ -137,16 +138,32 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
         return prepped_port
 
     def bind_port(self, context):
-        if not self.does_vswitch_exist(context.host):
-            # this is not an IVS host
-            return
-
-        # currently only vlan segments are supported
-        for segment in context.network.network_segments:
-            if segment[api.NETWORK_TYPE] == pconst.TYPE_VLAN:
-                context.set_binding(segment[api.ID], portbindings.VIF_TYPE_IVS,
-                                    {portbindings.CAP_PORT_FILTER: True,
-                                     portbindings.OVS_HYBRID_PLUG: False})
+        """Marks ports as bound.
+
+        Binds external ports and IVS ports.
+        Fabric configuration will occur on the subsequent port update.
+        Currently only vlan segments are supported.
+        """
+        if context.current['device_owner'] == EXTERNAL_PORT_OWNER:
+            # TODO(kevinbenton): check controller to see if the port exists
+            # so this driver can be run in parallel with others that add
+            # support for external port bindings
+            for segment in context.network.network_segments:
+                if segment[api.NETWORK_TYPE] == pconst.TYPE_VLAN:
+                    context.set_binding(
+                        segment[api.ID], portbindings.VIF_TYPE_BRIDGE,
+                        {portbindings.CAP_PORT_FILTER: False,
+                         portbindings.OVS_HYBRID_PLUG: False})
+                    return
+
+        # IVS hosts will have a vswitch with the same name as the hostname
+        if self.does_vswitch_exist(context.host):
+            for segment in context.network.network_segments:
+                if segment[api.NETWORK_TYPE] == pconst.TYPE_VLAN:
+                    context.set_binding(
+                        segment[api.ID], portbindings.VIF_TYPE_IVS,
+                        {portbindings.CAP_PORT_FILTER: True,
+                        portbindings.OVS_HYBRID_PLUG: False})
 
     def does_vswitch_exist(self, host):
         """Check if Indigo vswitch exists with the given hostname.
index 2dbe2a6d6d165505b147df1cd80485e30368945d..f1c844734b9338c3e7a136017e927e1b0d068cd1 100644 (file)
@@ -23,8 +23,10 @@ import webob.exc
 from neutron import context as neutron_context
 from neutron.extensions import portbindings
 from neutron import manager
+from neutron.openstack.common import jsonutils
 from neutron.plugins.bigswitch import servermanager
 from neutron.plugins.ml2 import config as ml2_config
+from neutron.plugins.ml2.drivers.mech_bigswitch import driver as bsn_driver
 from neutron.plugins.ml2.drivers import type_vlan as vlan_config
 import neutron.tests.unit.bigswitch.test_restproxy_plugin as trp
 from neutron.tests.unit.ml2 import test_ml2_plugin
@@ -195,3 +197,18 @@ class TestBigSwitchMechDriverPortsV2(test_db_plugin.TestPortsV2,
             self.assertEqual('host', pb['binding:host_id'])
             self.assertIn('bound_segment', pb)
             self.assertIn('network', pb)
+
+    def test_bind_external_port(self):
+        ext_id = jsonutils.dumps({'type': 'vlan', 'chassis_id': 'FF',
+                                  'port_id': '1'})
+        port_kwargs = {
+            portbindings.HOST_ID: ext_id,
+            'device_owner': bsn_driver.EXTERNAL_PORT_OWNER
+        }
+        with contextlib.nested(
+            mock.patch(SERVER_POOL + '.rest_create_port'),
+            self.port(arg_list=(portbindings.HOST_ID,), **port_kwargs)
+        ) as (rmock, port):
+            create_body = rmock.mock_calls[-1][1][2]
+            self.assertIsNotNone(create_body['bound_segment'])
+            self.assertEqual(create_body[portbindings.HOST_ID], ext_id)