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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox