KVM/QEMU2.3.0 虚拟机动态迁移分析(一)

1 迁移源端QEMU

migrate命令 –> hmp_migrate –> qmp_migrate –> qemu_savevm_state_blocked判断当前虚拟机状态适不适合迁移 –> migrate_init迁移初始化 –> 根据uri来选择迁移函数,如表1所示。

Uri 跳转函数
Tcp: tcp_start_outgoing_migration
Rdma: rdma_start_outgoing_migration
exec: exec_start_outgoing_migration
unix: unix_start_outgoing_migration
fd: fd_start_outgoing_migration

以TCP迁移为例说明:tcp_start_outgoing_migration –> inet_nonblocking_connect(创建一个非阻塞的socket,并用其连接一个地址,并将tcp_wait_for_connect注册为连接成功后的处理函数)。

tcp_wait_for_connect –> migrate_fd_connect –> qemu_thread_create(创建线程,使用函数migration_thread作为执行体)。

migration_thread –> qemu_savevm_state_begin –> qemu_savevm_state_pending –> 多次qemu_savevm_state_iterate –> vm_stop_force_state –> qemu_savevm_state_complete –> migrate_set_state –> 脏页重传机制是否到达停止条件 *–> 迁移后期处理。

qemu_savevm_state_begin –> qemu_put_be32(f, QEMU_VM_FILE_MAGIC) –> qemu_put_be32(f, QEMU_VM_FILE_VERSION) –> qemu_put_byte(f, QEMU_VM_SECTION_START) –> qemu_put_be32(f, se->section_id) –> qemu_put_byte(f, len) –> qemu_put_buffer(f, (uint8_t )se->idstr, len) –> qemu_put_be32(f, se->instance_id) –> qemu_put_be32(f, se->version_id) –> 调用设备注册的函数se->ops->save_live_setup(f, se->opaque),然后循环。 –> qemu_fflush(f)。

qemu_savevm_state_pending –> 遍历每个设备,依次调用每个设备的函数se->ops->save_live_pending,然后循环。

qemu_savevm_state_iterate –> qemu_put_byte(f, QEMU_VM_SECTION_PART) –> qemu_put_be32(f, se->section_id) –> 调用每个设备的函数se->ops->save_live_iterate,然后循环。

qemu_savevm_state_complete –> qemu_put_byte(f, QEMU_VM_SECTION_END) –> qemu_put_be32(f, se->section_id) –> 调用每个设备的函数se->ops->save_live_complete(f, se->opaque),然后循环 –> qemu_put_byte(f, QEMU_VM_SECTION_FULL) –> qemu_put_be32(f, se->section_id) –> qemu_put_byte(f, len) –> qemu_put_buffer(f, (uint8_t )se->idstr, len) –> qemu_put_be32(f, se->instance_id) –> qemu_put_be32(f, se->version_id) –> 对于每个设备,调用函数vmstate_save(f, se, vmdesc),然后循环。

vmstate_save(f, se, vmdesc) –> 如果se->vmsd句柄存在的话,调用vmstate_save_state(f, se->vmsd, se->opaque, vmdesc),否则调用vmstate_save_old_style(f, se, vmdesc)。

vmstate_save_old_style(f, se, vmdesc) –> 调用回调函数se->ops->save_state(f, se->opaque)。

vmstate_save_state(f, se->vmsd, se->opaque, vmdesc) –> 调用回调函数vmsd->pre_save(opaque) *–> 其他信息导入或者处理。

2 迁移目的端QEMU

目的端:migrate_incoming命令 –> hmp_migrate_incoming(获得uri) –> qmp_migrate_incoming –> qemu_start_incoming_migration –> 表2.

Uri 跳转函数
Defer deferred_incoming_migration
Tcp: tcp_start_incoming_migration
Rdma: rdma_start_incoming_migration
exec: exec_start_incoming_migration
unix: unix_start_incoming_migration
fd: fd_start_incoming_migration

以TCP迁移为例说明:tcp_start_incoming_migration –> inet_listen(在输入的端口上开启本地监听服务) *–> qemu_set_fd_handler2(设置本地监听服务的相应函数为tcp_accept_incoming_migration)。

tcp_accept_incoming_migration –> qemu_accept(接受一个外部的连接)
*–> 一旦接收成功,利用函数qemu_set_fd_handler2和closesocket关闭本地的监听服务,不再接收外部连接。
*–> qemu_fopen_socket,利用刚刚建立的连接句柄来创建一个QEMUFile结构体,用于后续的数据传输。
–>process_incoming_migration –> qemu_coroutine_create创建一个协程,注册协程的入口函数为process_incoming_migration_co –> qemu_get_fd和qemu_set_nonblock设置文件描述符为非阻塞IO *–> qemu_coroutine_enter执行该协程。

process_incoming_migration_co –> qemu_loadvm_state与源端qemu进行通信,传输数据 –> qemu_fclose关闭QEMUFile结构体 –> 判断迁移是否成功 –> bdrv_invalidate_cache_all强迫所有的设备刷新各自的缓存 –> vm_start恢复虚拟机的运行。

qemu_loadvm_state –> qemu_savevm_state_blocked判断当前虚拟机状态适不适合迁移
*–> qemu_get_be32取出一个32位的整数,如果其等于宏QEMU_VM_FILE_MAGIC,则为迁移字节流。
*–> qemu_get_be32取出一个32位的整数,该字段代表QEMUFile格式的版本号,判断版本号是否匹配。
*–> qemu_get_byte得到接下来section的类型,根据类型的不同,处理流程表3所示。

Uri 跳转函数
QEMU_VM_SECTION_START,QEMU_VM_SECTION_FULL (section_id)qemu_get_be32 -> (len,保证不超过256)qemu_get_byte -> (idstr)qemu_get_buffer(…, len) -> (instance_id)qemu_get_be32 -> (version_id)qemu_get_be32 -> find_se根据idstr和instance_id来找到SaveStateEntry结构体实例 -> 根据version_id来判断版本号是否一致 -> vmstate_load加载QEMUFile中该小节中的内容。
QEMU_VM_SECTION_PART,QEMU_VM_SECTION_END (section_id)qemu_get_be32 -> 寻找section_id是迁移中的哪个设备 -> vmstate_load加载QEMUFile中该小节中的内容。
Default 未知类型报错。

vmstate_load –> 如果没有设置vmsd指针,则调用se->ops->load_state函数进行处理;否则,调用函数vmstate_load_state进行处理。
se->ops->load_state:是每一个设备自己注册的函数,此处不具体展开来讲。
vmstate_load_state –> 以此调用vmsd->load_state_old、vmsd->pre_load、vmsd->post_load,这三个函数是每个迁移设备自己注册的函数,此处不具体展开来讲。

你可能感兴趣的:(linux系统,虚拟化)