# default: ovs
# vif_type = ovs
+# Overrides for vif types based on nova compute node host IDs
+# Comma separated list of host IDs to fix to a specific VIF type
+# The VIF type is taken from the end of the configuration item
+# node_override_vif_<vif_type>
+# For example, the following would set the VIF type to IVS for
+# host-id1 and host-id2
+# node_overrride_vif_ivs=host-id1,host-id2
+
[router]
# Specify the default router rules installed in newly created tenant routers
# Specify multiple times for multiple rules
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 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.
+#
+
+"""Table to track port to host associations
+
+Revision ID: 3cabb850f4a5
+Revises: 5918cbddab04
+Create Date: 2013-06-24 14:30:33.533562
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '3cabb850f4a5'
+down_revision = '5918cbddab04'
+
+# Change to ['*'] if this migration applies to all plugins
+
+migration_for_plugins = [
+ 'quantum.plugins.bigswitch.plugin.QuantumRestProxyV2'
+]
+
+from alembic import op
+import sqlalchemy as sa
+
+
+from quantum.db import migration
+
+
+def upgrade(active_plugin=None, options=None):
+ if not migration.should_run(active_plugin, migration_for_plugins):
+ return
+
+ ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('portlocations',
+ sa.Column('port_id', sa.String(length=255),
+ primary_key=True, nullable=False),
+ sa.Column('host_id',
+ sa.String(length=255), nullable=False)
+ )
+ ### end Alembic commands ###
+
+
+def downgrade(active_plugin=None, options=None):
+ if not migration.should_run(active_plugin, migration_for_plugins):
+ return
+
+ ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('portlocations')
+ ### end Alembic commands ###
VIF_TYPE_802_QBH = '802.1qbh'
VIF_TYPE_HYPERV = 'hyperv'
VIF_TYPE_OTHER = 'other'
+VIF_TYPES = [VIF_TYPE_UNBOUND, VIF_TYPE_BINDING_FAILED, VIF_TYPE_OVS,
+ VIF_TYPE_IVS, VIF_TYPE_BRIDGE, VIF_TYPE_802_QBG,
+ VIF_TYPE_802_QBH, VIF_TYPE_HYPERV, VIF_TYPE_OTHER]
+
EXTENDED_ATTRIBUTES_2_0 = {
'ports': {
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Big Switch Networks, 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: Kevin Benton, Big Switch Networks, Inc.
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013, Big Switch Networks
+# 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.
+
+import sqlalchemy as sa
+
+from quantum.db import model_base
+from quantum.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+class PortLocation(model_base.BASEV2):
+ port_id = sa.Column(sa.String(255), primary_key=True)
+ host_id = sa.Column(sa.String(255), nullable=False)
+
+
+def get_port_hostid(context, port_id):
+ with context.session.begin(subtransactions=True):
+ query = context.session.query(PortLocation)
+ res = query.filter_by(port_id=port_id).first()
+ if not res:
+ return False
+ return res.host_id
+
+
+def put_port_hostid(context, port_id, host_id):
+ if port_id == '':
+ LOG.warning(_("Received an empty port ID for host '%s'"), host_id)
+ return
+ with context.session.begin(subtransactions=True):
+ location = PortLocation(port_id=port_id, host_id=host_id)
+ context.session.add(location)
from quantum.extensions import portbindings
from quantum.openstack.common import log as logging
from quantum.openstack.common import rpc
+from quantum.plugins.bigswitch.db import porttracker_db
from quantum.plugins.bigswitch import routerrule_db
from quantum.plugins.bigswitch.version import version_string_with_vcs
"Nova compute nodes")),
]
+# Each VIF Type can have a list of nova host IDs that are fixed to that type
+for i in portbindings.VIF_TYPES:
+ opt = cfg.ListOpt('node_override_vif_' + i, default=[],
+ help=_("Nova compute nodes to manually set VIF "
+ "type to %s") % i)
+ nova_opts.append(opt)
+
+# Add the vif types for reference later
+nova_opts.append(cfg.ListOpt('vif_types', default=portbindings.VIF_TYPES))
cfg.CONF.register_opts(nova_opts, "NOVA")
# Update DB
port["port"]["admin_state_up"] = False
+ if (portbindings.HOST_ID in port['port']
+ and 'device_id' in port['port']):
+ porttracker_db.put_port_hostid(context, port['port']['device_id'],
+ port['port'][portbindings.HOST_ID])
new_port = super(QuantumRestProxyV2, self).create_port(context, port)
net = super(QuantumRestProxyV2,
self).get_network(context, new_port["network_id"])
# Update DB
new_port = super(QuantumRestProxyV2, self).update_port(context,
port_id, port)
-
+ if (portbindings.HOST_ID in port['port']
+ and 'device_id' in port['port']):
+ porttracker_db.put_port_hostid(context, port['port']['device_id'],
+ port['port'][portbindings.HOST_ID])
# update on networl ctrl
try:
resource = PORTS_PATH % (orig_port["tenant_id"],
"[%s]. Defaulting to ovs. "),
cfg_vif_type)
cfg_vif_type = portbindings.VIF_TYPE_OVS
-
+ hostid = porttracker_db.get_port_hostid(context,
+ port.get("device_id"))
+ if hostid:
+ override = self._check_hostvif_override(hostid)
+ if override:
+ cfg_vif_type = override
port[portbindings.VIF_TYPE] = cfg_vif_type
port[portbindings.CAPABILITIES] = {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}
return port
+
+ def _check_hostvif_override(self, hostid):
+ for v in cfg.CONF.NOVA.vif_types:
+ if hostid in getattr(cfg.CONF.NOVA, "node_override_vif_" + v, []):
+ return v
+ return False
# options: ivs or ovs
# default: ovs
vif_type = ovs
+# Overrides for vif types based on nova compute node host IDs
+# Comma separated list of host IDs to fix to a specific VIF type
+node_override_vif_ivs = ivshost
[router]
# Specify the default router rules installed in newly created tenant routers
from mock import patch
from oslo.config import cfg
+import webob.exc
import quantum.common.test_lib as test_lib
from quantum.extensions import portbindings
cfg.CONF.set_override('vif_type', 'ivs', 'NOVA')
+class TestBigSwitchVIFOverride(test_plugin.TestPortsV2,
+ BigSwitchProxyPluginV2TestCase,
+ test_bindings.PortBindingsTestCase):
+ VIF_TYPE = portbindings.VIF_TYPE_OVS
+ HAS_PORT_FILTER = False
+
+ def setUp(self):
+ super(TestBigSwitchVIFOverride,
+ self).setUp()
+ cfg.CONF.set_override('vif_type', 'ovs', 'NOVA')
+
+ def test_port_vif_details(self):
+ kwargs = {'name': 'name', 'binding:host_id': 'ivshost',
+ 'device_id': 'override_dev'}
+ with self.port(**kwargs) as port:
+ self.assertEqual(port['port']['binding:vif_type'],
+ portbindings.VIF_TYPE_IVS)
+ kwargs = {'name': 'name2', 'binding:host_id': 'someotherhost',
+ 'device_id': 'other_dev'}
+ with self.port(**kwargs) as port:
+ self.assertEqual(port['port']['binding:vif_type'], self.VIF_TYPE)
+
+ def _make_port(self, fmt, net_id, expected_res_status=None, **kwargs):
+ res = self._create_port(fmt, net_id, expected_res_status,
+ ('binding:host_id', ), **kwargs)
+ # Things can go wrong - raise HTTP exc with res code only
+ # so it can be caught by unit tests
+ if res.status_int >= 400:
+ raise webob.exc.HTTPClientError(code=res.status_int)
+ return self.deserialize(fmt, res)
+
+
class TestBigSwitchProxyNetworksV2(test_plugin.TestNetworksV2,
BigSwitchProxyPluginV2TestCase):