785e8553df
We need to make sure that the patch output was clean. As test_*.py are not needed and xenhost will be patched through xs suppack, those content can be removed from patch files. Change-Id: Ie78b4fd31b73fa6fff6064f855b31a1c7c0fddad
295 lines
12 KiB
Diff
295 lines
12 KiB
Diff
diff --git a/nova/exception.py b/nova/exception.py
|
|
index 40b82bf..f9cd12f 100644
|
|
--- a/nova/exception.py
|
|
+++ b/nova/exception.py
|
|
@@ -187,6 +187,11 @@ class VirtualInterfacePlugException(NovaException):
|
|
msg_fmt = _("Virtual interface plugin failed")
|
|
|
|
|
|
+class VirtualInterfaceUnplugException(NovaException):
|
|
+ msg_fmt = _("Virtual interface unplugin failed: "
|
|
+ "%(reason)s")
|
|
+
|
|
+
|
|
class GlanceConnectionFailed(NovaException):
|
|
msg_fmt = _("Connection to glance host %(server)s failed: "
|
|
"%(reason)s")
|
|
diff --git a/nova/virt/xenapi/client/objects.py b/nova/virt/xenapi/client/objects.py
|
|
index 5cc91eb..7f7215c 100644
|
|
--- a/nova/virt/xenapi/client/objects.py
|
|
+++ b/nova/virt/xenapi/client/objects.py
|
|
@@ -100,6 +100,12 @@ class VDI(XenAPISessionObject):
|
|
super(VDI, self).__init__(session, "VDI")
|
|
|
|
|
|
+class VIF(XenAPISessionObject):
|
|
+ """Virtual Network Interface."""
|
|
+ def __init__(self, session):
|
|
+ super(VIF, self).__init__(session, "VIF")
|
|
+
|
|
+
|
|
class SR(XenAPISessionObject):
|
|
"""Storage Repository."""
|
|
def __init__(self, session):
|
|
diff --git a/nova/virt/xenapi/client/session.py b/nova/virt/xenapi/client/session.py
|
|
index 8f277ff..70e9bec 100644
|
|
--- a/nova/virt/xenapi/client/session.py
|
|
+++ b/nova/virt/xenapi/client/session.py
|
|
@@ -65,6 +65,7 @@ def apply_session_helpers(session):
|
|
session.VM = cli_objects.VM(session)
|
|
session.SR = cli_objects.SR(session)
|
|
session.VDI = cli_objects.VDI(session)
|
|
+ session.VIF = cli_objects.VIF(session)
|
|
session.VBD = cli_objects.VBD(session)
|
|
session.PBD = cli_objects.PBD(session)
|
|
session.PIF = cli_objects.PIF(session)
|
|
diff --git a/nova/virt/xenapi/vif.py b/nova/virt/xenapi/vif.py
|
|
index 5c7a350..b9660be 100644
|
|
--- a/nova/virt/xenapi/vif.py
|
|
+++ b/nova/virt/xenapi/vif.py
|
|
@@ -23,6 +23,7 @@ from oslo_log import log as logging
|
|
from nova import exception
|
|
from nova.i18n import _
|
|
from nova.i18n import _LW
|
|
+from nova.network import model as network_model
|
|
from nova.virt.xenapi import network_utils
|
|
from nova.virt.xenapi import vm_utils
|
|
|
|
@@ -185,11 +186,18 @@ class XenAPIBridgeDriver(XenVIFDriver):
|
|
def unplug(self, instance, vif, vm_ref):
|
|
super(XenAPIBridgeDriver, self).unplug(instance, vif, vm_ref)
|
|
|
|
+ def post_start_actions(self, instance, vif_ref):
|
|
+ """no further actions needed for this driver type"""
|
|
+ pass
|
|
+
|
|
|
|
class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|
"""VIF driver for Open vSwitch with XenAPI."""
|
|
|
|
def plug(self, instance, vif, vm_ref=None, device=None):
|
|
+ """create an interim network for this vif; and build
|
|
+ the vif_rec which will be used by xapi to create VM vif
|
|
+ """
|
|
if not vm_ref:
|
|
vm_ref = vm_utils.lookup(self._session, instance['name'])
|
|
|
|
@@ -203,10 +211,10 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|
if not device:
|
|
device = 0
|
|
|
|
- # with OVS model, always plug into an OVS integration bridge
|
|
- # that is already created
|
|
- network_ref = network_utils.find_network_with_bridge(
|
|
- self._session, CONF.xenserver.ovs_integration_bridge)
|
|
+ # Create an interim network for each VIF, so dom0 has a single
|
|
+ # bridge for each device (the emulated and PV ethernet devices
|
|
+ # will both be on this bridge.
|
|
+ network_ref = self.create_vif_interim_network(vif)
|
|
vif_rec = {}
|
|
vif_rec['device'] = str(device)
|
|
vif_rec['network'] = network_ref
|
|
@@ -221,4 +229,157 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|
return self._create_vif(vif, vif_rec, vm_ref)
|
|
|
|
def unplug(self, instance, vif, vm_ref):
|
|
+ """unplug vif:
|
|
+ 1. unplug and destroy vif.
|
|
+ 2. delete the patch port pair between the integration bridge and
|
|
+ the interim network.
|
|
+ 3. destroy the interim network
|
|
+ 4. delete the OVS bridge service for the interim network
|
|
+ """
|
|
super(XenAPIOpenVswitchDriver, self).unplug(instance, vif, vm_ref)
|
|
+
|
|
+ net_name = self.get_vif_interim_net_name(vif)
|
|
+ network = network_utils.find_network_with_name_label(
|
|
+ self._session, net_name)
|
|
+ if network is None:
|
|
+ return
|
|
+ vifs = self._session.network.get_VIFs(network)
|
|
+ if vifs:
|
|
+ # only remove the interim network when it's empty.
|
|
+ # for resize/migrate on local host, vifs on both of the
|
|
+ # source and target VM will be connected to the same
|
|
+ # interim network.
|
|
+ return
|
|
+ LOG.debug('destroying patch port pair for vif: vif_id=%(vif_id)s',
|
|
+ {'vif_id': vif['id']})
|
|
+ bridge_name = self._session.network.get_bridge(network)
|
|
+ patch_port1, patch_port2 = self._get_patch_port_pair_names(vif['id'])
|
|
+ try:
|
|
+ # delete the patch port pair
|
|
+ self._ovs_del_port(bridge_name, patch_port1)
|
|
+ self._ovs_del_port(CONF.xenserver.ovs_integration_bridge,
|
|
+ patch_port2)
|
|
+ except Exception as e:
|
|
+ LOG.warn(_LW("Failed to delete patch port pair for vif %(if)s,"
|
|
+ " exception:%(exception)s"),
|
|
+ {'if': vif, 'exception': e}, instance=instance)
|
|
+ raise exception.VirtualInterfaceUnplugException(
|
|
+ reason=_("Failed to delete patch port pair"))
|
|
+
|
|
+ LOG.debug('destroying network: network=%(network)s,'
|
|
+ 'bridge=%(br)s',
|
|
+ {'network': network, 'br': bridge_name})
|
|
+ try:
|
|
+ self._session.network.destroy(network)
|
|
+ # delete bridge if it still exists.
|
|
+ # As there is patch port existing on this bridge when destroying
|
|
+ # the VM vif (which happens when shutdown the VM), the bridge
|
|
+ # won't be destroyed automatically by XAPI. So let's destroy it
|
|
+ # at here.
|
|
+ self._ovs_del_br(bridge_name)
|
|
+ except Exception as e:
|
|
+ LOG.warn(_LW("Failed to delete bridge for vif %(if)s, "
|
|
+ "exception:%(exception)s"),
|
|
+ {'if': vif, 'exception': e}, instance=instance)
|
|
+ raise exception.VirtualInterfaceUnplugException(
|
|
+ reason=_("Failed to delete bridge"))
|
|
+
|
|
+ def post_start_actions(self, instance, vif_ref):
|
|
+ """Do needed actions post vif start:
|
|
+ plug the interim ovs bridge to the integration bridge;
|
|
+ set external_ids to the int-br port which will service
|
|
+ for this vif.
|
|
+ """
|
|
+ vif_rec = self._session.VIF.get_record(vif_ref)
|
|
+ network_ref = vif_rec['network']
|
|
+ bridge_name = self._session.network.get_bridge(network_ref)
|
|
+ network_uuid = self._session.network.get_uuid(network_ref)
|
|
+ iface_id = vif_rec['other_config']['nicira-iface-id']
|
|
+ patch_port1, patch_port2 = self._get_patch_port_pair_names(iface_id)
|
|
+ LOG.debug('plug_ovs_bridge: port1=%(port1)s, port2=%(port2)s,'
|
|
+ 'network_uuid=%(uuid)s, bridge_name=%(bridge_name)s',
|
|
+ {'port1': patch_port1, 'port2': patch_port2,
|
|
+ 'uuid': network_uuid, 'bridge_name': bridge_name})
|
|
+ if bridge_name is None:
|
|
+ raise exception.VirtualInterfacePlugException(
|
|
+ _("Failed to find bridge for vif"))
|
|
+
|
|
+ self._ovs_add_patch_port(bridge_name, patch_port1, patch_port2)
|
|
+ self._ovs_add_patch_port(CONF.xenserver.ovs_integration_bridge,
|
|
+ patch_port2, patch_port1)
|
|
+ self._ovs_map_external_ids(patch_port2, vif_rec)
|
|
+
|
|
+ def get_vif_interim_net_name(self, vif):
|
|
+ return ("net-" + vif['id'])[:network_model.NIC_NAME_LEN]
|
|
+
|
|
+ def create_vif_interim_network(self, vif):
|
|
+ net_name = self.get_vif_interim_net_name(vif)
|
|
+ network_rec = {'name_label': net_name,
|
|
+ 'name_description': "interim network for vif",
|
|
+ 'other_config': {}}
|
|
+ network_ref = network_utils.find_network_with_name_label(
|
|
+ self._session, net_name)
|
|
+ if network_ref:
|
|
+ # already exist, just return
|
|
+ # in some scenarios: e..g resize/migrate, it won't create new
|
|
+ # interim network.
|
|
+ return network_ref
|
|
+ try:
|
|
+ network_ref = self._session.network.create(network_rec)
|
|
+ except Exception as e:
|
|
+ LOG.warn(_LW("Failed to create interim network for vif %(if)s, "
|
|
+ "exception:%(exception)s"),
|
|
+ {'if': vif, 'exception': e})
|
|
+ raise exception.VirtualInterfacePlugException(
|
|
+ _("Failed to create the interim network for vif"))
|
|
+ return network_ref
|
|
+
|
|
+ def _get_patch_port_pair_names(self, iface_id):
|
|
+ return (("pp1-%s" % iface_id)[:network_model.NIC_NAME_LEN],
|
|
+ ("pp2-%s" % iface_id)[:network_model.NIC_NAME_LEN])
|
|
+
|
|
+ def _ovs_add_patch_port(self, bridge_name, port_name, peer_port_name):
|
|
+ cmd = 'ovs_add_patch_port'
|
|
+ args = {'bridge_name': bridge_name,
|
|
+ 'port_name': port_name,
|
|
+ 'peer_port_name': peer_port_name
|
|
+ }
|
|
+ self._exec_dom0_cmd(cmd, args)
|
|
+
|
|
+ def _ovs_del_port(self, bridge_name, port_name):
|
|
+ cmd = 'ovs_del_port'
|
|
+ args = {'bridge_name': bridge_name,
|
|
+ 'port_name': port_name
|
|
+ }
|
|
+ self._exec_dom0_cmd(cmd, args)
|
|
+
|
|
+ def _ovs_del_br(self, bridge_name):
|
|
+ cmd = 'ovs_del_br'
|
|
+ args = {'bridge_name': bridge_name}
|
|
+ self._exec_dom0_cmd(cmd, args)
|
|
+
|
|
+ def _ovs_set_if_external_id(self, interface, extneral_id, value):
|
|
+ cmd = 'ovs_set_if_external_id'
|
|
+ args = {'interface': interface,
|
|
+ 'extneral_id': extneral_id,
|
|
+ 'value': value}
|
|
+ self._exec_dom0_cmd(cmd, args)
|
|
+
|
|
+ def _ovs_map_external_ids(self, interface, vif_rec):
|
|
+ '''set external ids on the integration bridge vif
|
|
+ '''
|
|
+ mac = vif_rec['MAC']
|
|
+ iface_id = vif_rec['other_config']['nicira-iface-id']
|
|
+ vif_uuid = vif_rec['uuid']
|
|
+ status = 'active'
|
|
+
|
|
+ self._ovs_set_if_external_id(interface, 'attached-mac', mac)
|
|
+ self._ovs_set_if_external_id(interface, 'iface-id', iface_id)
|
|
+ self._ovs_set_if_external_id(interface, 'xs-vif-uuid', vif_uuid)
|
|
+ self._ovs_set_if_external_id(interface, 'iface-status', status)
|
|
+
|
|
+ def _exec_dom0_cmd(self, cmd, cmd_args):
|
|
+ args = {'cmd': cmd,
|
|
+ 'args': cmd_args
|
|
+ }
|
|
+ self._session.call_plugin_serialized('xenhost', 'network_config', args)
|
|
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
|
|
index ab9368c..51d9627 100644
|
|
--- a/nova/virt/xenapi/vmops.py
|
|
+++ b/nova/virt/xenapi/vmops.py
|
|
@@ -348,6 +348,18 @@ class VMOps(object):
|
|
if bad_volumes_callback and bad_devices:
|
|
bad_volumes_callback(bad_devices)
|
|
|
|
+ # Do some operations which have to be done after start:
|
|
+ # e.g. The vif's interim bridge won't be created until VM starts.
|
|
+ # So the operations on the interim bridge have be done after
|
|
+ # start.
|
|
+ self._post_start_actions(instance)
|
|
+
|
|
+ def _post_start_actions(self, instance):
|
|
+ vm_ref = vm_utils.lookup(self._session, instance['name'])
|
|
+ vif_refs = self._session.call_xenapi("VM.get_VIFs", vm_ref)
|
|
+ for vif_ref in vif_refs:
|
|
+ self.vif_driver.post_start_actions(instance, vif_ref)
|
|
+
|
|
def _get_vdis_for_instance(self, context, instance, name_label,
|
|
image_meta, image_type, block_device_info):
|
|
"""Create or connect to all virtual disks for this instance."""
|
|
@@ -1935,13 +1947,20 @@ class VMOps(object):
|
|
"""Creates vifs for an instance."""
|
|
|
|
LOG.debug("Creating vifs", instance=instance)
|
|
+ vif_refs = []
|
|
|
|
# this function raises if vm_ref is not a vm_opaque_ref
|
|
self._session.call_xenapi("VM.get_domid", vm_ref)
|
|
|
|
for device, vif in enumerate(network_info):
|
|
LOG.debug('Create VIF %s', vif, instance=instance)
|
|
- self.vif_driver.plug(instance, vif, vm_ref=vm_ref, device=device)
|
|
+ vif_ref = self.vif_driver.plug(instance, vif,
|
|
+ vm_ref=vm_ref, device=device)
|
|
+ vif_refs.append(vif_ref)
|
|
+
|
|
+ LOG.debug('Created the vif_refs: %(vifs)s for VM name: %(name)s',
|
|
+ {'vifs': vif_refs, 'name': instance['name']},
|
|
+ instance=instance)
|
|
|
|
def plug_vifs(self, instance, network_info):
|
|
"""Set up VIF networking on the host."""
|