#server_ssl=True
#sync_data=True
#server_timeout=10
+
+[NOVA]
+# Specify the VIF_TYPE that will be controlled on the Nova compute instances
+# options: ivs or ovs
+# default: ovs
+# vif_type = ovs
# dhcp-agent uses cat
cat: RegExpFilter, cat, root, cat, /proc/\d+/cmdline
ovs-vsctl: CommandFilter, ovs-vsctl, root
+ivs-ctl: CommandFilter, ivs-ctl, root
# metadata proxy
metadata_proxy: CommandFilter, quantum-ns-metadata-proxy, root
device_name)
+class IVSInterfaceDriver(LinuxInterfaceDriver):
+ """Driver for creating an internal interface on an IVS bridge."""
+
+ DEV_NAME_PREFIX = 'tap'
+
+ def __init__(self, conf):
+ super(IVSInterfaceDriver, self).__init__(conf)
+ self.DEV_NAME_PREFIX = 'ns-'
+
+ def _get_tap_name(self, dev_name, prefix=None):
+ dev_name = dev_name.replace(prefix or self.DEV_NAME_PREFIX, 'tap')
+ return dev_name
+
+ def _ivs_add_port(self, device_name, port_id, mac_address):
+ cmd = ['ivs-ctl', 'add-port', device_name]
+ utils.execute(cmd, self.root_helper)
+
+ def plug(self, network_id, port_id, device_name, mac_address,
+ bridge=None, namespace=None, prefix=None):
+ """Plug in the interface."""
+ if not ip_lib.device_exists(device_name,
+ self.root_helper,
+ namespace=namespace):
+
+ ip = ip_lib.IPWrapper(self.root_helper)
+ tap_name = self._get_tap_name(device_name, prefix)
+
+ root_dev, ns_dev = ip.add_veth(tap_name, device_name)
+
+ self._ivs_add_port(tap_name, port_id, mac_address)
+
+ ns_dev = ip.device(device_name)
+ ns_dev.link.set_address(mac_address)
+
+ if self.conf.network_device_mtu:
+ ns_dev.link.set_mtu(self.conf.network_device_mtu)
+ root_dev.link.set_mtu(self.conf.network_device_mtu)
+
+ if namespace:
+ namespace_obj = ip.ensure_namespace(namespace)
+ namespace_obj.add_device_to_namespace(ns_dev)
+
+ ns_dev.link.set_up()
+ root_dev.link.set_up()
+ else:
+ LOG.warn(_("Device %s already exists"), device_name)
+
+ def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
+ """Unplug the interface."""
+ tap_name = self._get_tap_name(device_name, prefix)
+ try:
+ cmd = ['ivs-ctl', 'del-port', tap_name]
+ utils.execute(cmd, self.root_helper)
+ device = ip_lib.IPDevice(device_name,
+ self.root_helper,
+ namespace)
+ device.link.delete()
+ LOG.debug(_("Unplugged interface '%s'"), device_name)
+ except RuntimeError:
+ LOG.error(_("Failed unplugging interface '%s'"),
+ device_name)
+
+
class BridgeInterfaceDriver(LinuxInterfaceDriver):
"""Driver for creating bridge interfaces."""
VIF_TYPE_UNBOUND = 'unbound'
VIF_TYPE_BINDING_FAILED = 'binding_failed'
VIF_TYPE_OVS = 'ovs'
+VIF_TYPE_IVS = 'ivs'
VIF_TYPE_BRIDGE = 'bridge'
VIF_TYPE_802_QBG = '802.1qbg'
VIF_TYPE_802_QBH = '802.1qbh'
cfg.CONF.register_opts(restproxy_opts, "RESTPROXY")
+nova_opts = [
+ cfg.StrOpt('vif_type', default='ovs',
+ help=_("Virtual interface type to configure on "
+ "Nova compute nodes")),
+]
+
+
+cfg.CONF.register_opts(nova_opts, "NOVA")
+
+
# The following are used to invoke the API on the external controller
NET_RESOURCE_PATH = "/tenants/%s/networks"
PORT_RESOURCE_PATH = "/tenants/%s/networks/%s/ports"
return data
def _extend_port_dict_binding(self, context, port):
- port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_OVS
+ cfg_vif_type = cfg.CONF.NOVA.vif_type.lower()
+ if not cfg_vif_type in (portbindings.VIF_TYPE_OVS,
+ portbindings.VIF_TYPE_IVS):
+ LOG.warning(_("Unrecognized vif_type in configuration "
+ "[%s]. Defaulting to ovs. "),
+ cfg_vif_type)
+ cfg_vif_type = portbindings.VIF_TYPE_OVS
+
+ port[portbindings.VIF_TYPE] = cfg_vif_type
+
port[portbindings.CAPABILITIES] = {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}
servers=localhost:8899
serverssl=False
#serverauth=username:password
+
+[NOVA]
+# Specify the VIF_TYPE that will be controlled on the Nova compute instances
+# options: ivs or ovs
+# default: ovs
+vif_type = ovs
+
import os
from mock import patch
+from oslo.config import cfg
import quantum.common.test_lib as test_lib
from quantum.extensions import portbindings
HAS_PORT_FILTER = False
+class TestBigSwitchProxyPortsV2IVS(test_plugin.TestPortsV2,
+ BigSwitchProxyPluginV2TestCase,
+ test_bindings.PortBindingsTestCase):
+ VIF_TYPE = portbindings.VIF_TYPE_IVS
+ HAS_PORT_FILTER = False
+
+ def setUp(self):
+ super(TestBigSwitchProxyPortsV2IVS,
+ self).setUp()
+ cfg.CONF.set_override('vif_type', 'ivs', 'NOVA')
+
+
class TestBigSwitchProxyNetworksV2(test_plugin.TestNetworksV2,
BigSwitchProxyPluginV2TestCase):
namespace=namespace)
self.ip_dev.assert_has_calls(expected)
self.assertEquals('fake1', plugin_tag1)
+
+
+class TestIVSInterfaceDriver(TestBase):
+
+ def setUp(self):
+ super(TestIVSInterfaceDriver, self).setUp()
+
+ def test_get_device_name(self):
+ br = interface.IVSInterfaceDriver(self.conf)
+ device_name = br.get_device_name(FakePort())
+ self.assertEqual('ns-abcdef01-12', device_name)
+
+ def test_plug_with_prefix(self):
+ self._test_plug(devname='qr-0', prefix='qr-')
+
+ def _test_plug(self, devname=None, namespace=None,
+ prefix=None, mtu=None):
+
+ if not devname:
+ devname = 'ns-0'
+
+ def device_exists(dev, root_helper=None, namespace=None):
+ return dev == 'indigo'
+
+ ivs = interface.IVSInterfaceDriver(self.conf)
+ self.device_exists.side_effect = device_exists
+
+ root_dev = mock.Mock()
+ _ns_dev = mock.Mock()
+ ns_dev = mock.Mock()
+ self.ip().add_veth = mock.Mock(return_value=(root_dev, _ns_dev))
+ self.ip().device = mock.Mock(return_value=(ns_dev))
+ expected = [mock.call('sudo'), mock.call().add_veth('tap0', devname),
+ mock.call().device(devname)]
+
+ ivsctl_cmd = ['ivs-ctl', 'add-port', 'tap0']
+
+ with mock.patch.object(utils, 'execute') as execute:
+ ivs.plug('01234567-1234-1234-99',
+ 'port-1234',
+ devname,
+ 'aa:bb:cc:dd:ee:ff',
+ namespace=namespace,
+ prefix=prefix)
+ execute.assert_called_once_with(ivsctl_cmd, 'sudo')
+
+ ns_dev.assert_has_calls(
+ [mock.call.link.set_address('aa:bb:cc:dd:ee:ff')])
+ if mtu:
+ ns_dev.assert_has_calls([mock.call.link.set_mtu(mtu)])
+ root_dev.assert_has_calls([mock.call.link.set_mtu(mtu)])
+ if namespace:
+ expected.extend(
+ [mock.call().ensure_namespace(namespace),
+ mock.call().ensure_namespace().add_device_to_namespace(
+ mock.ANY)])
+
+ self.ip.assert_has_calls(expected)
+ root_dev.assert_has_calls([mock.call.link.set_up()])
+ ns_dev.assert_has_calls([mock.call.link.set_up()])
+
+ def test_plug_mtu(self):
+ self.conf.set_override('network_device_mtu', 9000)
+ self._test_plug(mtu=9000)
+
+ def test_plug_namespace(self):
+ self._test_plug(namespace='mynamespace')
+
+ def test_unplug(self):
+ ivs = interface.IVSInterfaceDriver(self.conf)
+ ivsctl_cmd = ['ivs-ctl', 'del-port', 'tap0']
+ with mock.patch.object(utils, 'execute') as execute:
+ ivs.unplug('ns-0')
+ execute.assert_called_once_with(ivsctl_cmd, 'sudo')
+ self.ip_dev.assert_has_calls([mock.call('ns-0', 'sudo', None),
+ mock.call().link.delete()])