From 722b02d40e84619ad056b8fb5aa2d8de25fd1984 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 4 Apr 2016 17:50:39 +0100 Subject: [PATCH] vif_plug_ovs: merge both plugins into one There is no need to create separate plugins for each type of VIF configuration - a single plugin is intended to be capable of supporting multiple different VIF configs. On this basis, the ovs & ovs_hybrid plugins can be merged to just create a single 'ovs' plugin. This means that consumers of os-vif do not need to remember multiple different plugin names - they can always just use the 'ovs' plugin and feed it whichever type of VIF config they desire. Change-Id: I8ab37fea065a3d92585decf89bcc095c404e6ed2 Signed-off-by: Daniel P. Berrange --- setup.cfg | 3 +- vif_plug_ovs/ovs.py | 105 +++++++++++++++++++++++++-- vif_plug_ovs/ovs_hybrid.py | 116 ------------------------------ vif_plug_ovs/tests/test_plugin.py | 10 +-- 4 files changed, 104 insertions(+), 130 deletions(-) delete mode 100644 vif_plug_ovs/ovs_hybrid.py diff --git a/setup.cfg b/setup.cfg index 7f75f4e1..a911e610 100644 --- a/setup.cfg +++ b/setup.cfg @@ -58,5 +58,4 @@ output_file = os_vif/locale/os-vif.pot [entry_points] os_vif = linux_bridge = vif_plug_linux_bridge.linux_bridge:LinuxBridgePlugin - ovs = vif_plug_ovs.ovs:OvsBridgePlugin - ovs_hybrid = vif_plug_ovs.ovs_hybrid:OvsHybridPlugin + ovs = vif_plug_ovs.ovs:OvsPlugin diff --git a/vif_plug_ovs/ovs.py b/vif_plug_ovs/ovs.py index ec656b0d..022cfedb 100644 --- a/vif_plug_ovs/ovs.py +++ b/vif_plug_ovs/ovs.py @@ -19,25 +19,116 @@ from os_vif import objects from os_vif import plugin +from oslo_config import cfg + +from vif_plug_ovs import exception +from vif_plug_ovs import linux_net -class OvsBridgePlugin(plugin.PluginBase): - """An OVS VIF type that uses a standard Linux bridge for integration.""" +class OvsPlugin(plugin.PluginBase): + """An OVS plugin that can setup VIFs in many ways + + The OVS plugin supports several different VIF types, VIFBridge + and VIFOpenVSwitch, and will choose the appropriate plugging + action depending on the type of VIF config it receives. + + If given a VIFBridge, then it will create connect the VM via + a regular Linux bridge device to allow security group rules to + be applied to VM traiffic. + """ + + NIC_NAME_LEN = 14 + + CONFIG_OPTS = ( + cfg.IntOpt('network_device_mtu', + default=1500, + help='MTU setting for network interface.', + deprecated_group="DEFAULT"), + cfg.IntOpt('ovs_vsctl_timeout', + default=120, + help='Amount of time, in seconds, that ovs_vsctl should ' + 'wait for a response from the database. 0 is to wait ' + 'forever.', + deprecated_group="DEFAULT"), + ) + + @staticmethod + def get_veth_pair_names(vif): + iface_id = vif.id + return (("qvb%s" % iface_id)[:OvsPlugin.NIC_NAME_LEN], + ("qvo%s" % iface_id)[:OvsPlugin.NIC_NAME_LEN]) def describe(self): return objects.host_info.HostPluginInfo( - plugin_name="ovs", + plugin_name="ovs_hybrid", vif_info=[ + objects.host_info.HostVIFInfo( + vif_object_name=objects.vif.VIFBridge.__name__, + min_version="1.0", + max_version="1.0"), objects.host_info.HostVIFInfo( vif_object_name=objects.vif.VIFOpenVSwitch.__name__, min_version="1.0", max_version="1.0") ]) + def _plug_bridge(self, vif, instance_info): + """Plug using hybrid strategy + + Create a per-VIF linux bridge, then link that bridge to the OVS + integration bridge via a veth device, setting up the other end + of the veth device just like a normal OVS port. Then boot the + VIF on the linux bridge using standard libvirt mechanisms. + """ + + v1_name, v2_name = self.get_veth_pair_names(vif) + + linux_net.ensure_bridge(vif.bridge_name) + + if not linux_net.device_exists(v2_name): + linux_net.create_veth_pair(v1_name, v2_name, + self.config.network_device_mtu) + linux_net.add_bridge_port(vif.bridge_name, v1_name) + linux_net.create_ovs_vif_port( + vif.network.bridge, + v2_name, + vif.port_profile.interface_id, + vif.address, instance_info.uuid, + self.config.network_device_mtu, + timeout=self.config.ovs_vsctl_timeout) + def plug(self, vif, instance_info): - # Nothing required to plug an OVS port... - pass + if not hasattr(vif, "port_profile"): + raise exception.MissingPortProfile() + if not isinstance(vif.port_profile, + objects.vif.VIFPortProfileOpenVSwitch): + raise exception.WrongPortProfile( + profile=vif.port_profile.__class__.__name__) + + if isinstance(vif, objects.vif.VIFBridge): + self._plug_bridge(vif, instance_info) + + def _unplug_bridge(self, vif, instance_info): + """UnPlug using hybrid strategy + + Unhook port from OVS, unhook port from bridge, delete + bridge, and delete both veth devices. + """ + + v1_name, v2_name = self.get_veth_pair_names(vif) + + linux_net.delete_bridge(vif.bridge_name, v1_name) + + linux_net.delete_ovs_vif_port(vif.network.bridge, v2_name, + timeout=self.config.ovs_vsctl_timeout) def unplug(self, vif, instance_info): - # Nothing required to unplug an OVS port... - pass + if not hasattr(vif, "port_profile"): + raise exception.MissingPortProfile() + if not isinstance(vif.port_profile, + objects.vif.VIFPortProfileOpenVSwitch): + raise exception.WrongPortProfile( + profile=vif.port_profile.__class__.__name__) + + if isinstance(vif, objects.vif.VIFBridge): + self._unplug_bridge(vif, instance_info) diff --git a/vif_plug_ovs/ovs_hybrid.py b/vif_plug_ovs/ovs_hybrid.py deleted file mode 100644 index a62ab6d8..00000000 --- a/vif_plug_ovs/ovs_hybrid.py +++ /dev/null @@ -1,116 +0,0 @@ -# Derived from nova/virt/libvirt/vif.py -# -# Copyright (C) 2011 Midokura KK -# Copyright (C) 2011 Nicira, Inc -# Copyright 2011 OpenStack Foundation -# 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. - -from os_vif import objects -from os_vif import plugin -from oslo_config import cfg - -from vif_plug_ovs import exception -from vif_plug_ovs import linux_net - - -class OvsHybridPlugin(plugin.PluginBase): - """ - An OVS VIF type that uses a pair of devices in order to allow - security group rules to be applied to traffic coming in or out of - a virtual machine. - """ - - NIC_NAME_LEN = 14 - - CONFIG_OPTS = ( - cfg.IntOpt('network_device_mtu', - default=1500, - help='MTU setting for network interface.', - deprecated_group="DEFAULT"), - cfg.IntOpt('ovs_vsctl_timeout', - default=120, - help='Amount of time, in seconds, that ovs_vsctl should ' - 'wait for a response from the database. 0 is to wait ' - 'forever.', - deprecated_group="DEFAULT"), - ) - - @staticmethod - def get_veth_pair_names(vif): - iface_id = vif.id - return (("qvb%s" % iface_id)[:OvsHybridPlugin.NIC_NAME_LEN], - ("qvo%s" % iface_id)[:OvsHybridPlugin.NIC_NAME_LEN]) - - def describe(self): - return objects.host_info.HostPluginInfo( - plugin_name="ovs_hybrid", - vif_info=[ - objects.host_info.HostVIFInfo( - vif_object_name=objects.vif.VIFBridge.__name__, - min_version="1.0", - max_version="1.0") - ]) - - def plug(self, vif, instance_info): - """Plug using hybrid strategy - - Create a per-VIF linux bridge, then link that bridge to the OVS - integration bridge via a veth device, setting up the other end - of the veth device just like a normal OVS port. Then boot the - VIF on the linux bridge using standard libvirt mechanisms. - """ - - if not hasattr(vif, "port_profile"): - raise exception.MissingPortProfile() - if not isinstance(vif.port_profile, - objects.vif.VIFPortProfileOpenVSwitch): - raise exception.WrongPortProfile( - profile=vif.port_profile.__class__.__name__) - - v1_name, v2_name = self.get_veth_pair_names(vif) - - linux_net.ensure_bridge(vif.bridge_name) - - if not linux_net.device_exists(v2_name): - linux_net.create_veth_pair(v1_name, v2_name, - self.config.network_device_mtu) - linux_net.add_bridge_port(vif.bridge_name, v1_name) - linux_net.create_ovs_vif_port( - vif.network.bridge, - v2_name, - vif.port_profile.interface_id, - vif.address, instance_info.uuid, - self.config.network_device_mtu, - timeout=self.config.ovs_vsctl_timeout) - - def unplug(self, vif, instance_info): - """UnPlug using hybrid strategy - - Unhook port from OVS, unhook port from bridge, delete - bridge, and delete both veth devices. - """ - if not hasattr(vif, "port_profile"): - raise exception.MissingPortProfile() - if not isinstance(vif.port_profile, - objects.vif.VIFPortProfileOpenVSwitch): - raise exception.WrongPortProfile( - profile=vif.port_profile.__class__.__name__) - - v1_name, v2_name = self.get_veth_pair_names(vif) - - linux_net.delete_bridge(vif.bridge_name, v1_name) - - linux_net.delete_ovs_vif_port(vif.network.bridge, v2_name, - timeout=self.config.ovs_vsctl_timeout) diff --git a/vif_plug_ovs/tests/test_plugin.py b/vif_plug_ovs/tests/test_plugin.py index b22195c5..aadb668a 100644 --- a/vif_plug_ovs/tests/test_plugin.py +++ b/vif_plug_ovs/tests/test_plugin.py @@ -18,7 +18,7 @@ import testtools from os_vif import objects from vif_plug_ovs import linux_net -from vif_plug_ovs import ovs_hybrid +from vif_plug_ovs import ovs if six.PY2: @@ -71,7 +71,7 @@ class PluginTest(testtools.TestCase): name='demo', uuid='f0000000-0000-0000-0000-000000000001') - def test_plug_ovs_hybrid(self): + def test_plug_ovs_bridge(self): calls = { 'device_exists': [mock.call('qvob679325f-ca')], 'create_veth_pair': [mock.call('qvbb679325f-ca', @@ -98,7 +98,7 @@ class PluginTest(testtools.TestCase): mock.patch.object(linux_net, 'create_ovs_vif_port') ) as (ensure_bridge, device_exists, create_veth_pair, add_bridge_port, create_ovs_vif_port): - plugin = ovs_hybrid.OvsHybridPlugin.load("ovs_hybrid") + plugin = ovs.OvsPlugin.load("ovs") plugin.plug(self.vif_ovs, self.instance) ensure_bridge.assert_has_calls(calls['ensure_bridge']) device_exists.assert_has_calls(calls['device_exists']) @@ -106,7 +106,7 @@ class PluginTest(testtools.TestCase): add_bridge_port.assert_has_calls(calls['add_bridge_port']) create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port']) - def test_unplug_ovs_hybrid(self): + def test_unplug_ovs_bridge(self): calls = { 'delete_bridge': [mock.call('qbrvif-xxx-yyy', 'qvbb679325f-ca')], 'delete_ovs_vif_port': [mock.call('br0', 'qvob679325f-ca', @@ -116,7 +116,7 @@ class PluginTest(testtools.TestCase): mock.patch.object(linux_net, 'delete_bridge'), mock.patch.object(linux_net, 'delete_ovs_vif_port') ) as (delete_bridge, delete_ovs_vif_port): - plugin = ovs_hybrid.OvsHybridPlugin.load("ovs_hybrid") + plugin = ovs.OvsPlugin.load("ovs") plugin.unplug(self.vif_ovs, self.instance) delete_bridge.assert_has_calls(calls['delete_bridge']) delete_ovs_vif_port.assert_has_calls(calls['delete_ovs_vif_port'])