diff --git a/usr.sbin/bhyve/migration.c b/usr.sbin/bhyve/migration.c --- a/usr.sbin/bhyve/migration.c +++ b/usr.sbin/bhyve/migration.c @@ -66,6 +66,8 @@ #include "pci_emul.h" #include "snapshot.h" +#define MB (1024UL * 1024) +#define GB (1024UL * MB) #ifdef BHYVE_DEBUG #define DPRINTF(FMT, ...) \ ({ \ @@ -336,6 +338,160 @@ return (0); } + +static int +migrate_check_memsize(size_t local_lowmem_size, size_t local_highmem_size, + size_t remote_lowmem_size, size_t remote_highmem_size) +{ + int ret; + + ret = MIGRATION_SPECS_OK; + + if (local_lowmem_size != remote_lowmem_size){ + ret = MIGRATION_SPECS_NOT_OK; + DPRINTF("Local and remote lowmem size mismatch"); + } + + if (local_highmem_size != remote_highmem_size){ + ret = MIGRATION_SPECS_NOT_OK; + DPRINTF("Local and remote highmem size mismatch"); + } + + return (ret); +} + +static int +migrate_recv_memory(struct vmctx *ctx, int socket) +{ + size_t local_lowmem_size, local_highmem_size; + size_t remote_lowmem_size, remote_highmem_size; + char *baseaddr; + int memsize_ok; + int rc; + + local_lowmem_size = local_highmem_size = 0; + remote_lowmem_size = remote_highmem_size = 0; + rc = 0; + + rc = vm_get_guestmem_from_ctx(ctx, + &baseaddr, &local_lowmem_size, + &local_highmem_size); + if (rc != 0) { + DPRINTF("Could not get guest lowmem size and highmem size"); + return (rc); + } + + rc = migration_transfer_data(socket, &remote_lowmem_size, sizeof(remote_lowmem_size), MIGRATION_RECV_REQ); + if (rc < 0) { + DPRINTF("Could not recv lowmem size"); + return (rc); + } + + rc = migration_transfer_data(socket, &remote_highmem_size, sizeof(remote_highmem_size), MIGRATION_RECV_REQ); + if (rc < 0) { + DPRINTF("Could not recv highmem size"); + return (rc); + } + + memsize_ok = migrate_check_memsize(local_lowmem_size, local_highmem_size, + remote_lowmem_size, remote_highmem_size); + + rc = migration_transfer_data(socket, + &memsize_ok, sizeof(memsize_ok), MIGRATION_SEND_REQ); + if (rc < 0) { + DPRINTF("Could not send migration_ok to remote"); + return (rc); + } + + if (memsize_ok != MIGRATION_SPECS_OK) { + DPRINTF("Memory size mismatch with remote host"); + return (-1); + } + + rc = migration_transfer_data(socket, baseaddr, local_lowmem_size, MIGRATION_RECV_REQ); + if (rc < 0) { + DPRINTF("Could not recv chunk lowmem."); + return (-1); + } + + if (local_highmem_size > 0){ + rc = migration_transfer_data(socket, baseaddr + 4 * GB, local_highmem_size, MIGRATION_RECV_REQ); + if (rc < 0) { + DPRINTF("Could not recv highmem"); + return (-1); + } + } + + return (0); +} + +static int +migrate_send_memory(struct vmctx *ctx, int socket) +{ + size_t lowmem_size, highmem_size; + char *mmap_vm_lowmem, *mmap_vm_highmem; + char *baseaddr; + int memsize_ok; + int rc; + + rc = 0; + mmap_vm_lowmem = MAP_FAILED; + mmap_vm_highmem = MAP_FAILED; + + rc = vm_get_guestmem_from_ctx(ctx, &baseaddr, + &lowmem_size, &highmem_size); + if (rc != 0) { + DPRINTF("Could not get guest lowmem size and highmem size"); + return (rc); + } + + /* Send the size of the lowmem segment */ + rc = migration_transfer_data(socket, &lowmem_size, sizeof(lowmem_size), MIGRATION_SEND_REQ); + if (rc < 0) { + DPRINTF("Could not send lowmem size"); + return (rc); + } + + /* Send the size of the highmem segment */ + rc = migration_transfer_data(socket, &highmem_size, sizeof(lowmem_size), MIGRATION_SEND_REQ); + if (rc < 0) { + DPRINTF("Could not send highmem size"); + return (rc); + } + + /* Wait for answer - params ok (if memory size matches) */ + rc = migration_transfer_data(socket, &memsize_ok, sizeof(memsize_ok), MIGRATION_RECV_REQ); + if (rc < 0) { + DPRINTF("Could not receive response from remote"); + return (rc); + } + + if (memsize_ok != MIGRATION_SPECS_OK) { + DPRINTF("Memory size mismatch with remote host"); + return (-1); + } + + mmap_vm_lowmem = baseaddr; + mmap_vm_highmem = baseaddr + 4 * GB; + + /* Send the lowmem segment */ + rc = migration_transfer_data(socket, mmap_vm_lowmem, lowmem_size, MIGRATION_SEND_REQ); + if (rc < 0) { + DPRINTF("Could not send lowmem"); + return (-1); + } + + /* Send the highmem segment */ + if (highmem_size > 0){ + rc = migration_transfer_data(socket, mmap_vm_highmem, highmem_size, MIGRATION_SEND_REQ); + if (rc < 0) { + DPRINTF("Could not send highmem"); + return (-1); + } + } + + return (0); +} static inline int migrate_connections(struct migrate_req req, int *socket_fd, int *connection_socket_fd, @@ -474,6 +630,12 @@ goto unlock_vm_and_exit; } + rc = migrate_send_memory(ctx, s); + if (rc != 0) { + EPRINTF("Could not send memory to destination"); + error = rc; + goto unlock_vm_and_exit; + } rc = migration_transfer_data(s, &migration_completed, sizeof(migration_completed), MIGRATION_RECV_REQ); if ((rc < 0) || (migration_completed != MIGRATION_SPECS_OK)) { @@ -521,6 +683,13 @@ return (rc); } + rc = migrate_recv_memory(ctx, con_socket); + if (rc < 0) { + EPRINTF("Could not recv :lowmem and highmem"); + close(con_socket); + close(s); + return (-1); + } fprintf(stdout, "%s: Migration completed\r\n", __func__); migration_completed = MIGRATION_SPECS_OK;