Migration over fd:
source:
1) Make new descriptor (pipe, socket) and send the descriptor
to qemu-monitor over unix socket.
2) Register the descriptor in qemu-monitor with function
getfd DSC_NAME
and close the descriptor in main process.
3) Migrate over descriptor.
migrate fd:DSC_NAME
destination:
1) Start child process with open second side of source descriptor.
2) Start machine with param -incoming fd:descriptor
3) Wait for finishing migration.
Signed-off-by: Jiří Župka <[email protected]>
---
client/virt/kvm_vm.py | 47 +++++++++++++++++++++++++++++++++++---
client/virt/virt_env_process.py | 3 +-
2 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/client/virt/kvm_vm.py b/client/virt/kvm_vm.py
index 10aafbb..9857998 100644
--- a/client/virt/kvm_vm.py
+++ b/client/virt/kvm_vm.py
@@ -15,7 +15,7 @@ class VM(virt_vm.BaseVM):
This class handles all basic VM operations.
"""
- MIGRATION_PROTOS = ['tcp', 'unix', 'exec']
+ MIGRATION_PROTOS = ['tcp', 'unix', 'exec', 'fd']
#
# By default we inherit all timeouts from the base VM class
@@ -971,7 +971,8 @@ class VM(virt_vm.BaseVM):
@error.context_aware
def create(self, name=None, params=None, root_dir=None,
timeout=CREATE_TIMEOUT, migration_mode=None,
- migration_exec_cmd=None, mac_source=None):
+ migration_exec_cmd=None, migration_fd=None,
+ mac_source=None):
"""
Start the VM by running a qemu command.
All parameters are optional. If name, params or root_dir are not
@@ -985,6 +986,7 @@ class VM(virt_vm.BaseVM):
@param migration_exec_cmd: Command to embed in '-incoming "exec: ..."'
(e.g. 'gzip -c -d filename') if migration_mode is 'exec'
default to listening on a random TCP port
+ @param migration_fd: Open descriptor from machine should migrate.
@param mac_source: A VM object from which to copy MAC addresses. If not
specified, new addresses will be generated.
@@ -1183,6 +1185,8 @@ class VM(virt_vm.BaseVM):
else:
qemu_command += (' -incoming "exec:%s"' %
migration_exec_cmd)
+ elif migration_mode == "fd":
+ qemu_command += ' -incoming "fd:%d"' % (migration_fd)
p9_fs_driver = params.get("9p_fs_driver")
if p9_fs_driver == "proxy":
@@ -1728,10 +1732,25 @@ class VM(virt_vm.BaseVM):
@error.context_aware
+ def send_fd(self, fd, fd_name="migfd"):
+ """
+ Send file descriptor over unix socket to VM.
+
+ @param fd: File descriptor.
+ @param fd_name: File descriptor identificator in VM.
+ """
+ error.context("Send fd %d like %s to VM %s" % (fd, fd_name, self.name))
+
+ logging.debug("Send file descriptor %s to source VM." % fd_name)
+ self.monitor.cmd("getfd %s" % (fd_name), fd=fd)
+ error.context()
+
+
+ @error.context_aware
def migrate(self, timeout=MIGRATE_TIMEOUT, protocol="tcp",
cancel_delay=None, offline=False, stable_check=False,
clean=True, save_path="/tmp", dest_host="localhost",
- remote_port=None):
+ remote_port=None, fd_src=None, fd_dst=None):
"""
Migrate the VM.
@@ -1752,6 +1771,10 @@ class VM(virt_vm.BaseVM):
@save_path: The path for state files.
@param dest_host: Destination host (defaults to 'localhost').
@param remote_port: Port to use for remote migration.
+ @param fd_s: File descriptor for migration to which source
+ VM write data. Descriptor is closed during the migration.
+ @param fd_d: File descriptor for migration from which destination
+ VM read data.
"""
if protocol not in self.MIGRATION_PROTOS:
raise virt_vm.VMMigrateProtoUnsupportedError
@@ -1795,6 +1818,16 @@ class VM(virt_vm.BaseVM):
"for migration to finish")
local = dest_host == "localhost"
+ mig_fd_name = None
+
+ if protocol == "fd":
+ #Check if descriptors aren't None for local migration.
+ if local and (fd_dst is None or fd_src is None):
+ (fd_dst, fd_src) = os.pipe()
+
+ mig_fd_name = "migfd_%d_%d" % (fd_src, time.time())
+ self.send_fd(fd_src, mig_fd_name)
+ os.close(fd_src)
clone = self.clone()
if local:
@@ -1803,7 +1836,10 @@ class VM(virt_vm.BaseVM):
# Pause the dest vm after creation
extra_params = clone.params.get("extra_params", "") + " -S"
clone.params["extra_params"] = extra_params
- clone.create(migration_mode=protocol, mac_source=self)
+ clone.create(migration_mode=protocol, mac_source=self,
+ migration_fd=fd_dst)
+ if fd_dst:
+ os.close(fd_dst)
error.context()
try:
@@ -1816,6 +1852,8 @@ class VM(virt_vm.BaseVM):
uri = "unix:%s" % clone.migration_file
elif protocol == "exec":
uri = '"exec:nc localhost %s"' % clone.migration_port
+ elif protocol == "fd":
+ uri = "fd:%s" % mig_fd_name
if offline:
self.monitor.cmd("stop")
@@ -1833,6 +1871,7 @@ class VM(virt_vm.BaseVM):
return
wait_for_migration()
+
self.verify_kernel_crash()
self.verify_alive()
diff --git a/client/virt/virt_env_process.py b/client/virt/virt_env_process.py
index 1c726e5..23a584a 100644
--- a/client/virt/virt_env_process.py
+++ b/client/virt/virt_env_process.py
@@ -99,7 +99,8 @@ def preprocess_vm(test, params, env, name):
else:
# Start the VM (or restart it if it's already up)
vm.create(name, params, test.bindir,
- migration_mode=params.get("migration_mode"))
+ migration_mode=params.get("migration_mode"),
+ migration_fd=params.get("migration_fd"))
else:
# Don't start the VM, just update its params
vm.params = params
--
1.7.7.6
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html