BSN: Bind external ports in ML2 driver
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
This commit is contained in:
parent
cc8a57cb04
commit
cd1292fee4
@ -34,6 +34,7 @@ from neutron.plugins.common import constants as pconst
|
|||||||
from neutron.plugins.ml2 import driver_api as api
|
from neutron.plugins.ml2 import driver_api as api
|
||||||
|
|
||||||
|
|
||||||
|
EXTERNAL_PORT_OWNER = 'neutron:external_port'
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
# time in seconds to maintain existence of vswitch response
|
# time in seconds to maintain existence of vswitch response
|
||||||
@ -137,16 +138,32 @@ class BigSwitchMechanismDriver(plugin.NeutronRestProxyV2Base,
|
|||||||
return prepped_port
|
return prepped_port
|
||||||
|
|
||||||
def bind_port(self, context):
|
def bind_port(self, context):
|
||||||
if not self.does_vswitch_exist(context.host):
|
"""Marks ports as bound.
|
||||||
# this is not an IVS host
|
|
||||||
return
|
|
||||||
|
|
||||||
# currently only vlan segments are supported
|
Binds external ports and IVS ports.
|
||||||
for segment in context.network.network_segments:
|
Fabric configuration will occur on the subsequent port update.
|
||||||
if segment[api.NETWORK_TYPE] == pconst.TYPE_VLAN:
|
Currently only vlan segments are supported.
|
||||||
context.set_binding(segment[api.ID], portbindings.VIF_TYPE_IVS,
|
"""
|
||||||
{portbindings.CAP_PORT_FILTER: True,
|
if context.current['device_owner'] == EXTERNAL_PORT_OWNER:
|
||||||
portbindings.OVS_HYBRID_PLUG: False})
|
# 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):
|
def does_vswitch_exist(self, host):
|
||||||
"""Check if Indigo vswitch exists with the given hostname.
|
"""Check if Indigo vswitch exists with the given hostname.
|
||||||
|
@ -23,8 +23,10 @@ import webob.exc
|
|||||||
from neutron import context as neutron_context
|
from neutron import context as neutron_context
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
|
from neutron.openstack.common import jsonutils
|
||||||
from neutron.plugins.bigswitch import servermanager
|
from neutron.plugins.bigswitch import servermanager
|
||||||
from neutron.plugins.ml2 import config as ml2_config
|
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
|
from neutron.plugins.ml2.drivers import type_vlan as vlan_config
|
||||||
import neutron.tests.unit.bigswitch.test_restproxy_plugin as trp
|
import neutron.tests.unit.bigswitch.test_restproxy_plugin as trp
|
||||||
from neutron.tests.unit.ml2 import test_ml2_plugin
|
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.assertEqual('host', pb['binding:host_id'])
|
||||||
self.assertIn('bound_segment', pb)
|
self.assertIn('bound_segment', pb)
|
||||||
self.assertIn('network', 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user