diff --git a/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py b/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py index 75f25cea92..dc8c12c339 100644 --- a/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py +++ b/neutron/plugins/ml2/drivers/mech_bigswitch/driver.py @@ -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 + """Marks ports as bound. - # 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}) + 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. diff --git a/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py b/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py index 2dbe2a6d6d..f1c844734b 100644 --- a/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py +++ b/neutron/tests/unit/ml2/drivers/test_bigswitch_mech.py @@ -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)