From: Bogdan Ionescu <bogdan@ionescu.at>
To: f.gruenbichler@proxmox.com
Cc: pve-devel@lists.proxmox.com, Bogdan Ionescu <bogdan@ionescu.at>
Subject: [PATCH qemu-server] remote migration: allow insecure TCP data plane
Date: Fri, 15 May 2026 00:27:52 +0200 [thread overview]
Message-ID: <20260514222753.13187-1-bogdan@ionescu.at> (raw)
In-Reply-To: <1777552058.4o39hpnqt6.astroid@yuna.none>
Signed-off-by: Bogdan Ionescu <bogdan@ionescu.at>
---
src/PVE/API2/Qemu.pm | 47 +++++++++++++++++++++++++++++++++++-------
src/PVE/CLI/qm.pm | 17 +++++++++++++++
src/PVE/QemuMigrate.pm | 10 +++++++++
3 files changed, 66 insertions(+), 8 deletions(-)
diff --git a/src/PVE/API2/Qemu.pm b/src/PVE/API2/Qemu.pm
index d762401b..43888ab5 100644
--- a/src/PVE/API2/Qemu.pm
+++ b/src/PVE/API2/Qemu.pm
@@ -5668,6 +5668,23 @@ __PACKAGE__->register_method({
minimum => '0',
default => 'migrate limit from datacenter or storage config',
},
+ migration_type => {
+ type => 'string',
+ enum => ['secure', 'insecure'],
+ description =>
+ "Migration traffic is encrypted using a websocket tunnel by default. "
+ . "On secure, completely private networks this can be disabled to "
+ . "increase performance. WARNING: with 'insecure', VM RAM and disk "
+ . "migration data is transferred in clear text over the selected "
+ . "migration network.",
+ optional => 1,
+ },
+ migration_network => {
+ type => 'string',
+ format => 'CIDR',
+ description => "CIDR of the trusted private network used for insecure remote migration.",
+ optional => 1,
+ },
},
},
returns => {
@@ -5683,9 +5700,16 @@ __PACKAGE__->register_method({
my $source_vmid = extract_param($param, 'vmid');
my $target_endpoint = extract_param($param, 'target-endpoint');
my $target_vmid = extract_param($param, 'target-vmid') // $source_vmid;
+ my $migration_type = extract_param($param, 'migration_type') // 'secure';
+ my $migration_network = extract_param($param, 'migration_network');
my $delete = extract_param($param, 'delete') // 0;
+ # insecure remote migration can transfer VM RAM and disk data in clear text
+ if ($migration_type eq 'insecure' || defined($migration_network)) {
+ $rpcenv->check_full($authuser, "/", ['Sys.Modify']);
+ }
+
PVE::Cluster::check_cfs_quorum();
# test if VM exists
@@ -5760,7 +5784,8 @@ __PACKAGE__->register_method({
client => $api_client,
vmid => $target_vmid,
};
- $param->{migration_type} = 'websocket';
+ $param->{migration_type} = $migration_type eq 'insecure' ? 'insecure' : 'websocket';
+ $param->{migration_network} = $migration_network if defined($migration_network);
$param->{'with-local-disks'} = 1;
$param->{delete} = $delete if $delete;
@@ -6716,6 +6741,7 @@ __PACKAGE__->register_method({
return {
api => $PVE::QemuMigrate::WS_TUNNEL_VERSION,
age => 0,
+ caps => ['insecure-remote'],
};
},
'config' => sub {
@@ -6866,19 +6892,24 @@ __PACKAGE__->register_method({
$params->{migrate_opts},
);
- if ($info->{migrate}->{proto} ne 'unix') {
+ if (
+ $params->{migrate_opts}->{type} ne 'insecure'
+ && $info->{migrate}->{proto} ne 'unix'
+ ) {
PVE::QemuServer::vm_stop(undef, $state->{vmid}, 1, 1);
die "migration over non-UNIX sockets not possible\n";
}
- my $socket = $info->{migrate}->{addr};
- chown $state->{socket_uid}, -1, $socket;
- $state->{sockets}->{$socket} = 1;
-
- my $unix_sockets = $info->{migrate}->{unix_sockets};
- foreach my $socket (@$unix_sockets) {
+ if ($info->{migrate}->{proto} eq 'unix') {
+ my $socket = $info->{migrate}->{addr};
chown $state->{socket_uid}, -1, $socket;
$state->{sockets}->{$socket} = 1;
+
+ my $unix_sockets = $info->{migrate}->{unix_sockets} // [];
+ foreach my $socket (@$unix_sockets) {
+ chown $state->{socket_uid}, -1, $socket;
+ $state->{sockets}->{$socket} = 1;
+ }
}
return $info;
},
diff --git a/src/PVE/CLI/qm.pm b/src/PVE/CLI/qm.pm
index bfa0d1d5..43ec442a 100755
--- a/src/PVE/CLI/qm.pm
+++ b/src/PVE/CLI/qm.pm
@@ -224,6 +224,23 @@ __PACKAGE__->register_method({
minimum => '0',
default => 'migrate limit from datacenter or storage config',
},
+ migration_type => {
+ type => 'string',
+ enum => ['secure', 'insecure'],
+ description =>
+ "Migration traffic is encrypted using a websocket tunnel by default. "
+ . "On secure, completely private networks this can be disabled to "
+ . "increase performance. WARNING: with 'insecure', VM RAM and disk "
+ . "migration data is transferred in clear text over the selected "
+ . "migration network.",
+ optional => 1,
+ },
+ migration_network => {
+ type => 'string',
+ format => 'CIDR',
+ description => "CIDR of the trusted private network used for insecure remote migration.",
+ optional => 1,
+ },
},
},
returns => {
diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm
index 8f38bf69..617cc1de 100644
--- a/src/PVE/QemuMigrate.pm
+++ b/src/PVE/QemuMigrate.pm
@@ -46,6 +46,12 @@ use base qw(PVE::AbstractMigrate);
# compared against remote end's minimum version
our $WS_TUNNEL_VERSION = 2;
+sub remote_tunnel_has_cap {
+ my ($tunnel, $cap) = @_;
+
+ return grep { $_ eq $cap } @{ $tunnel->{caps} // [] };
+}
+
sub fork_tunnel {
my ($self, $ssh_forward_info) = @_;
@@ -351,6 +357,10 @@ sub prepare {
if $WS_TUNNEL_VERSION < $min_version;
die "Remote tunnel endpoint too old, upgrade required\n"
if $WS_TUNNEL_VERSION > $tunnel->{version};
+ die "Remote tunnel endpoint does not support insecure remote migration, upgrade target or"
+ . " omit migration_type=insecure\n"
+ if $self->{opts}->{migration_type} eq 'insecure'
+ && !remote_tunnel_has_cap($tunnel, 'insecure-remote');
print "websocket tunnel started\n";
$self->{tunnel} = $tunnel;
--
2.47.3
next prev parent reply other threads:[~2026-05-14 22:36 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-25 1:10 [pve-devel] [RFC] qemu-server: add migration_type=insecure to remote-migrate Bogdan Ionescu
2026-04-30 12:40 ` Fabian Grünbichler
2026-05-14 22:25 ` Bogdan Ionescu
2026-05-14 22:27 ` Bogdan Ionescu [this message]
2026-05-14 22:27 ` [PATCH pve-guest-common] tunnel: propagate remote capabilities Bogdan Ionescu
2026-05-15 21:54 ` [PATCH v2 qemu-server] remote migration: allow insecure TCP data plane Bogdan Ionescu
2026-05-15 21:54 ` [PATCH v2 pve-guest-common] tunnel: propagate remote capabilities Bogdan Ionescu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260514222753.13187-1-bogdan@ionescu.at \
--to=bogdan@ionescu.at \
--cc=f.gruenbichler@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.