[pve-devel] [PATCH V2 manager] fix #4335: report: add datacenter.cfg to output

2023-02-13 Thread Max Carrara
Includes the contents of /etc/pve/datacenter.cfg
in the cluster section.

Signed-off-by: Max Carrara 
---
Changes from v1:
 * Output of `/etc/pve/datacenter.cfg` is now in the cluster section,
   as discussed[1]

[1] https://lists.proxmox.com/pipermail/pve-devel/2023-February/055715.html

 PVE/Report.pm | 1 +
 1 file changed, 1 insertion(+)

diff --git a/PVE/Report.pm b/PVE/Report.pm
index 90b7cb1c..457bba6e 100644
--- a/PVE/Report.pm
+++ b/PVE/Report.pm
@@ -91,6 +91,7 @@ my $init_report_cmds = sub {
'pvecm status',
'cat /etc/pve/corosync.conf 2>/dev/null',
'ha-manager status',
+   'cat /etc/pve/datacenter.cfg',
],
},
hardware => {
-- 
2.30.2



___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH qemu-server] feature #3937: config: store user in meta property

2023-02-13 Thread Leo Nunner
Adds a field to the "meta" config property which stores the user who
created the VM.

Signed-off-by: Leo Nunner 
---
 PVE/QemuServer.pm | 8 
 1 file changed, 8 insertions(+)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index a0e16dc..28ed8e7 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -281,6 +281,11 @@ my $meta_info_fmt = {
pattern => '\d+(\.\d+)+',
optional => 1,
 },
+'user' => {
+   type => 'string',
+   description => "The user who created the VM.",
+   optional => 1,
+},
 };
 
 my $confdesc = {
@@ -2184,10 +2189,13 @@ sub parse_meta_info {
 sub new_meta_info_string {
 my () = @_; # for now do not allow to override any value
 
+my $rpcenv = PVE::RPCEnvironment->get();
+
 return PVE::JSONSchema::print_property_string(
{
'creation-qemu' => kvm_user_version(),
ctime => "". int(time()),
+   user => $rpcenv->get_user(),
},
$meta_info_fmt
 );
-- 
2.30.2



___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v2 widget-toolkit] ui: SMART: show SMART data in correct columns

2023-02-13 Thread Matthias Heiserer
Signed-off-by: Matthias Heiserer 
---

Changes from v2:
make expression more compact


 src/window/DiskSmart.js | 17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/window/DiskSmart.js b/src/window/DiskSmart.js
index 3c8040b..b538ea1 100644
--- a/src/window/DiskSmart.js
+++ b/src/window/DiskSmart.js
@@ -38,12 +38,12 @@ Ext.define('Proxmox.window.DiskSmart', {
},
{
text: gettext('Value'),
-   dataIndex: 'raw',
+   dataIndex: 'real-value',
renderer: Ext.String.htmlEncode,
},
{
text: gettext('Normalized'),
-   dataIndex: 'value',
+   dataIndex: 'real-normalized',
width: 60,
},
{
@@ -154,7 +154,18 @@ Ext.define('Proxmox.window.DiskSmart', {
 Ext.define('pmx-smart-attribute', {
extend: 'Ext.data.Model',
fields: [
-   { name: 'id', type: 'number' }, 'name', 'value', 'worst', 
'threshold', 'flags', 'fail', 'raw',
+   { name: 'id', type: 'number' }, 'name', 'value', 'worst', 
'threshold', 'flags', 'fail',
+   'raw', 'normalized',
+   {
+   name: 'real-value',
+   // FIXME remove with next major release (PBS 3.0)
+   calculate: data => (data.normalized ?? false) ? data.raw : 
data.value,
+   },
+   {
+   name: 'real-normalized',
+   // FIXME remove with next major release (PBS 3.0)
+   calculate: data => data.normalized ?? data.raw,
+   },
],
idProperty: 'name',
 });
-- 
2.30.2



___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 03/16] memory: refactor sockets

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 10 +++---
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index e10c0b7..3899917 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -165,8 +165,7 @@ sub qemu_memory_hotplug {
 
 return $value if !PVE::QemuServer::check_running($vmid);
 
-my $sockets = 1;
-$sockets = $conf->{sockets} if $conf->{sockets};
+my $sockets = $conf->{sockets} || 1;
 
 my $memory = $conf->{memory} || $defaults->{memory};
 $value = $defaults->{memory} if !$value;
@@ -289,8 +288,7 @@ sub config {
if $conf->{"numa$i"};
}
 
-   my $sockets = 1;
-   $sockets = $conf->{sockets} if $conf->{sockets};
+   my $sockets = $conf->{sockets} || 1;
 
$static_memory = $STATICMEM;
$static_memory = $static_memory * $sockets if ($conf->{hugepages} && 
$conf->{hugepages} == 1024);
@@ -499,9 +497,7 @@ sub hugepages_topology {
 my $defaults = PVE::QemuServer::load_defaults();
 my $memory = $conf->{memory} || $defaults->{memory};
 my $static_memory = 0;
-my $sockets = 1;
-$sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
-$sockets = $conf->{sockets} if $conf->{sockets};
+my $sockets = $conf->{sockets} || 1;
 my $numa_custom_topology = undef;
 my $hotplug_features = 
PVE::QemuServer::parse_hotplug_features(defined($conf->{hotplug}) ? 
$conf->{hotplug} : '1');
 
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 04/16] memory: remove calls to parse_hotplug_features

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer.pm|  6 --
 PVE/QemuServer/Memory.pm | 13 ++---
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index a0e16dc..97185e1 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -3869,7 +3869,7 @@ sub config_to_command {
push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, 
$machine_version, $winversion, $gpu_passthrough);
 }
 
-PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, 
$hotplug_features, $cmd);
+PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, 
$hotplug_features->{memory}, $cmd);
 
 push @$cmd, '-S' if $conf->{freeze};
 
@@ -5902,7 +5902,9 @@ sub vm_start_nolock {
 if ($conf->{hugepages}) {
 
my $code = sub {
-   my $hugepages_topology = 
PVE::QemuServer::Memory::hugepages_topology($conf);
+   my $hotplug_features = 
parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
+   my $hugepages_topology = 
PVE::QemuServer::Memory::hugepages_topology($conf, $hotplug_features->{memory});
+
my $hugepages_host_topology = 
PVE::QemuServer::Memory::hugepages_host_topology();
 
PVE::QemuServer::Memory::hugepages_mount();
diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index 3899917..4812a9e 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -273,12 +273,12 @@ sub qemu_dimm_list {
 }
 
 sub config {
-my ($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd) = 
@_;
+my ($conf, $vmid, $sockets, $cores, $defaults, $hotplug, $cmd) = @_;
 
 my $memory = $conf->{memory} || $defaults->{memory};
 my $static_memory = 0;
 
-if ($hotplug_features->{memory}) {
+if ($hotplug) {
die "NUMA needs to be enabled for memory hotplug\n" if !$conf->{numa};
my $MAX_MEM = get_max_mem($conf);
die "Total memory is bigger than ${MAX_MEM}MB\n" if $memory > $MAX_MEM;
@@ -365,7 +365,7 @@ sub config {
}
 }
 
-if ($hotplug_features->{memory}) {
+if ($hotplug) {
foreach_dimm($conf, $vmid, $memory, $sockets, sub {
my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, 
$memory) = @_;
 
@@ -488,7 +488,7 @@ sub hugepages_size {
 }
 
 sub hugepages_topology {
-my ($conf) = @_;
+my ($conf, $hotplug) = @_;
 
 my $hugepages_topology = {};
 
@@ -499,9 +499,8 @@ sub hugepages_topology {
 my $static_memory = 0;
 my $sockets = $conf->{sockets} || 1;
 my $numa_custom_topology = undef;
-my $hotplug_features = 
PVE::QemuServer::parse_hotplug_features(defined($conf->{hotplug}) ? 
$conf->{hotplug} : '1');
 
-if ($hotplug_features->{memory}) {
+if ($hotplug) {
$static_memory = $STATICMEM;
$static_memory = $static_memory * $sockets if ($conf->{hugepages} && 
$conf->{hugepages} == 1024);
 } else {
@@ -537,7 +536,7 @@ sub hugepages_topology {
}
 }
 
-if ($hotplug_features->{memory}) {
+if ($hotplug) {
my $numa_hostmap = get_numa_guest_to_host_map($conf);
 
foreach_dimm($conf, undef, $memory, $sockets, sub {
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 08/16] config: memory: add 'max' option

2023-02-13 Thread Alexandre Derumier
max can be multiple of 64GiB only,
The dimm size is compute from the max memory

we can have 64 slots:

64GiB = 64 slots x 1GiB
128GiB = 64 slots x 2GiB
..
4TiB = 64 slots x 64GiB

Also, with numa, we need to share slot between (up to 8) sockets.

64 is a multiple of 8,

64GiB = 8 sockets * 8 slots * 1GiB
128GiB = 8 sockets * 8 slots * 2GiB
...

and with virtio-mem,
we can have 32000 blocks of 2MiB minimum

64GB = 32000 * 2MiB

Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer.pm|  4 ++--
 PVE/QemuServer/Memory.pm | 33 +
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index f1330f1..3bd86da 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -5042,7 +5042,7 @@ sub vmconfig_hotplug_pending {
vm_deviceunplug($vmid, $conf, $opt);
vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, 
$force);
} elsif ($opt =~ m/^memory$/) {
-   die "skip\n" if !$hotplug_features->{memory};
+   die "skip\n" if 
!PVE::QemuServer::Memory::can_hotplug($hotplug_features->{memory}, $conf);
PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf);
} elsif ($opt eq 'cpuunits') {
$cgroup->change_cpu_shares(undef);
@@ -5118,7 +5118,7 @@ sub vmconfig_hotplug_pending {
vmconfig_update_disk($storecfg, $conf, 
$hotplug_features->{disk},
 $vmid, $opt, $value, $arch, $machine_type);
} elsif ($opt =~ m/^memory$/) { #dimms
-   die "skip\n" if !$hotplug_features->{memory};
+   die "skip\n" if 
!PVE::QemuServer::Memory::can_hotplug($hotplug_features->{memory}, $conf, 
$value);
$value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, 
$conf, $value);
} elsif ($opt eq 'cpuunits') {
my $new_cpuunits = 
PVE::CGroup::clamp_cpu_shares($conf->{pending}->{$opt}); #clamp
diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index 32fbdc5..deeb88f 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -3,8 +3,10 @@ package PVE::QemuServer::Memory;
 use strict;
 use warnings;
 
+use PVE::JSONSchema;
 use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline 
dir_glob_foreach);
 use PVE::Exception qw(raise raise_param_exc);
+use PVE::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne);
 
 use PVE::QemuServer;
 use PVE::QemuServer::Monitor qw(mon_cmd);
@@ -25,8 +27,26 @@ our $memory_fmt = {
minimum => 16,
default => 512,
 },
+max => {
+   type => 'integer',
+   optional => 1,
+   minimum => 65536,
+   maximum => 4194304,
+   format => 'pve-qm-memory-max',
+},
 };
 
+PVE::JSONSchema::register_format('pve-qm-memory-max', \&verify_qm_memory_max);
+sub verify_qm_memory_max {
+my ($max, $noerr) = @_;
+
+return if $noerr;
+
+die "max memory need to be a multiple of 64GiB\n" if $max && $max % 65536 
!= 0;
+
+return $max
+}
+
 sub print_memory {
 my $memory = shift;
 
@@ -313,6 +333,19 @@ sub qemu_memory_hotplug {
 return $conf->{memory};
 }
 
+sub can_hotplug {
+my ($hotplug, $conf, $value) = @_;
+
+return if !$hotplug;
+
+my $oldmem = parse_memory($conf->{memory});
+my $newmem = parse_memory($value);
+
+return if safe_num_ne($newmem->{max}, $oldmem->{max});
+
+return 1;
+}
+
 sub qemu_dimm_list {
 my ($vmid) = @_;
 
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 00/16] rework memory hotplug + virtiomem

2023-02-13 Thread Alexandre Derumier
This patch series rework the current memory hotplug + virtiomem.

memory option now have extra options:

memory: [[current=]] [,max=] [,virtio=<1|0>]
ex: memory: current=1024,max=131072,virtio=1


for classic memory hotplug, when maxmemory is defined,
we use 64 fixed size dimm.
The max option is a multiple of 64GB.

The virtio option enable new virtio-mem support,
instead of plugging dimm, it's add/removed block inside
big dimm.
virtio-mem can use 32000 blocks, the blocksize is compute from
max memory.


Changelog v2:

update differents patches based on Fiona comments.
(I have send 2 others mails with comments not yet addressed)

Biggest change is on virtio-mem, instead of trying to have same amount of memory
on each virtiomem (some block could be unmovable and break unplug),
we try to balance/dispatch remaining block on other available virtiomems.

Also, the minimum blocksize supported by linux guest os is 4MB currently,
even if virtiomem can use 2MB on qemu side.


Changelog v3:

- cleanup from last Fiona comments
- classic hotplug : fix memory unplug
- virtio-mem: split retry logic in a second optional patch 
  (feel free to apply it later if needed)

Changelog v4:
- cleanup from last Fiona comments



Alexandre Derumier (16):
  memory: extract some code to their own sub for mocking
  tests: add memory tests
  memory: refactor sockets
  memory: remove calls to parse_hotplug_features
  add memory parser
  memory: add get_static_mem
  memory: use static_memory in foreach_dimm
  config: memory: add 'max' option
  memory: get_max_mem: use config memory max
  memory: rename qemu_dimm_list to qemu_memdevices_list
  memory: don't use foreach_reversedimm for unplug
  memory: use 64 slots && static dimm size when max is defined
  test: add memory-max tests
  memory: add virtio-mem support
  memory: virtio-mem : implement redispatch retry.
  tests: add virtio-mem tests

 PVE/API2/Qemu.pm  |  38 +-
 PVE/QemuConfig.pm |   4 +-
 PVE/QemuMigrate.pm|   6 +-
 PVE/QemuServer.pm |  40 +-
 PVE/QemuServer/Helpers.pm |   3 +-
 PVE/QemuServer/Memory.pm  | 527 ++
 PVE/QemuServer/PCI.pm |   8 +
 test/cfg2cmd/memory-hotplug-hugepages.conf|  12 +
 .../cfg2cmd/memory-hotplug-hugepages.conf.cmd |  62 +++
 test/cfg2cmd/memory-hotplug.conf  |  11 +
 test/cfg2cmd/memory-hotplug.conf.cmd  | 174 ++
 test/cfg2cmd/memory-hugepages-1g.conf |  11 +
 test/cfg2cmd/memory-hugepages-1g.conf.cmd |  30 +
 test/cfg2cmd/memory-hugepages-2m.conf |  11 +
 test/cfg2cmd/memory-hugepages-2m.conf.cmd |  30 +
 test/cfg2cmd/memory-max-128G.conf |  11 +
 test/cfg2cmd/memory-max-128G.conf.cmd |  86 +++
 test/cfg2cmd/memory-max-512G.conf |  11 +
 test/cfg2cmd/memory-max-512G.conf.cmd |  58 ++
 test/cfg2cmd/memory-virtio-hugepages-1G.conf  |  12 +
 .../memory-virtio-hugepages-1G.conf.cmd   |  35 ++
 test/cfg2cmd/memory-virtio-max.conf   |  11 +
 test/cfg2cmd/memory-virtio-max.conf.cmd   |  35 ++
 test/cfg2cmd/memory-virtio.conf   |  11 +
 test/cfg2cmd/memory-virtio.conf.cmd   |  35 ++
 test/run_config2command_tests.pl  |  15 +
 26 files changed, 1135 insertions(+), 152 deletions(-)
 create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf
 create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf.cmd
 create mode 100644 test/cfg2cmd/memory-hotplug.conf
 create mode 100644 test/cfg2cmd/memory-hotplug.conf.cmd
 create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf
 create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf.cmd
 create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf
 create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf.cmd
 create mode 100644 test/cfg2cmd/memory-max-128G.conf
 create mode 100644 test/cfg2cmd/memory-max-128G.conf.cmd
 create mode 100644 test/cfg2cmd/memory-max-512G.conf
 create mode 100644 test/cfg2cmd/memory-max-512G.conf.cmd
 create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf
 create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd
 create mode 100644 test/cfg2cmd/memory-virtio-max.conf
 create mode 100644 test/cfg2cmd/memory-virtio-max.conf.cmd
 create mode 100644 test/cfg2cmd/memory-virtio.conf
 create mode 100644 test/cfg2cmd/memory-virtio.conf.cmd

-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 11/16] memory: don't use foreach_reversedimm for unplug

2023-02-13 Thread Alexandre Derumier
simple use dimm_list() returned by qemu

Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 73 
 1 file changed, 22 insertions(+), 51 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index a13b3a1..cf1ddb9 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -217,38 +217,6 @@ sub foreach_dimm{
 }
 }
 
-sub foreach_reverse_dimm {
-my ($conf, $vmid, $memory, $sockets, $func) = @_;
-
-my $dimm_id = 253;
-my $current_size = 0;
-my $dimm_size = 0;
-
-if($conf->{hugepages} && $conf->{hugepages} == 1024) {
-   $current_size = 8355840;
-   $dimm_size = 131072;
-} else {
-   $current_size = 4177920;
-   $dimm_size = 65536;
-}
-
-return if $current_size == $memory;
-
-my @numa_map = get_numa_node_list($conf);
-
-for (my $j = 0; $j < 8; $j++) {
-   for (my $i = 0; $i < 32; $i++) {
-   my $name = "dimm${dimm_id}";
-   $dimm_id--;
-   my $numanode = $numa_map[(31-$i) % @numa_map];
-   $current_size -= $dimm_size;
-   &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, 
$memory);
-   return  $current_size if $current_size <= $memory;
-   }
-   $dimm_size /= 2;
-}
-}
-
 sub qemu_memory_hotplug {
 my ($vmid, $conf, $value) = @_;
 
@@ -322,30 +290,33 @@ sub qemu_memory_hotplug {
 
 } else {
 
-   foreach_reverse_dimm($conf, $vmid, $value, $sockets, sub {
-   my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, 
$memory) = @_;
+   my $dimms = qemu_dimm_list($vmid);
+   my $current_size = $memory;
+   for my $name (sort { $dimms->{$b}{slot} <=> $dimms->{$a}{slot} } keys 
%$dimms) {
 
-   return if $current_size >= get_current_memory($conf->{memory});
+   my $dimm_size = $dimms->{$name}->{size} / 1024 / 1024;
 
-   print "try to unplug memory dimm $name\n";
+   last if $current_size <= $value;
 
-   my $retry = 0;
-   while (1) {
-   eval { PVE::QemuServer::qemu_devicedel($vmid, $name) };
-   sleep 3;
-   my $dimm_list = qemu_memdevices_list($vmid, '^dimm(\d+)$');
-   last if !$dimm_list->{$name};
-   raise_param_exc({ $name => "error unplug memory module" }) 
if $retry > 5;
-   $retry++;
-   }
+   print "try to unplug memory dimm $name\n";
 
-   #update conf after each succesful module unplug
-   $newmem->{current} = $current_size;
-   $conf->{memory} = print_memory($newmem);
+   my $retry = 0;
+   while (1) {
+   eval { PVE::QemuServer::qemu_devicedel($vmid, $name) };
+   sleep 3;
+   my $dimm_list = qemu_memdevices_list($vmid, '^dimm(\d+)$');
+   last if !$dimm_list->{$name};
+   raise_param_exc({ $name => "error unplug memory module" }) if 
$retry > 5;
+   $retry++;
+   }
+   $current_size -= $dimm_size;
+   #update conf after each succesful module unplug
+   $newmem->{current} = $current_size;
+   $conf->{memory} = print_memory($newmem);
 
-   eval { PVE::QemuServer::qemu_objectdel($vmid, "mem-$name"); };
-   PVE::QemuConfig->write_config($vmid, $conf);
-   });
+   eval { PVE::QemuServer::qemu_objectdel($vmid, "mem-$name"); };
+   PVE::QemuConfig->write_config($vmid, $conf);
+   }
 }
 return $conf->{memory};
 }
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 15/16] memory: virtio-mem : implement redispatch retry.

2023-02-13 Thread Alexandre Derumier
If some memory can be removed on a specific node,
we try to rebalance again on other nodes

Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 51 +++-
 1 file changed, 35 insertions(+), 16 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index bf4e92a..f02b4e0 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -201,13 +201,28 @@ my sub get_virtiomem_total_current_size {
 return $size;
 }
 
+my sub get_virtiomem_total_errors_size {
+my ($mems) = @_;
+
+my $size = 0;
+for my $mem (values %$mems) {
+   next if !$mem->{error};
+   $size += $mem->{current};
+}
+return $size;
+}
+
 my sub balance_virtiomem {
 my ($vmid, $virtiomems, $blocksize, $target_total) = @_;
 
-my $nb_virtiomem = scalar(keys %$virtiomems);
+my $nb_virtiomem = scalar(grep { !$_->{error} } values $virtiomems->%*);
 
 print"try to balance memory on $nb_virtiomem virtiomems\n";
 
+die "No more available blocks in virtiomem to balance all requested 
memory\n"
+   if $target_total < 0;
+die "No more available virtiomem to balance the remaining memory\n" if 
$nb_virtiomem == 0;
+
 #if we can't share exactly the same amount, we add the remainder on last 
node
 my $target_aligned = int( $target_total / $nb_virtiomem / $blocksize) * 
$blocksize;
 my $target_remaining = $target_total - ($target_aligned * 
($nb_virtiomem-1));
@@ -215,6 +230,7 @@ my sub balance_virtiomem {
 my $i = 0;
 foreach my $id (sort keys %$virtiomems) {
my $virtiomem = $virtiomems->{$id};
+   next if $virtiomem->{error};
$i++;
my $virtiomem_target = $i == $nb_virtiomem ? $target_remaining : 
$target_aligned;
$virtiomem->{completed} = 0;
@@ -229,7 +245,6 @@ my sub balance_virtiomem {
 }
 
 my $total_finished = 0;
-my $error = undef;
 
 while ($total_finished != $nb_virtiomem) {
 
@@ -267,7 +282,6 @@ my sub balance_virtiomem {
if($virtiomem->{retry} >= 5) {
print "virtiomem$id: too many retry. set error\n";
$virtiomem->{error} = 1;
-   $error = 1;
#as change is async, we don't want that value change after the 
api call
eval {
mon_cmd($vmid, 'qom-set', 
@@ -280,7 +294,6 @@ my sub balance_virtiomem {
$virtiomem->{retry}++;
}
 }
-die "No more available blocks in virtiomem to balance all requested 
memory\n" if $error;
 }
 
 sub get_numa_node_list {
@@ -388,18 +401,24 @@ sub qemu_memory_hotplug {
};
}
 
-   my $target_total = $value - $static_memory;
-   my $err;
-   eval {
-   balance_virtiomem($vmid, $virtiomems, $blocksize, $target_total);
-   };
-   $err = $@ if $@;
-
-   my $current_memory = $static_memory + 
get_virtiomem_total_current_size($virtiomems);
-   $newmem->{current} = $current_memory;
-   $conf->{memory} = print_memory($newmem);
-   PVE::QemuConfig->write_config($vmid, $conf);
-   die $err if $err;
+   while (1) {
+
+   my $target_total = $value - $static_memory - 
get_virtiomem_total_errors_size($virtiomems);
+   my $err;
+   eval {
+   balance_virtiomem($vmid, $virtiomems, $blocksize, 
$target_total);
+   };
+   $err = $@ if $@;
+
+   my $current_memory = $static_memory + 
get_virtiomem_total_current_size($virtiomems);
+   $newmem->{current} = $current_memory;
+   $conf->{memory} = print_memory($newmem);
+   PVE::QemuConfig->write_config($vmid, $conf);
+
+   die $err if $err;
+   last if $current_memory == $value;
+   }
+   return $conf->{memory};
 
 } elsif ($value > $memory) {
 
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 05/16] add memory parser

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 PVE/API2/Qemu.pm  |  7 ++--
 PVE/QemuConfig.pm |  4 +--
 PVE/QemuMigrate.pm|  6 ++--
 PVE/QemuServer.pm | 27 +++
 PVE/QemuServer/Helpers.pm |  3 +-
 PVE/QemuServer/Memory.pm  | 71 ---
 6 files changed, 82 insertions(+), 36 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 587bb22..9b80da1 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -32,6 +32,7 @@ use PVE::QemuServer::Drive;
 use PVE::QemuServer::ImportDisk;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::Machine;
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::QemuMigrate;
 use PVE::RPCEnvironment;
 use PVE::AccessControl;
@@ -1489,8 +1490,6 @@ my $update_vm_api  = sub {
 
 my $storecfg = PVE::Storage::config();
 
-my $defaults = PVE::QemuServer::load_defaults();
-
 &$resolve_cdrom_alias($param);
 
 # now try to verify all parameters
@@ -1608,7 +1607,9 @@ my $update_vm_api  = sub {
}
 
if ($param->{memory} || defined($param->{balloon})) {
-   my $maxmem = $param->{memory} || $conf->{pending}->{memory} || 
$conf->{memory} || $defaults->{memory};
+
+   my $memory = $param->{memory} || $conf->{pending}->{memory} || 
$conf->{memory};
+   my $maxmem = get_current_memory($memory);
my $balloon = defined($param->{balloon}) ? $param->{balloon} : 
$conf->{pending}->{balloon} || $conf->{balloon};
 
die "balloon value too large (must be smaller than assigned 
memory)\n"
diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
index 051382c..999e658 100644
--- a/PVE/QemuConfig.pm
+++ b/PVE/QemuConfig.pm
@@ -12,6 +12,7 @@ use PVE::QemuServer::Helpers;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer;
 use PVE::QemuServer::Machine;
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::Storage;
 use PVE::Tools;
 use PVE::Format qw(render_bytes render_duration);
@@ -208,8 +209,7 @@ sub __snapshot_save_vmstate {
$target = PVE::QemuServer::find_vmstate_storage($conf, $storecfg);
 }
 
-my $defaults = PVE::QemuServer::load_defaults();
-my $mem_size = $conf->{memory} // $defaults->{memory};
+my $mem_size = get_current_memory($conf->{memory});
 my $driver_state_size = 500; # assume 500MB is enough to safe all driver 
state;
 # our savevm-start does live-save of the memory until the space left in the
 # volume is just enough for the remaining memory content + internal state
diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index 09cc1d8..f86fdbe 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -26,6 +26,7 @@ use PVE::QemuServer::Drive;
 use PVE::QemuServer::Helpers qw(min_version);
 use PVE::QemuServer::Machine;
 use PVE::QemuServer::Monitor qw(mon_cmd);
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::QemuServer;
 
 use PVE::AbstractMigrate;
@@ -1026,7 +1027,8 @@ sub phase2_start_remote_cluster {
 my $remote_vmid = $self->{opts}->{remote}->{vmid};
 
 # like regular start but with some overhead accounted for
-my $timeout = 
PVE::QemuServer::Helpers::config_aware_timeout($self->{vmconf}) + 10;
+my $memory = get_current_memory($self->{vmconf}->{memory});
+my $timeout = 
PVE::QemuServer::Helpers::config_aware_timeout($self->{vmconf}, $memory) + 10;
 
 my $res = PVE::Tunnel::write_tunnel($self->{tunnel}, $timeout, "start", 
$params);
 
@@ -1181,7 +1183,7 @@ sub phase2 {
 $qemu_migrate_params->{'downtime-limit'} = int($migrate_downtime);
 
 # set cachesize to 10% of the total memory
-my $memory =  $conf->{memory} || $defaults->{memory};
+my $memory = get_current_memory($conf->{memory});
 my $cachesize = int($memory * 1048576 / 10);
 $cachesize = round_powerof2($cachesize);
 
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 97185e1..f1330f1 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -53,7 +53,7 @@ use PVE::QemuServer::CGroup;
 use PVE::QemuServer::CPUConfig qw(print_cpu_device get_cpu_options);
 use PVE::QemuServer::Drive qw(is_valid_drivename drive_is_cloudinit 
drive_is_cdrom drive_is_read_only parse_drive print_drive);
 use PVE::QemuServer::Machine;
-use PVE::QemuServer::Memory;
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr 
print_pcie_root_port parse_hostpci);
 use PVE::QemuServer::USB qw(parse_usb_device);
@@ -341,11 +341,9 @@ my $confdesc = {
 },
 memory => {
optional => 1,
-   type => 'integer',
-   description => "Amount of RAM for the VM in MiB. This is the maximum 
available memory when"
-   ." you use the balloon device.",
-   minimum => 16,
-   default => 512,
+   type => 'string',
+   description => "Memory properties.",
+   format => $PVE::QemuServer::Memory::memory_fmt
 },
 balloon => {
o

[pve-devel] [PATCH v4 qemu-server 13/16] test: add memory-max tests

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 test/cfg2cmd/memory-max-128G.conf | 11 
 test/cfg2cmd/memory-max-128G.conf.cmd | 86 +++
 test/cfg2cmd/memory-max-512G.conf | 11 
 test/cfg2cmd/memory-max-512G.conf.cmd | 58 ++
 4 files changed, 166 insertions(+)
 create mode 100644 test/cfg2cmd/memory-max-128G.conf
 create mode 100644 test/cfg2cmd/memory-max-128G.conf.cmd
 create mode 100644 test/cfg2cmd/memory-max-512G.conf
 create mode 100644 test/cfg2cmd/memory-max-512G.conf.cmd

diff --git a/test/cfg2cmd/memory-max-128G.conf 
b/test/cfg2cmd/memory-max-128G.conf
new file mode 100644
index 000..8f0328d
--- /dev/null
+++ b/test/cfg2cmd/memory-max-128G.conf
@@ -0,0 +1,11 @@
+# TEST: memorymax 64G with 2 socket, dimm size should be 1GB && static memory 
should be 4G
+# QEMU_VERSION: 7.2
+cores: 2
+memory: 32768,max=65536
+name: simple
+numa: 1
+ostype: l26
+smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465
+sockets: 2
+vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8
+hotplug: memory
\ No newline at end of file
diff --git a/test/cfg2cmd/memory-max-128G.conf.cmd 
b/test/cfg2cmd/memory-max-128G.conf.cmd
new file mode 100644
index 000..5b22027
--- /dev/null
+++ b/test/cfg2cmd/memory-max-128G.conf.cmd
@@ -0,0 +1,86 @@
+/usr/bin/kvm \
+  -id 8006 \
+  -name 'simple,debug-threads=on' \
+  -no-shutdown \
+  -chardev 
'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \
+  -mon 'chardev=qmp,mode=control' \
+  -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \
+  -mon 'chardev=qmp-event,mode=control' \
+  -pidfile /var/run/qemu-server/8006.pid \
+  -daemonize \
+  -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \
+  -smp '4,sockets=2,cores=2,maxcpus=4' \
+  -nodefaults \
+  -boot 
'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg'
 \
+  -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \
+  -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \
+  -m 'size=4096,slots=64,maxmem=65536M' \
+  -object 'memory-backend-ram,id=ram-node0,size=2048M' \
+  -numa 'node,nodeid=0,cpus=0-1,memdev=ram-node0' \
+  -object 'memory-backend-ram,id=ram-node1,size=2048M' \
+  -numa 'node,nodeid=1,cpus=2-3,memdev=ram-node1' \
+  -object 'memory-backend-ram,id=mem-dimm0,size=1024M' \
+  -device 'pc-dimm,id=dimm0,memdev=mem-dimm0,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm1,size=1024M' \
+  -device 'pc-dimm,id=dimm1,memdev=mem-dimm1,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm2,size=1024M' \
+  -device 'pc-dimm,id=dimm2,memdev=mem-dimm2,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm3,size=1024M' \
+  -device 'pc-dimm,id=dimm3,memdev=mem-dimm3,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm4,size=1024M' \
+  -device 'pc-dimm,id=dimm4,memdev=mem-dimm4,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm5,size=1024M' \
+  -device 'pc-dimm,id=dimm5,memdev=mem-dimm5,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm6,size=1024M' \
+  -device 'pc-dimm,id=dimm6,memdev=mem-dimm6,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm7,size=1024M' \
+  -device 'pc-dimm,id=dimm7,memdev=mem-dimm7,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm8,size=1024M' \
+  -device 'pc-dimm,id=dimm8,memdev=mem-dimm8,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm9,size=1024M' \
+  -device 'pc-dimm,id=dimm9,memdev=mem-dimm9,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm10,size=1024M' \
+  -device 'pc-dimm,id=dimm10,memdev=mem-dimm10,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm11,size=1024M' \
+  -device 'pc-dimm,id=dimm11,memdev=mem-dimm11,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm12,size=1024M' \
+  -device 'pc-dimm,id=dimm12,memdev=mem-dimm12,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm13,size=1024M' \
+  -device 'pc-dimm,id=dimm13,memdev=mem-dimm13,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm14,size=1024M' \
+  -device 'pc-dimm,id=dimm14,memdev=mem-dimm14,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm15,size=1024M' \
+  -device 'pc-dimm,id=dimm15,memdev=mem-dimm15,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm16,size=1024M' \
+  -device 'pc-dimm,id=dimm16,memdev=mem-dimm16,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm17,size=1024M' \
+  -device 'pc-dimm,id=dimm17,memdev=mem-dimm17,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm18,size=1024M' \
+  -device 'pc-dimm,id=dimm18,memdev=mem-dimm18,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm19,size=1024M' \
+  -device 'pc-dimm,id=dimm19,memdev=mem-dimm19,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm20,size=1024M' \
+  -device 'pc-dimm,id=dimm20,memdev=mem-dimm20,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm21,size=1024M' \
+  -device 'pc-dimm,id=dimm21,memdev=mem-dimm21,node=1' \
+  -object 'memory-backend-ram,id=mem-dimm22,size=1024M' \
+  -device 'pc-dimm,id=dimm22,memdev=mem-dimm22,node=0' \
+  -object 'memory-backend-ram,id=mem-dimm23,size=1024M' \

[pve-devel] [PATCH v4 qemu-server 02/16] tests: add memory tests

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 test/cfg2cmd/memory-hotplug-hugepages.conf|  12 ++
 .../cfg2cmd/memory-hotplug-hugepages.conf.cmd |  62 +++
 test/cfg2cmd/memory-hotplug.conf  |  11 ++
 test/cfg2cmd/memory-hotplug.conf.cmd  | 174 ++
 test/cfg2cmd/memory-hugepages-1g.conf |  11 ++
 test/cfg2cmd/memory-hugepages-1g.conf.cmd |  30 +++
 test/cfg2cmd/memory-hugepages-2m.conf |  11 ++
 test/cfg2cmd/memory-hugepages-2m.conf.cmd |  30 +++
 test/run_config2command_tests.pl  |  15 ++
 9 files changed, 356 insertions(+)
 create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf
 create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf.cmd
 create mode 100644 test/cfg2cmd/memory-hotplug.conf
 create mode 100644 test/cfg2cmd/memory-hotplug.conf.cmd
 create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf
 create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf.cmd
 create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf
 create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf.cmd

diff --git a/test/cfg2cmd/memory-hotplug-hugepages.conf 
b/test/cfg2cmd/memory-hotplug-hugepages.conf
new file mode 100644
index 000..6cba31e
--- /dev/null
+++ b/test/cfg2cmd/memory-hotplug-hugepages.conf
@@ -0,0 +1,12 @@
+# TEST: memory hotplug with 1GB hugepage
+# QEMU_VERSION: 3.0
+cores: 2
+memory: 18432
+name: simple
+numa: 1
+ostype: l26
+smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465
+sockets: 2
+vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8
+hotplug: memory
+hugepages: 1024
\ No newline at end of file
diff --git a/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd 
b/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd
new file mode 100644
index 000..6d4d8e8
--- /dev/null
+++ b/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd
@@ -0,0 +1,62 @@
+/usr/bin/kvm \
+  -id 8006 \
+  -name 'simple,debug-threads=on' \
+  -no-shutdown \
+  -chardev 
'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \
+  -mon 'chardev=qmp,mode=control' \
+  -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \
+  -mon 'chardev=qmp-event,mode=control' \
+  -pidfile /var/run/qemu-server/8006.pid \
+  -daemonize \
+  -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \
+  -smp '4,sockets=2,cores=2,maxcpus=4' \
+  -nodefaults \
+  -boot 
'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg'
 \
+  -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \
+  -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \
+  -m 'size=2048,slots=255,maxmem=524288M' \
+  -object 
'memory-backend-file,id=ram-node0,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -numa 'node,nodeid=0,cpus=0-1,memdev=ram-node0' \
+  -object 
'memory-backend-file,id=ram-node1,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -numa 'node,nodeid=1,cpus=2-3,memdev=ram-node1' \
+  -object 
'memory-backend-file,id=mem-dimm0,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm0,memdev=mem-dimm0,node=0' \
+  -object 
'memory-backend-file,id=mem-dimm1,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm1,memdev=mem-dimm1,node=1' \
+  -object 
'memory-backend-file,id=mem-dimm2,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm2,memdev=mem-dimm2,node=0' \
+  -object 
'memory-backend-file,id=mem-dimm3,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm3,memdev=mem-dimm3,node=1' \
+  -object 
'memory-backend-file,id=mem-dimm4,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm4,memdev=mem-dimm4,node=0' \
+  -object 
'memory-backend-file,id=mem-dimm5,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm5,memdev=mem-dimm5,node=1' \
+  -object 
'memory-backend-file,id=mem-dimm6,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm6,memdev=mem-dimm6,node=0' \
+  -object 
'memory-backend-file,id=mem-dimm7,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm7,memdev=mem-dimm7,node=1' \
+  -object 
'memory-backend-file,id=mem-dimm8,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm8,memdev=mem-dimm8,node=0' \
+  -object 
'memory-backend-file,id=mem-dimm9,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm9,memdev=mem-dimm9,node=1' \
+  -object 
'memory-backend-file,id=mem-dimm10,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes'
 \
+  -device 'pc-dimm,id=dimm10,memdev=mem-dimm10,node=0' \
+  -object 
'memory-backend-file,id=mem-dimm11,size=1024M,mem-path=/run/hugepages

[pve-devel] [PATCH v4 qemu-server 01/16] memory: extract some code to their own sub for mocking

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index 6fac468..e10c0b7 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -13,7 +13,7 @@ my $MAX_NUMA = 8;
 my $STATICMEM = 1024;
 
 my $_host_bits;
-my sub get_host_phys_address_bits {
+sub get_host_phys_address_bits {
 return $_host_bits if defined($_host_bits);
 
 my $fh = IO::File->new ('/proc/cpuinfo', "r") or return;
@@ -76,6 +76,12 @@ sub get_numa_node_list {
 return (0..($sockets-1));
 }
 
+sub host_numanode_exists {
+my ($id) = @_;
+
+return -d "/sys/devices/system/node/node$id/";
+}
+
 # only valid when numa nodes map to a single host node
 sub get_numa_guest_to_host_map {
 my ($conf) = @_;
@@ -348,7 +354,7 @@ sub config {
my $numa_memory = ($static_memory / $sockets);
 
for (my $i = 0; $i < $sockets; $i++)  {
-   die "host NUMA node$i doesn't exist\n" if ! -d 
"/sys/devices/system/node/node$i/" && $conf->{hugepages};
+   die "host NUMA node$i doesn't exist\n" if 
!host_numanode_exists($i) && $conf->{hugepages};
 
my $mem_object = print_mem_object($conf, "ram-node$i", 
$numa_memory);
push @$cmd, '-object', $mem_object;
@@ -402,7 +408,7 @@ sub print_numa_hostnodes {
$hostnodes .= "-$end" if defined($end);
$end //= $start;
for (my $i = $start; $i <= $end; ++$i ) {
-   die "host NUMA node$i doesn't exist\n" if ! -d 
"/sys/devices/system/node/node$i/";
+   die "host NUMA node$i doesn't exist\n" if !host_numanode_exists($i);
}
 }
 return $hostnodes;
@@ -445,21 +451,26 @@ sub hugepages_nr {
   return $size / $hugepages_size;
 }
 
+sub hugepages_chunk_size_supported {
+my ($size) = @_;
+
+return -d "/sys/kernel/mm/hugepages/hugepages-". ($size * 1024) ."kB";
+}
+
 sub hugepages_size {
 my ($conf, $size) = @_;
 die "hugepages option is not enabled" if !$conf->{hugepages};
 die "memory size '$size' is not a positive even integer; cannot use for 
hugepages\n"
if $size <= 0 || $size & 1;
 
-my $page_chunk = sub { -d  "/sys/kernel/mm/hugepages/hugepages-". ($_[0] * 
1024) ."kB" };
-die "your system doesn't support hugepages\n" if !$page_chunk->(2) && 
!$page_chunk->(1024);
+die "your system doesn't support hugepages\n" if 
!hugepages_chunk_size_supported(2) && !hugepages_chunk_size_supported(1024);
 
 if ($conf->{hugepages} eq 'any') {
 
# try to use 1GB if available && memory size is matching
-   if ($page_chunk->(1024) && ($size & 1023) == 0) {
+   if (hugepages_chunk_size_supported(1024) && ($size & 1023) == 0) {
return 1024;
-   } elsif ($page_chunk->(2)) {
+   } elsif (hugepages_chunk_size_supported(2)) {
return 2;
} else {
die "host only supports 1024 GB hugepages, but requested size 
'$size' is not a multiple of 1024 MB\n"
@@ -468,7 +479,7 @@ sub hugepages_size {
 
my $hugepagesize = $conf->{hugepages};
 
-   if (!$page_chunk->($hugepagesize)) {
+   if (!hugepages_chunk_size_supported($hugepagesize)) {
die "your system doesn't support hugepages of $hugepagesize MB\n";
} elsif (($size % $hugepagesize) != 0) {
die "Memory size $size is not a multiple of the requested hugepages 
size $hugepagesize\n";
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 14/16] memory: add virtio-mem support

2023-02-13 Thread Alexandre Derumier
a 4GiB static memory is needed for DMA+boot memory, as this memory
is almost always un-unpluggeable.

1 virtio-mem pci device is setup for each numa node on pci.4 bridge

virtio-mem use a fixed blocksize with 32000 blocks
Blocksize is computed from the maxmemory-4096/32000 with a minimum of
2MiB to map THP.
(lower blocksize = more chance to unplug memory).

Note: Currently, linux only support 4MiB virtio blocksize, 2MiB support
is currently is progress.

For hotplug/unplug, we are try to allocate/unallocate same amount
of memory aligned to the blocksize on each numa node if possible.
If a node a not able to reach the target memory (could be an unmovable
page on unplug for example), we try again to redispatch memory the
remaining memory on others nodes.

About hugepages:

For ordinary memory devices, such as DIMMs, we preallocate memory via the
memory backend for such use cases; however, with virtio-mem we're dealing
with sparse memory backends; preallocating the whole memory backend
destroys the whole purpose of virtio-mem.

Instead, we want to preallocate memory when actually exposing memory to the
VM dynamically, and fail plugging memory gracefully + warn the user in case
preallocation fails.

fixes:
https://bugzilla.proxmox.com/show_bug.cgi?id=2949
Signed-off-by: Alexandre Derumier 
---
 PVE/API2/Qemu.pm |   9 +-
 PVE/QemuServer.pm|   7 +-
 PVE/QemuServer/Memory.pm | 215 ---
 PVE/QemuServer/PCI.pm|   8 ++
 4 files changed, 222 insertions(+), 17 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 6627910..7a2128a 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -32,7 +32,7 @@ use PVE::QemuServer::Drive;
 use PVE::QemuServer::ImportDisk;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::Machine;
-use PVE::QemuServer::Memory qw(get_current_memory parse_memory 
get_host_max_mem);
+use PVE::QemuServer::Memory qw(get_current_memory parse_memory 
get_host_max_mem get_virtiomem_block_size);
 use PVE::QemuMigrate;
 use PVE::RPCEnvironment;
 use PVE::AccessControl;
@@ -485,6 +485,13 @@ my $check_memory_param = sub {
 die "memory max can't be bigger than supported cpu architecture 
$host_max_mem MiB\n"
if $mem->{max} && $mem->{max} > $host_max_mem;
 
+if ($mem->{virtio}) {
+   my $blocksize = get_virtiomem_block_size($conf);
+
+   die "memory need to be a multiple of $blocksize MiB when virtiomem is 
enabled\n"
+   if $mem->{current} % $blocksize != 0;
+}
+
 if ($param->{memory} || defined($param->{balloon})) {
 
my $memory = $param->{memory} || $conf->{pending}->{memory} || 
$conf->{memory};
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 3bd86da..a34ff3e 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -3866,7 +3866,12 @@ sub config_to_command {
push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, 
$machine_version, $winversion, $gpu_passthrough);
 }
 
-PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, 
$hotplug_features->{memory}, $cmd);
+my $mem_devices = {};
+PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, 
$hotplug_features->{memory}, $cmd, $mem_devices);
+foreach my $id (sort keys %$mem_devices) {
+   my $pciaddr = print_pci_addr($id, $bridges, $arch, $machine_type);
+   push @$devices, "-device", "$mem_devices->{$id}$pciaddr";
+}
 
 push @$cmd, '-S' if $conf->{freeze};
 
diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index 1b1c99d..bf4e92a 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -3,6 +3,8 @@ package PVE::QemuServer::Memory;
 use strict;
 use warnings;
 
+use POSIX qw(ceil);
+
 use PVE::JSONSchema;
 use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline 
dir_glob_foreach);
 use PVE::Exception qw(raise raise_param_exc);
@@ -16,6 +18,7 @@ our @EXPORT_OK = qw(
 get_current_memory
 parse_memory
 get_host_max_mem
+get_virtiomem_block_size
 );
 
 my $MAX_NUMA = 8;
@@ -37,6 +40,12 @@ our $memory_fmt = {
maximum => 4194304,
format => 'pve-qm-memory-max',
 },
+virtio => {
+   description => "Enable virtio-mem memory (Experimental: Only works with 
Linux guest with kernel >= 5.10)",
+   type => 'boolean',
+   optional => 1,
+   default => 0,
+},
 };
 
 PVE::JSONSchema::register_format('pve-qm-memory-max', \&verify_qm_memory_max);
@@ -72,7 +81,9 @@ my sub get_static_mem {
 my $static_memory = 0;
 my $memory = parse_memory($conf->{memory});
 
-if ($memory->{max}) {
+if ($memory->{virtio}) {
+   $static_memory = 4096;
+} elsif ($memory->{max}) {
my $dimm_size = $memory->{max} / $MAX_SLOTS;
#static mem can't be lower than 4G and lower than 1 dimmsize by socket
$static_memory = $dimm_size * $sockets;
@@ -161,6 +172,117 @@ sub get_current_memory {
 return $memory->{current};
 }
 
+sub get_virtiomem_block_size {
+my ($con

[pve-devel] [PATCH v4 qemu-server 16/16] tests: add virtio-mem tests

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 test/cfg2cmd/memory-virtio-hugepages-1G.conf  | 12 +++
 .../memory-virtio-hugepages-1G.conf.cmd   | 35 +++
 test/cfg2cmd/memory-virtio-max.conf   | 11 ++
 test/cfg2cmd/memory-virtio-max.conf.cmd   | 35 +++
 test/cfg2cmd/memory-virtio.conf   | 11 ++
 test/cfg2cmd/memory-virtio.conf.cmd   | 35 +++
 6 files changed, 139 insertions(+)
 create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf
 create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd
 create mode 100644 test/cfg2cmd/memory-virtio-max.conf
 create mode 100644 test/cfg2cmd/memory-virtio-max.conf.cmd
 create mode 100644 test/cfg2cmd/memory-virtio.conf
 create mode 100644 test/cfg2cmd/memory-virtio.conf.cmd

diff --git a/test/cfg2cmd/memory-virtio-hugepages-1G.conf 
b/test/cfg2cmd/memory-virtio-hugepages-1G.conf
new file mode 100644
index 000..bbe908c
--- /dev/null
+++ b/test/cfg2cmd/memory-virtio-hugepages-1G.conf
@@ -0,0 +1,12 @@
+# TEST: virtio-mem without memorymax defined and hugepages
+# QEMU_VERSION: 7.2
+cores: 2
+memory: 32768,virtio=1
+name: simple
+numa: 1
+ostype: l26
+smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465
+sockets: 2
+vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8
+hugepages: 1024
+hotplug: memory
\ No newline at end of file
diff --git a/test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd 
b/test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd
new file mode 100644
index 000..2e7de74
--- /dev/null
+++ b/test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd
@@ -0,0 +1,35 @@
+/usr/bin/kvm \
+  -id 8006 \
+  -name 'simple,debug-threads=on' \
+  -no-shutdown \
+  -chardev 
'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \
+  -mon 'chardev=qmp,mode=control' \
+  -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \
+  -mon 'chardev=qmp-event,mode=control' \
+  -pidfile /var/run/qemu-server/8006.pid \
+  -daemonize \
+  -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \
+  -smp '4,sockets=2,cores=2,maxcpus=4' \
+  -nodefaults \
+  -boot 
'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg'
 \
+  -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \
+  -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \
+  -m 'size=4096,maxmem=524288M' \
+  -object 
'memory-backend-file,id=ram-node0,size=2048M,mem-path=/run/hugepages/kvm/1048576kB,share=on'
 \
+  -numa 'node,nodeid=0,cpus=0-1,memdev=ram-node0' \
+  -object 
'memory-backend-file,id=ram-node1,size=2048M,mem-path=/run/hugepages/kvm/1048576kB,share=on'
 \
+  -numa 'node,nodeid=1,cpus=2-3,memdev=ram-node1' \
+  -object 
'memory-backend-file,id=mem-virtiomem0,size=260096M,mem-path=/run/hugepages/kvm/1048576kB,share=on,reserve=off'
 \
+  -object 
'memory-backend-file,id=mem-virtiomem1,size=260096M,mem-path=/run/hugepages/kvm/1048576kB,share=on,reserve=off'
 \
+  -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \
+  -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \
+  -device 'pci-bridge,id=pci.4,chassis_nr=4,bus=pci.1,addr=0x1c' \
+  -device 'vmgenid,guid=c773c261-d800-4348-9f5d-167fadd53cf8' \
+  -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \
+  -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \
+  -device 'VGA,id=vga,bus=pci.0,addr=0x2' \
+  -device 
'virtio-mem-pci,block-size=32M,requested-size=14336M,id=virtiomem0,memdev=mem-virtiomem0,node=0,prealloc=on,bus=pci.4,addr=0x4'
 \
+  -device 
'virtio-mem-pci,block-size=32M,requested-size=14336M,id=virtiomem1,memdev=mem-virtiomem1,node=1,prealloc=on,bus=pci.4,addr=0x5'
 \
+  -device 
'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \
+  -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
+  -machine 'type=pc+pve0'
\ No newline at end of file
diff --git a/test/cfg2cmd/memory-virtio-max.conf 
b/test/cfg2cmd/memory-virtio-max.conf
new file mode 100644
index 000..59b8e94
--- /dev/null
+++ b/test/cfg2cmd/memory-virtio-max.conf
@@ -0,0 +1,11 @@
+# TEST: memory max 64G with 2 socket with virtio-mem
+# QEMU_VERSION: 7.2
+cores: 2
+memory: 32768,max=65536,virtio=1
+name: simple
+numa: 1
+ostype: l26
+smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465
+sockets: 2
+vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8
+hotplug: memory
\ No newline at end of file
diff --git a/test/cfg2cmd/memory-virtio-max.conf.cmd 
b/test/cfg2cmd/memory-virtio-max.conf.cmd
new file mode 100644
index 000..6bda268
--- /dev/null
+++ b/test/cfg2cmd/memory-virtio-max.conf.cmd
@@ -0,0 +1,35 @@
+/usr/bin/kvm \
+  -id 8006 \
+  -name 'simple,debug-threads=on' \
+  -no-shutdown \
+  -chardev 
'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \
+  -mon 'chardev=qmp,mode=control' \
+  -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \
+  -mon 'chardev=qmp-event,mode=control' \
+  -pidfile /var/run/qemu-server/8006.pid \

[pve-devel] [PATCH v4 qemu-server 06/16] memory: add get_static_mem

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 37 +++--
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index 09fa25c..5dc2cb8 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -15,7 +15,6 @@ get_current_memory
 );
 
 my $MAX_NUMA = 8;
-my $STATICMEM = 1024;
 
 our $memory_fmt = {
 current => {
@@ -44,6 +43,22 @@ sub parse_memory {
 return $res;
 }
 
+my sub get_static_mem {
+my ($conf, $sockets, $hotplug) = @_;
+
+my $static_memory = 0;
+my $memory = parse_memory($conf->{memory});
+
+if ($hotplug) {
+   $static_memory = 1024;
+   $static_memory = $static_memory * $sockets if ($conf->{hugepages} && 
$conf->{hugepages} == 1024);
+} else {
+   $static_memory = $memory->{current};
+}
+
+return $static_memory;
+}
+
 my $_host_bits;
 sub get_host_phys_address_bits {
 return $_host_bits if defined($_host_bits);
@@ -213,8 +228,7 @@ sub qemu_memory_hotplug {
 $value = $newmem->{current};
 
 my $sockets = $conf->{sockets} || 1;
-my $static_memory = $STATICMEM;
-$static_memory = $static_memory * $sockets if ($conf->{hugepages} && 
$conf->{hugepages} == 1024);
+my $static_memory = get_static_mem($conf, $sockets, 1);
 
 die "memory can't be lower than $static_memory MB" if $value < 
$static_memory;
 my $MAX_MEM = get_max_mem($conf);
@@ -322,7 +336,7 @@ sub config {
 my ($conf, $vmid, $sockets, $cores, $hotplug, $cmd) = @_;
 
 my $memory = get_current_memory($conf->{memory});
-my $static_memory = 0;
+my $static_memory = get_static_mem($conf, $sockets, $hotplug);
 
 if ($hotplug) {
die "NUMA needs to be enabled for memory hotplug\n" if !$conf->{numa};
@@ -334,17 +348,11 @@ sub config {
if $conf->{"numa$i"};
}
 
-   my $sockets = $conf->{sockets} || 1;
-
-   $static_memory = $STATICMEM;
-   $static_memory = $static_memory * $sockets if ($conf->{hugepages} && 
$conf->{hugepages} == 1024);
-
die "minimum memory must be ${static_memory}MB\n" if($memory < 
$static_memory);
push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M";
 
 } else {
 
-   $static_memory = $memory;
push @$cmd, '-m', $static_memory;
 }
 
@@ -541,17 +549,10 @@ sub hugepages_topology {
 return if !$conf->{numa};
 
 my $memory = get_current_memory($conf->{memory});
-my $static_memory = 0;
 my $sockets = $conf->{sockets} || 1;
+my $static_memory = get_static_mem($conf, $sockets, $hotplug);
 my $numa_custom_topology = undef;
 
-if ($hotplug) {
-   $static_memory = $STATICMEM;
-   $static_memory = $static_memory * $sockets if ($conf->{hugepages} && 
$conf->{hugepages} == 1024);
-} else {
-   $static_memory = $memory;
-}
-
 #custom numa topology
 for (my $i = 0; $i < $MAX_NUMA; $i++) {
next if !$conf->{"numa$i"};
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 10/16] memory: rename qemu_dimm_list to qemu_memdevices_list

2023-02-13 Thread Alexandre Derumier
current qemu_dimm_list can return any kind of memory devices.

make it more generic, with a regex filter to choose kind of device
from id.

Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index c912e4f..a13b3a1 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -333,7 +333,7 @@ sub qemu_memory_hotplug {
while (1) {
eval { PVE::QemuServer::qemu_devicedel($vmid, $name) };
sleep 3;
-   my $dimm_list = qemu_dimm_list($vmid);
+   my $dimm_list = qemu_memdevices_list($vmid, '^dimm(\d+)$');
last if !$dimm_list->{$name};
raise_param_exc({ $name => "error unplug memory module" }) 
if $retry > 5;
$retry++;
@@ -363,14 +363,14 @@ sub can_hotplug {
 return 1;
 }
 
-sub qemu_dimm_list {
-my ($vmid) = @_;
+sub qemu_memdevices_list {
+my ($vmid, $filter) = @_;
 
 my $dimmarray = mon_cmd($vmid, "query-memory-devices");
 my $dimms = {};
 
 foreach my $dimm (@$dimmarray) {
-
+next if $filter && $dimm->{data}->{id} !~ /$filter/;
 $dimms->{$dimm->{data}->{id}}->{id} = $dimm->{data}->{id};
 $dimms->{$dimm->{data}->{id}}->{node} = $dimm->{data}->{node};
 $dimms->{$dimm->{data}->{id}}->{addr} = $dimm->{data}->{addr};
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 07/16] memory: use static_memory in foreach_dimm

2023-02-13 Thread Alexandre Derumier
Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 12 +---
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index 5dc2cb8..32fbdc5 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -151,17 +151,15 @@ sub get_numa_guest_to_host_map {
 }
 
 sub foreach_dimm{
-my ($conf, $vmid, $memory, $sockets, $func) = @_;
+my ($conf, $vmid, $memory, $static_memory, $func) = @_;
 
 my $dimm_id = 0;
-my $current_size = 0;
+my $current_size = $static_memory;
 my $dimm_size = 0;
 
 if($conf->{hugepages} && $conf->{hugepages} == 1024) {
-   $current_size = 1024 * $sockets;
$dimm_size = 1024;
 } else {
-   $current_size = 1024;
$dimm_size = 512;
 }
 
@@ -238,7 +236,7 @@ sub qemu_memory_hotplug {
 
my $numa_hostmap;
 
-   foreach_dimm($conf, $vmid, $value, $sockets, sub {
+   foreach_dimm($conf, $vmid, $value, $static_memory, sub {
my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, 
$memory) = @_;
 
return if $current_size <= get_current_memory($conf->{memory});
@@ -420,7 +418,7 @@ sub config {
 }
 
 if ($hotplug) {
-   foreach_dimm($conf, $vmid, $memory, $sockets, sub {
+   foreach_dimm($conf, $vmid, $memory, $static_memory, sub {
my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, 
$memory) = @_;
 
my $mem_object = print_mem_object($conf, "mem-$name", $dimm_size);
@@ -585,7 +583,7 @@ sub hugepages_topology {
 if ($hotplug) {
my $numa_hostmap = get_numa_guest_to_host_map($conf);
 
-   foreach_dimm($conf, undef, $memory, $sockets, sub {
+   foreach_dimm($conf, undef, $memory, $static_memory, sub {
my ($conf, undef, $name, $dimm_size, $numanode, $current_size, 
$memory) = @_;
 
$numanode = $numa_hostmap->{$numanode};
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 12/16] memory: use 64 slots && static dimm size when max is defined

2023-02-13 Thread Alexandre Derumier
default kernel vhost config only support 64 slots by default,
for performance since 2015.

Original memory hotplug code was done before, using qemu
max supported 255 slots.

To reach max mem (4TB), we used incremental dimm size.

Instead of dynamic memory size, use 1 static dimm size, compute
from max memory/64.

We also force a static memory to 4GB, as memory under 4G don't
works fine with unplug

Fix:
https://bugzilla.proxmox.com/show_bug.cgi?id=3446
https://bugzilla.proxmox.com/show_bug.cgi?id=1426
Signed-off-by: Alexandre Derumier 
---
 PVE/QemuServer/Memory.pm | 20 
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index cf1ddb9..1b1c99d 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -19,6 +19,7 @@ get_host_max_mem
 );
 
 my $MAX_NUMA = 8;
+my $MAX_SLOTS = 64;
 
 our $memory_fmt = {
 current => {
@@ -71,7 +72,13 @@ my sub get_static_mem {
 my $static_memory = 0;
 my $memory = parse_memory($conf->{memory});
 
-if ($hotplug) {
+if ($memory->{max}) {
+   my $dimm_size = $memory->{max} / $MAX_SLOTS;
+   #static mem can't be lower than 4G and lower than 1 dimmsize by socket
+   $static_memory = $dimm_size * $sockets;
+   $static_memory = 4096 if $static_memory < 4096;
+} elsif ($hotplug) {
+   #legacy
$static_memory = 1024;
$static_memory = $static_memory * $sockets if ($conf->{hugepages} && 
$conf->{hugepages} == 1024);
 } else {
@@ -194,7 +201,10 @@ sub foreach_dimm{
 my $current_size = $static_memory;
 my $dimm_size = 0;
 
-if($conf->{hugepages} && $conf->{hugepages} == 1024) {
+my $confmem = parse_memory($conf->{memory});
+if ($confmem->{max}) {
+   $dimm_size = $confmem->{max} / $MAX_SLOTS;
+} elsif($conf->{hugepages} && $conf->{hugepages} == 1024) {
$dimm_size = 1024;
 } else {
$dimm_size = 512;
@@ -213,7 +223,7 @@ sub foreach_dimm{
&$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, 
$memory);
return  $current_size if $current_size >= $memory;
}
-   $dimm_size *= 2;
+   $dimm_size *= 2 if !$confmem->{max};
 }
 }
 
@@ -368,7 +378,9 @@ sub config {
}
 
die "minimum memory must be ${static_memory}MB\n" if($memory < 
$static_memory);
-   push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M";
+   my $confmem = parse_memory($conf->{memory});
+   my $slots = $confmem->{max} ? $MAX_SLOTS : 255;
+   push @$cmd, '-m', 
"size=${static_memory},slots=$slots,maxmem=${MAX_MEM}M";
 
 } else {
 
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH v4 qemu-server 09/16] memory: get_max_mem: use config memory max

2023-02-13 Thread Alexandre Derumier
verify than defined vm memorymax is not bigger than
host cpu supported memory

Add add early check in update vm api

Signed-off-by: Alexandre Derumier 
---
 PVE/API2/Qemu.pm | 32 ++--
 PVE/QemuServer/Memory.pm | 19 ++-
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 9b80da1..6627910 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -32,7 +32,7 @@ use PVE::QemuServer::Drive;
 use PVE::QemuServer::ImportDisk;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::Machine;
-use PVE::QemuServer::Memory qw(get_current_memory);
+use PVE::QemuServer::Memory qw(get_current_memory parse_memory 
get_host_max_mem);
 use PVE::QemuMigrate;
 use PVE::RPCEnvironment;
 use PVE::AccessControl;
@@ -476,6 +476,26 @@ my $create_disks = sub {
 return ($vollist, $res);
 };
 
+my $check_memory_param = sub {
+my ($conf, $param) = @_;
+
+my $mem = parse_memory($param->{memory});
+my $host_max_mem = get_host_max_mem($conf);
+
+die "memory max can't be bigger than supported cpu architecture 
$host_max_mem MiB\n"
+   if $mem->{max} && $mem->{max} > $host_max_mem;
+
+if ($param->{memory} || defined($param->{balloon})) {
+
+   my $memory = $param->{memory} || $conf->{pending}->{memory} || 
$conf->{memory};
+   my $maxmem = get_current_memory($memory);
+   my $balloon = defined($param->{balloon}) ? $param->{balloon} : 
$conf->{pending}->{balloon} || $conf->{balloon};
+
+   die "balloon value too large (must be smaller than assigned memory)\n"
+   if $balloon && $balloon > $maxmem;
+}
+};
+
 my $check_cpu_model_access = sub {
 my ($rpcenv, $authuser, $new, $existing) = @_;
 
@@ -1606,15 +1626,7 @@ my $update_vm_api  = sub {
}
}
 
-   if ($param->{memory} || defined($param->{balloon})) {
-
-   my $memory = $param->{memory} || $conf->{pending}->{memory} || 
$conf->{memory};
-   my $maxmem = get_current_memory($memory);
-   my $balloon = defined($param->{balloon}) ? $param->{balloon} : 
$conf->{pending}->{balloon} || $conf->{balloon};
-
-   die "balloon value too large (must be smaller than assigned 
memory)\n"
-   if $balloon && $balloon > $maxmem;
-   }
+   &$check_memory_param($conf, $param);
 
PVE::Cluster::log_msg('info', $authuser, "update VM $vmid: " . join (' 
', @paramarr));
 
diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index deeb88f..c912e4f 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -14,6 +14,8 @@ use base qw(Exporter);
 
 our @EXPORT_OK = qw(
 get_current_memory
+parse_memory
+get_host_max_mem
 );
 
 my $MAX_NUMA = 8;
@@ -96,7 +98,7 @@ sub get_host_phys_address_bits {
 return; # undef, cannot really do anything..
 }
 
-my sub get_max_mem {
+sub get_host_max_mem {
 my ($conf) = @_;
 
 my $cpu = {};
@@ -130,6 +132,21 @@ my sub get_max_mem {
 return $bits_to_max_mem > 4*1024*1024 ? 4*1024*1024 : $bits_to_max_mem;
 }
 
+my sub get_max_mem {
+my ($conf) = @_;
+
+my $host_max_mem = get_host_max_mem($conf);
+my $mem = parse_memory($conf->{memory});
+
+if ($mem->{max}) {
+   die "configured memory max can't be bigger than supported cpu 
architecture $host_max_mem MiB\n"
+   if $mem->{max} > $host_max_mem;
+   return $mem->{max};
+}
+
+return $host_max_mem;
+}
+
 sub get_current_memory {
 my ($value) = @_;
 
-- 
2.30.2


___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH manager 2/2] lxc: Add `Disconnect` option for network interfaces

2023-02-13 Thread Christoph Heiss
Signed-off-by: Christoph Heiss 
---
 www/manager6/Parser.js  |  3 +++
 www/manager6/lxc/Network.js | 13 +
 2 files changed, 16 insertions(+)

diff --git a/www/manager6/Parser.js b/www/manager6/Parser.js
index 9f7b2c84..c3772d3b 100644
--- a/www/manager6/Parser.js
+++ b/www/manager6/Parser.js
@@ -298,6 +298,8 @@ Ext.define('PVE.Parser', {
data[match_res[1]] = match_res[2];
} else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
data.firewall = PVE.Parser.parseBoolean(match_res[1]);
+   } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
+   data.link_down = PVE.Parser.parseBoolean(match_res[1]);
} else if (!p.match(/^type=\S+$/)) {
console.warn(`could not parse LXC network string ${p}`);
}
@@ -319,6 +321,7 @@ Ext.define('PVE.Parser', {
name: 1,
rate: 1,
tag: 1,
+   link_down: 1,
};
return Object.entries(config)
.filter(([k, v]) => v !== undefined && v !== '' && knownKeys[k])
diff --git a/www/manager6/lxc/Network.js b/www/manager6/lxc/Network.js
index 85033bd8..746924b3 100644
--- a/www/manager6/lxc/Network.js
+++ b/www/manager6/lxc/Network.js
@@ -282,6 +282,12 @@ Ext.define('PVE.lxc.NetworkInputPanel', {
minValue: 576,
maxValue: 65535,
},
+   {
+   xtype: 'proxmoxcheckbox',
+   fieldLabel: gettext('Disconnect'),
+   name: 'link_down',
+   value: cdata.link_down,
+   },
];

me.advancedColumn2 = [
@@ -539,6 +545,12 @@ Ext.define('PVE.lxc.NetworkView', {
width: 80,
dataIndex: 'mtu',
},
+   {
+   header: gettext('Disconnected'),
+   width: 100,
+   dataIndex: 'link_down',
+   renderer: Proxmox.Utils.format_boolean,
+   },
],
listeners: {
activate: me.load,
@@ -564,6 +576,7 @@ Ext.define('PVE.lxc.NetworkView', {
'tag',
'firewall',
'mtu',
+   'link_down',
],
 });
 });
--
2.39.1



___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH container 1/2] net: Add `link_down` config to allow setting interfaces as disconnected

2023-02-13 Thread Christoph Heiss
If this network option is set, the host-side link will be forced down.
This has the effect that the interface inside the container has
LOWERLAYERDOWN set, which basically means that the PHY is considered
down, thus effectivly being "unplugged".

Also fix some trailing whitespace while touching the file.

Signed-off-by: Christoph Heiss 
---
 src/PVE/LXC.pm| 20 +---
 src/PVE/LXC/Config.pm |  5 +
 src/lxcnetaddbr   |  3 ++-
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index ce6d5a5..039a476 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -668,7 +668,7 @@ sub update_lxc_config {

 # some init scripts expect a linux terminal (turnkey).
 $raw .= "lxc.environment = TERM=linux\n";
-
+
 my $utsname = $conf->{hostname} || "CT$vmid";
 $raw .= "lxc.uts.name = $utsname\n";

@@ -932,8 +932,9 @@ sub update_net {
my $oldnet = PVE::LXC::Config->parse_lxc_network($oldnetcfg);

if (safe_string_ne($oldnet->{hwaddr}, $newnet->{hwaddr}) ||
-   safe_string_ne($oldnet->{name}, $newnet->{name})) {
-
+   safe_string_ne($oldnet->{name}, $newnet->{name}) ||
+   defined($oldnet->{link_down}) != defined($newnet->{link_down})
+   ) {
PVE::Network::veth_delete($veth);
delete $conf->{$opt};
PVE::LXC::Config->write_config($vmid, $conf);
@@ -1010,6 +1011,11 @@ sub hotplug_net {
 $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 
'link', 'set', $eth ,'up'  ];
 PVE::Tools::run_command($cmd);

+# In case the network device should be disconnected, force the host-link 
down
+if (defined($newnet->{link_down})) {
+   PVE::Tools::run_command(['/sbin/ip', 'link', 'set', 'dev', $veth, 
'down']);
+}
+
 my $done = { type => 'veth' };
 foreach (qw(bridge tag firewall hwaddr name)) {
$done->{$_} = $newnet->{$_} if $newnet->{$_};
@@ -1703,14 +1709,14 @@ sub __mountpoint_mount {
 my $type = $mountpoint->{type};
 my $quota = !$snapname && !$mountpoint->{ro} && $mountpoint->{quota};
 my $mounted_dev;
-
+
 return if !$volid || !$mount;

 $mount =~ s!/+!/!g;

 my $mount_path;
 my ($mpfd, $parentfd, $last_dir);
-
+
 if (defined($rootdir)) {
($rootdir, $mount_path, $mpfd, $parentfd, $last_dir) =
__mount_prepare_rootdir($rootdir, $mount, $rootuid, $rootgid);
@@ -1719,7 +1725,7 @@ sub __mountpoint_mount {
 if (defined($stage_mount)) {
$mount_path = $rootdir;
 }
-
+
 my ($storage, $volname) = PVE::Storage::parse_volume_id($volid, 1);

 die "unknown snapshot path for '$volid'" if !$storage && 
defined($snapname);
@@ -1828,7 +1834,7 @@ sub __mountpoint_mount {
warn "cannot enable quota control for bind mounts\n" if $quota;
return wantarray ? ($volid, 0, undef) : $volid;
 }
-
+
 die "unsupported storage";
 }

diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
index af25a96..1d4362e 100644
--- a/src/PVE/LXC/Config.pm
+++ b/src/PVE/LXC/Config.pm
@@ -814,6 +814,11 @@ our $netconf_desc = {
description => "Apply rate limiting to the interface",
optional => 1,
 },
+link_down => {
+   type => 'boolean',
+   description => 'Whether this interface should be disconnected (like 
pulling the plug).',
+   optional => 1,
+},
 };
 PVE::JSONSchema::register_format('pve-lxc-network', $netconf_desc);

diff --git a/src/lxcnetaddbr b/src/lxcnetaddbr
index 83052e1..d8c6767 100755
--- a/src/lxcnetaddbr
+++ b/src/lxcnetaddbr
@@ -58,7 +58,8 @@ if (-d "/sys/class/net/$iface") {
 #avoid insecure dependency;
 ($bridgemtu) = $bridgemtu =~ /(\d+)/;

-PVE::Tools::run_command("/sbin/ip link set dev $iface up mtu $bridgemtu");
+my $linkstate = defined($net->{link_down}) ? 'down' : 'up';
+PVE::Tools::run_command("/sbin/ip link set dev $iface $linkstate mtu 
$bridgemtu");
 PVE::Tools::run_command("/sbin/ip addr add 0.0.0.0/0 dev $iface");

 if ($have_sdn) {
--
2.39.1



___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



[pve-devel] [PATCH container/manager 0/2] fix #3413: Add `Disconnect` option for LXC networks

2023-02-13 Thread Christoph Heiss
This adds a `Disconnect` option for network interfaces on LXC
containers, much like it already exists for VMs. This has been requested
in #3413 [0] and seems useful, esp. considering we already support the
same thing for VMs.

One thing to note is that LXC does not seem to support the notion of
setting an interface down. The `flags` property would suggest that this
possible [1], but AFAICS it does not work. I tried setting the value as
empty and to something else than "up" (since that is really the only
supported option [2][3]), which both had absolutely no effect.

The solution was to force the host-side link of the container network
down, thus effectively becoming "physically" disconnected.

[0] https://bugzilla.proxmox.com/show_bug.cgi?id=3413
[1] https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html#lbAO
[2] https://github.com/lxc/lxc/blob/08f0e769/src/lxc/confile.c#L453-L467
[3] https://github.com/lxc/lxc/blob/08f0e769/src/lxc/confile.c#L5933-L5952

pve-container:

Christoph Heiss (1):
  net: Add `link_down` config to allow setting interfaces as disconnected

 src/PVE/LXC.pm| 20 +---
 src/PVE/LXC/Config.pm |  5 +
 src/lxcnetaddbr   |  3 ++-
 3 files changed, 20 insertions(+), 8 deletions(-)

pve-manager:

Christoph Heiss (1):
  lxc: Add `Disconnect` option for network interfaces

 www/manager6/Parser.js  |  3 +++
 www/manager6/lxc/Network.js | 13 +
 2 files changed, 16 insertions(+)

--
2.39.1



___
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



Re: [pve-devel] [PATCH container 1/2] net: Add `link_down` config to allow setting interfaces as disconnected

2023-02-13 Thread Wolfgang Bumiller
On Mon, Feb 13, 2023 at 02:56:59PM +0100, Christoph Heiss wrote:
> If this network option is set, the host-side link will be forced down.
> This has the effect that the interface inside the container has
> LOWERLAYERDOWN set, which basically means that the PHY is considered
> down, thus effectivly being "unplugged".
> 
> Also fix some trailing whitespace while touching the file.
> 
> Signed-off-by: Christoph Heiss 
> ---
>  src/PVE/LXC.pm| 20 +---
>  src/PVE/LXC/Config.pm |  5 +
>  src/lxcnetaddbr   |  3 ++-
>  3 files changed, 20 insertions(+), 8 deletions(-)
> 
> diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
> index ce6d5a5..039a476 100644
> --- a/src/PVE/LXC.pm
> +++ b/src/PVE/LXC.pm
> @@ -668,7 +668,7 @@ sub update_lxc_config {
> 
>  # some init scripts expect a linux terminal (turnkey).
>  $raw .= "lxc.environment = TERM=linux\n";
> -
> +
>  my $utsname = $conf->{hostname} || "CT$vmid";
>  $raw .= "lxc.uts.name = $utsname\n";
> 
> @@ -932,8 +932,9 @@ sub update_net {
>   my $oldnet = PVE::LXC::Config->parse_lxc_network($oldnetcfg);
> 
>   if (safe_string_ne($oldnet->{hwaddr}, $newnet->{hwaddr}) ||
> - safe_string_ne($oldnet->{name}, $newnet->{name})) {
> -
> + safe_string_ne($oldnet->{name}, $newnet->{name}) ||
> + defined($oldnet->{link_down}) != defined($newnet->{link_down})

Doing this here would cause the interface to be deleted and recreated in
a "down" state, which is much more disruptive than it needs to be.
Instead, this should be treated more like we do changing the 'bridge'
property (the 'else' case just below this), and stop after the
`tap_unplug` for the 'down' case.

> + ) {
>   PVE::Network::veth_delete($veth);
>   delete $conf->{$opt};
>   PVE::LXC::Config->write_config($vmid, $conf);
> @@ -1010,6 +1011,11 @@ sub hotplug_net {
>  $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 
> 'link', 'set', $eth ,'up'  ];
>  PVE::Tools::run_command($cmd);
> 
> +# In case the network device should be disconnected, force the host-link 
> down
> +if (defined($newnet->{link_down})) {
> + PVE::Tools::run_command(['/sbin/ip', 'link', 'set', 'dev', $veth, 
> 'down']);

These interfaces are usually part of a bridge, and therefore the next
`ifreload` (and probably some other things) would re-enable them
automatically.

We do need to actually "unplug" them from the bridge (tap_unplug) to
avoid this.

> +}
> +
>  my $done = { type => 'veth' };
>  foreach (qw(bridge tag firewall hwaddr name)) {
>   $done->{$_} = $newnet->{$_} if $newnet->{$_};
> @@ -1703,14 +1709,14 @@ sub __mountpoint_mount {
>  my $type = $mountpoint->{type};
>  my $quota = !$snapname && !$mountpoint->{ro} && $mountpoint->{quota};
>  my $mounted_dev;
> -
> +
>  return if !$volid || !$mount;
> 
>  $mount =~ s!/+!/!g;
> 
>  my $mount_path;
>  my ($mpfd, $parentfd, $last_dir);
> -
> +
>  if (defined($rootdir)) {
>   ($rootdir, $mount_path, $mpfd, $parentfd, $last_dir) =
>   __mount_prepare_rootdir($rootdir, $mount, $rootuid, $rootgid);
> @@ -1719,7 +1725,7 @@ sub __mountpoint_mount {
>  if (defined($stage_mount)) {
>   $mount_path = $rootdir;
>  }
> -
> +
>  my ($storage, $volname) = PVE::Storage::parse_volume_id($volid, 1);
> 
>  die "unknown snapshot path for '$volid'" if !$storage && 
> defined($snapname);
> @@ -1828,7 +1834,7 @@ sub __mountpoint_mount {
>   warn "cannot enable quota control for bind mounts\n" if $quota;
>   return wantarray ? ($volid, 0, undef) : $volid;
>  }
> -
> +
>  die "unsupported storage";
>  }
> 
> diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
> index af25a96..1d4362e 100644
> --- a/src/PVE/LXC/Config.pm
> +++ b/src/PVE/LXC/Config.pm
> @@ -814,6 +814,11 @@ our $netconf_desc = {
>   description => "Apply rate limiting to the interface",
>   optional => 1,
>  },
> +link_down => {
> + type => 'boolean',
> + description => 'Whether this interface should be disconnected (like 
> pulling the plug).',
> + optional => 1,
> +},
>  };
>  PVE::JSONSchema::register_format('pve-lxc-network', $netconf_desc);
> 
> diff --git a/src/lxcnetaddbr b/src/lxcnetaddbr
> index 83052e1..d8c6767 100755
> --- a/src/lxcnetaddbr
> +++ b/src/lxcnetaddbr
> @@ -58,7 +58,8 @@ if (-d "/sys/class/net/$iface") {
>  #avoid insecure dependency;
>  ($bridgemtu) = $bridgemtu =~ /(\d+)/;
> 
> -PVE::Tools::run_command("/sbin/ip link set dev $iface up mtu 
> $bridgemtu");
> +my $linkstate = defined($net->{link_down}) ? 'down' : 'up';

We need to skip the rest altogether if the link is supposed to stay down
reliably. As mentioned above, a 'down' interface that is still plugged
into a bridge will get activated sooner or later...

> +PVE::Tools::run_command("/sbin/ip link set dev $iface $linkstate mtu 
> $bridgemtu");
>  PVE::Tools::run_command("/sbin/ip