Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/migration.c
Show First 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "migration.h" | #include "migration.h" | ||||
#include "pci_emul.h" | #include "pci_emul.h" | ||||
#include "snapshot.h" | #include "snapshot.h" | ||||
#define MB (1024UL * 1024) | |||||
#define GB (1024UL * MB) | |||||
#ifdef BHYVE_DEBUG | #ifdef BHYVE_DEBUG | ||||
#define DPRINTF(FMT, ...) \ | #define DPRINTF(FMT, ...) \ | ||||
({ \ | ({ \ | ||||
fprintf(stderr, "%s: " FMT "\r\n", __func__, ##__VA_ARGS__); \ | fprintf(stderr, "%s: " FMT "\r\n", __func__, ##__VA_ARGS__); \ | ||||
}) | }) | ||||
#else | #else | ||||
#define DPRINTF(FMT, ...) | #define DPRINTF(FMT, ...) | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 262 Lines • ▼ Show 20 Lines | case AF_INET6: | ||||
break; | break; | ||||
default: | default: | ||||
DPRINTF("Unknown address family."); | DPRINTF("Unknown address family."); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (0); | 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 | static inline int | ||||
migrate_connections(struct migrate_req req, int *socket_fd, | migrate_connections(struct migrate_req req, int *socket_fd, | ||||
int *connection_socket_fd, | int *connection_socket_fd, | ||||
enum migration_transfer_req type) | enum migration_transfer_req type) | ||||
{ | { | ||||
unsigned char ipv4_addr[INET_ADDRSTRLEN]; | unsigned char ipv4_addr[INET_ADDRSTRLEN]; | ||||
unsigned char ipv6_addr[INET6_ADDRSTRLEN]; | unsigned char ipv6_addr[INET6_ADDRSTRLEN]; | ||||
int addr_type; | int addr_type; | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | vm_send_migrate_req(struct vmctx *ctx, struct migrate_req req) | ||||
rc = vm_pause_user_devs(ctx); | rc = vm_pause_user_devs(ctx); | ||||
if (rc != 0) { | if (rc != 0) { | ||||
EPRINTF("Could not pause devices"); | EPRINTF("Could not pause devices"); | ||||
error = rc; | error = rc; | ||||
goto unlock_vm_and_exit; | 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, | rc = migration_transfer_data(s, &migration_completed, | ||||
sizeof(migration_completed), MIGRATION_RECV_REQ); | sizeof(migration_completed), MIGRATION_RECV_REQ); | ||||
if ((rc < 0) || (migration_completed != MIGRATION_SPECS_OK)) { | if ((rc < 0) || (migration_completed != MIGRATION_SPECS_OK)) { | ||||
EPRINTF("Could not recv migration completed remote or received error"); | EPRINTF("Could not recv migration completed remote or received error"); | ||||
error = -1; | error = -1; | ||||
goto unlock_vm_and_exit; | goto unlock_vm_and_exit; | ||||
} | } | ||||
Show All 31 Lines | vm_recv_migrate_req(struct vmctx *ctx, struct migrate_req req) | ||||
rc = migration_check_specs(con_socket, MIGRATION_RECV_REQ); | rc = migration_check_specs(con_socket, MIGRATION_RECV_REQ); | ||||
if (rc < 0) { | if (rc < 0) { | ||||
EPRINTF("Error while checking specs"); | EPRINTF("Error while checking specs"); | ||||
close(con_socket); | close(con_socket); | ||||
close(s); | close(s); | ||||
return (rc); | 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__); | fprintf(stdout, "%s: Migration completed\r\n", __func__); | ||||
migration_completed = MIGRATION_SPECS_OK; | migration_completed = MIGRATION_SPECS_OK; | ||||
rc = migration_transfer_data(con_socket, &migration_completed, | rc = migration_transfer_data(con_socket, &migration_completed, | ||||
sizeof(migration_completed), MIGRATION_SEND_REQ); | sizeof(migration_completed), MIGRATION_SEND_REQ); | ||||
if (rc < 0) { | if (rc < 0) { | ||||
EPRINTF("Could not send migration completed remote"); | EPRINTF("Could not send migration completed remote"); | ||||
close(con_socket); | close(con_socket); | ||||
Show All 10 Lines |