[PATCH 2/3] virt: Adds migration over fd for kvm.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux