Page MenuHomeFreeBSD

D34717.diff
No OneTemporary

D34717.diff

diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -88,6 +88,7 @@
.if ${MK_BHYVE_SNAPSHOT} != "no"
SRCS+= snapshot.c
+SRCS+= migration.c
.endif
CFLAGS.kernemu_dev.c+= -I${SRCTOP}/sys/amd64
diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -80,6 +80,11 @@
.Op Fl o Ar var Ns Cm = Ns Ar value
.Op Fl p Ar vcpu Ns Cm \&: Ns Ar hostcpu
.Op Fl r Ar file
+.Oo Fl R
+.Sm off
+.Ar host Op Cm \&: Ar port
+.Sm on
+.Oc
.Sm off
.Oo Fl s\~
.Ar slot Cm \&, Ar emulation Op Cm \&, Ar conf
@@ -276,6 +281,13 @@
.Fl l
options.
The count of vCPUs and memory configuration are read from the snapshot.
+.It Fl R Ar host Ns Op Cm \&: Ns Ar port
+Receive migration from a source guest.
+Await for a connection from
+.Ar host
+on the specified
+.Ar port
+and resume execution. The default migration port is 24983.
.It Fl S
Wire guest memory.
.It Fl s Cm help
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -98,6 +98,9 @@
#include "kernemu_dev.h"
#include "mem.h"
#include "mevent.h"
+#ifdef BHYVE_SNAPSHOT
+#include "migration.h"
+#endif
#include "mptbl.h"
#include "pci_emul.h"
#include "pci_irq.h"
@@ -231,6 +234,7 @@
" -p: pin 'vcpu' to 'hostcpu'\n"
#ifdef BHYVE_SNAPSHOT
" -r: path to checkpoint file\n"
+ " -R: <host[:port]> the source vm host and port for migration\n"
#endif
" -S: guest memory cannot be swapped\n"
" -s: <slot,driver,configinfo> PCI slot config\n"
@@ -1082,7 +1086,11 @@
exit(4);
}
} else {
+#ifndef BHYVE_SNAPSHOT
if (!romboot) {
+#else
+ if (!romboot && !get_config_bool_default("is_migrated", false)) {
+#endif
/*
* If the virtual machine was just created then a
* bootrom must be configured to boot it.
@@ -1227,9 +1235,11 @@
const char *optstr, *value, *vmname;
#ifdef BHYVE_SNAPSHOT
char *restore_file;
+ char *migration_host;
struct restore_state rstate;
restore_file = NULL;
+ migration_host = NULL;
#endif
init_config();
@@ -1237,7 +1247,7 @@
progname = basename(argv[0]);
#ifdef BHYVE_SNAPSHOT
- optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:";
+ optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:R:";
#else
optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:";
#endif
@@ -1294,6 +1304,10 @@
case 'r':
restore_file = optarg;
break;
+ case 'R':
+ migration_host = optarg;
+ set_config_bool("is_migrated", true);
+ break;
#endif
case 's':
if (strncmp(optarg, "help", strlen(optarg)) == 0) {
@@ -1510,38 +1524,51 @@
spinup_vcpu(&vcpu_info[vcpuid], vcpuid == BSP);
#ifdef BHYVE_SNAPSHOT
- if (restore_file != NULL) {
- fprintf(stdout, "Pausing pci devs...\r\n");
+ if (restore_file != NULL || migration_host != NULL) {
+ fprintf(stdout, "Pausing pci devs...\n");
if (vm_pause_devices() != 0) {
fprintf(stderr, "Failed to pause PCI device state.\n");
exit(1);
}
- fprintf(stdout, "Restoring vm mem...\r\n");
- if (restore_vm_mem(ctx, &rstate) != 0) {
- fprintf(stderr, "Failed to restore VM memory.\n");
- exit(1);
- }
+ if (restore_file != NULL) {
+ fprintf(stdout, "Restoring vm mem...\n");
+ if (restore_vm_mem(ctx, &rstate) != 0) {
+ fprintf(stderr,
+ "Failed to restore VM memory.\n");
+ exit(1);
+ }
- fprintf(stdout, "Restoring pci devs...\r\n");
- if (vm_restore_devices(&rstate) != 0) {
- fprintf(stderr, "Failed to restore PCI device state.\n");
- exit(1);
+ fprintf(stdout, "Restoring pci devs...\n");
+ if (vm_restore_devices(&rstate) != 0) {
+ fprintf(stderr,
+ "Failed to restore PCI device state.\n");
+ exit(1);
+ }
+
+ fprintf(stdout, "Restoring kernel structs...\n");
+ if (vm_restore_kern_structs(ctx, &rstate) != 0) {
+ fprintf(stderr,
+ "Failed to restore kernel structs.\n");
+ exit(1);
+ }
}
- fprintf(stdout, "Restoring kernel structs...\r\n");
- if (vm_restore_kern_structs(ctx, &rstate) != 0) {
- fprintf(stderr, "Failed to restore kernel structs.\n");
- exit(1);
+ if (migration_host != NULL) {
+ fprintf(stdout, "Starting the migration process...\n");
+ if (receive_vm_migration(ctx, migration_host) != 0) {
+ fprintf(stderr, "Failed to migrate the vm.\n");
+ exit(1);
+ }
}
- fprintf(stdout, "Resuming pci devs...\r\n");
+ fprintf(stdout, "Resuming pci devs...\n");
if (vm_resume_devices() != 0) {
fprintf(stderr, "Failed to resume PCI device state.\n");
exit(1);
}
}
-#endif
+#endif /* BHYVE_SNAPSHOT */
error = vm_get_register(bsp, VM_REG_GUEST_RIP, &rip);
assert(error == 0);
@@ -1609,8 +1636,9 @@
#endif
#ifdef BHYVE_SNAPSHOT
- if (restore_file != NULL) {
+ if (restore_file != NULL)
destroy_restore_state(&rstate);
+ if (restore_file != NULL || migration_host != NULL) {
if (vm_restore_time(ctx) < 0)
err(EX_OSERR, "Unable to restore time");
diff --git a/usr.sbin/bhyve/migration.h b/usr.sbin/bhyve/migration.h
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/migration.h
@@ -0,0 +1,27 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2017-2020 Elena Mihailescu
+ * Copyright (c) 2017-2020 Darius Mihai
+ * Copyright (c) 2017-2020 Mihai Carabas
+ *
+ * The migration feature was developed under sponsorships
+ * from Matthew Grooms.
+ *
+ */
+
+#pragma once
+
+#include <sys/param.h>
+#include <stdbool.h>
+
+#define DEFAULT_MIGRATION_PORT 24983
+
+struct vmctx;
+
+struct migrate_req {
+ char host[MAXHOSTNAMELEN];
+ unsigned int port;
+};
+
+int receive_vm_migration(struct vmctx *ctx, char *migration_data);
diff --git a/usr.sbin/bhyve/migration.c b/usr.sbin/bhyve/migration.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/migration.c
@@ -0,0 +1,98 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2017-2020 Elena Mihailescu
+ * Copyright (c) 2017-2020 Darius Mihai
+ * Copyright (c) 2017-2020 Mihai Carabas
+ *
+ * The migration feature was developed under sponsorships
+ * from Matthew Grooms.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/nv.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <arpa/inet.h>
+#ifndef WITHOUT_CAPSICUM
+#include <capsicum_helpers.h>
+#include <libcasper.h>
+#include <casper/cap_net.h>
+#include <casper/cap_sysctl.h>
+#endif
+#include <err.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vmmapi.h>
+
+#include "migration.h"
+#include "pci_emul.h"
+#include "snapshot.h"
+
+
+#ifdef BHYVE_DEBUG
+#define DPRINTF(FMT, ...) \
+({ \
+ fprintf(stderr, "%s: " FMT "\n", __func__, ##__VA_ARGS__); \
+ })
+#else
+#define DPRINTF(FMT, ...)
+#endif
+
+#define EPRINTF(FMT, ...) \
+({ \
+ fprintf(stderr, "%s: " FMT "\n", __func__, ##__VA_ARGS__); \
+ })
+
+int
+receive_vm_migration(struct vmctx *ctx, char *migration_data)
+{
+ struct migrate_req req;
+ size_t len;
+ char *hostname, *pos;
+ unsigned int port = DEFAULT_MIGRATION_PORT;
+ int rc;
+
+ assert(ctx != NULL);
+ assert(migration_data != NULL);
+
+ memset(req.host, 0, MAXHOSTNAMELEN);
+ hostname = strdup(migration_data);
+
+ if ((pos = strchr(hostname, ':')) != NULL) {
+ *pos = '\0';
+ pos = pos + 1;
+
+ rc = sscanf(pos, "%u", &port);
+
+ if (rc <= 0) {
+ EPRINTF("Could not parse the port");
+ free(hostname);
+ return (EINVAL);
+ }
+ }
+ req.port = port;
+
+ len = strlen(hostname);
+ if (len > MAXHOSTNAMELEN - 1) {
+ EPRINTF("Hostname length %lu bigger than maximum allowed %d",
+ len, MAXHOSTNAMELEN - 1);
+ free(hostname);
+ return (EINVAL);
+ }
+
+ strlcpy(req.host, hostname, MAXHOSTNAMELEN);
+
+ // rc = vm_recv_migrate_req(ctx, req);
+ rc = EOPNOTSUPP;
+ EPRINTF("Migration not implemented yet");
+
+ free(hostname);
+ return (rc);
+}
diff --git a/usr.sbin/bhyve/snapshot.c b/usr.sbin/bhyve/snapshot.c
--- a/usr.sbin/bhyve/snapshot.c
+++ b/usr.sbin/bhyve/snapshot.c
@@ -86,6 +86,7 @@
#include "ioapic.h"
#include "mem.h"
#include "mevent.h"
+#include "migration.h"
#include "mptbl.h"
#include "pci_emul.h"
#include "pci_irq.h"
@@ -1400,6 +1401,40 @@
}
IPC_COMMAND(ipc_cmd_set, checkpoint, vm_do_checkpoint);
+static int
+vm_do_migrate(struct vmctx __unused *ctx, const nvlist_t *nvl)
+{
+ size_t len;
+ struct migrate_req req;
+
+ if (!nvlist_exists_string(nvl, "hostname") ||
+ !nvlist_exists_number(nvl, "port"))
+ return (EINVAL);
+
+ memset(&req, 0, sizeof(struct migrate_req));
+ req.port = nvlist_get_number(nvl, "port");
+
+ len = strlen(nvlist_get_string(nvl, "hostname"));
+ if (len > MAXHOSTNAMELEN - 1) {
+ EPRINTLN("Hostname length %lu bigger than maximum allowed %d",
+ len, MAXHOSTNAMELEN - 1);
+ return (EINVAL);
+ }
+
+ strlcpy(req.host, nvlist_get_string(nvl, "hostname"), MAXHOSTNAMELEN);
+
+ printf("%s: IP address used for migration: %s;\n"
+ "Port used for migration: %d\n",
+ __func__,
+ req.host,
+ req.port);
+
+ // return (vm_send_migrate_req(ctx, req, nvlist_get_bool(nvl, "live")));
+ EPRINTLN("Migration operation not implemented yet\n");
+ return (EOPNOTSUPP);
+}
+IPC_COMMAND(ipc_cmd_set, migrate, vm_do_migrate);
+
void
init_snapshot(void)
{
diff --git a/usr.sbin/bhyvectl/bhyvectl.8 b/usr.sbin/bhyvectl/bhyvectl.8
--- a/usr.sbin/bhyvectl/bhyvectl.8
+++ b/usr.sbin/bhyvectl/bhyvectl.8
@@ -41,6 +41,11 @@
.Op Fl -force-poweroff
.Op Fl -checkpoint= Ns Ar <filename>
.Op Fl -suspend= Ns Ar <filename>
+.Oo
+.Fl -migrate= Ns Ar host Ns Op Cm \&: Ns Ar port
+|
+.Fl -migrate-live= Ns Ar host Ns Op Cm \&: Ns Ar port
+.Oc
.Sh DESCRIPTION
The
.Nm
@@ -85,6 +90,20 @@
.Fl -checkpoint .
The virtual machine will terminate after the snapshot has been
saved.
+.It Fl -migrate= Ns Ar host Ns Op Cm \&: Ns Ar port
+Warm migrate the virtual machine to a
+.Ar host
+on the specified
+.Ar port .
+The default migration port is 24983.
+The virtual machine will be destroyed after the migration finishes.
+.It Fl -migrate-live= Ns Ar host Ns Op Cm \&: Ns Ar port
+Live migrate the virtual machine to a
+.Ar host
+on the specified
+.Ar port .
+The default migration port is 24983.
+The virtual machine will be destroyed after the migration finishes.
.El
.Sh EXIT STATUS
.Ex -std
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -65,6 +65,7 @@
#ifdef BHYVE_SNAPSHOT
#include "snapshot.h"
+#include "migration.h"
#endif
#define MB (1UL << 20)
@@ -87,6 +88,7 @@
" [--destroy]\n"
#ifdef BHYVE_SNAPSHOT
" [--checkpoint=<filename> | --suspend=<filename>]\n"
+ " [--migrate=<host>[:<port>] | --migrate-live=<host>[:<port>]]\n"
#endif
" [--get-all]\n"
" [--get-stats]\n"
@@ -299,6 +301,7 @@
static int get_cpu_topology;
#ifdef BHYVE_SNAPSHOT
static int vm_suspend_opt;
+static int vm_migrate_live;
#endif
/*
@@ -589,6 +592,8 @@
#ifdef BHYVE_SNAPSHOT
SET_CHECKPOINT_FILE,
SET_SUSPEND_FILE,
+ MIGRATE_VM,
+ MIGRATE_VM_LIVE,
#endif
};
@@ -1456,6 +1461,8 @@
#ifdef BHYVE_SNAPSHOT
{ "checkpoint", REQ_ARG, 0, SET_CHECKPOINT_FILE},
{ "suspend", REQ_ARG, 0, SET_SUSPEND_FILE},
+ { "migrate", REQ_ARG, 0, MIGRATE_VM},
+ { "migrate-live", REQ_ARG, 0, MIGRATE_VM_LIVE},
#endif
};
@@ -1743,7 +1750,42 @@
return (send_message(vmname, nvl));
}
-#endif
+
+static int
+migration_request(const char *vmname, const char *migrate_vm, bool live)
+{
+ nvlist_t *nvl;
+ char *hostname, *pos;
+ int rc;
+ unsigned int port = DEFAULT_MIGRATION_PORT;
+
+ hostname = strdup(migrate_vm);
+
+ if ((pos = strchr(hostname, ':')) != NULL) {
+ *pos = '\0';
+ pos = pos + 1;
+
+ rc = sscanf(pos, "%u", &port);
+
+ if (rc <= 0) {
+ fprintf(stderr, "Could not parse the port\n");
+ free(hostname);
+ return (EINVAL);
+ }
+ }
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "migrate");
+ nvlist_add_string(nvl, "hostname", hostname);
+ nvlist_add_number(nvl, "port", port);
+ nvlist_add_bool(nvl, "live", live);
+
+ free(hostname);
+
+ return (send_message(vmname, nvl));
+}
+
+#endif /* BHYVE_SNAPSHOT */
int
main(int argc, char *argv[])
@@ -1763,7 +1805,7 @@
struct tm tm;
struct option *opts;
#ifdef BHYVE_SNAPSHOT
- char *checkpoint_file = NULL;
+ char *checkpoint_file = NULL, *migrate_host = NULL;
#endif
cpu_intel = cpu_vendor_intel();
@@ -1932,6 +1974,14 @@
checkpoint_file = optarg;
vm_suspend_opt = (ch == SET_SUSPEND_FILE);
break;
+ case MIGRATE_VM:
+ case MIGRATE_VM_LIVE:
+ if (migrate_host != NULL)
+ usage(cpu_intel);
+
+ migrate_host = optarg;
+ vm_migrate_live = (ch == MIGRATE_VM_LIVE);
+ break;
#endif
default:
usage(cpu_intel);
@@ -2414,6 +2464,9 @@
#ifdef BHYVE_SNAPSHOT
if (!error && checkpoint_file)
error = snapshot_request(vmname, checkpoint_file, vm_suspend_opt);
+
+ if (!error && migrate_host)
+ error = migration_request(vmname, migrate_host, vm_migrate_live);
#endif
free (opts);

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 29, 7:36 AM (13 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17838497
Default Alt Text
D34717.diff (12 KB)

Event Timeline