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 <jzupka@xxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html