]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXC/Config.pm
config: implement method to calculate derived properties from a config
[pve-container.git] / src / PVE / LXC / Config.pm
index 23c1ba7452fe53aab59f795d3ec53c024b88033e..2dd57e2b630a318514872183d6f3a16da0163b66 100644 (file)
@@ -2,6 +2,7 @@ package PVE::LXC::Config;
 
 use strict;
 use warnings;
+
 use Fcntl qw(O_RDONLY);
 
 use PVE::AbstractConfig;
@@ -12,10 +13,14 @@ use PVE::INotify;
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::Tools;
 
+use PVE::LXC;
+
 use base qw(PVE::AbstractConfig);
 
-use constant {FIFREEZE => 0xc0045877,
-              FITHAW   => 0xc0045878};
+use constant {
+    FIFREEZE => 0xc0045877,
+    FITHAW   => 0xc0045878,
+};
 
 my $nodename = PVE::INotify::nodename();
 my $lock_handles =  {};
@@ -87,10 +92,8 @@ sub has_feature {
        return if $err; # skip further test
        return if $backup_only && !$class->mountpoint_backup_enabled($ms, $mountpoint);
 
-       $err = 1
-           if !PVE::Storage::volume_has_feature($storecfg, $feature,
-                                                $mountpoint->{volume},
-                                                $snapname, $running, $opts);
+       $err = 1 if !PVE::Storage::volume_has_feature(
+           $storecfg, $feature, $mountpoint->{volume}, $snapname, $running, $opts);
     });
 
     return $err ? 0 : 1;
@@ -443,13 +446,13 @@ my $confdesc = {
     lock => {
        optional => 1,
        type => 'string',
-       description => "Lock/unlock the VM.",
+       description => "Lock/unlock the container.",
        enum => [qw(backup create destroyed disk fstrim migrate mounted rollback snapshot snapshot-delete)],
     },
     onboot => {
        optional => 1,
        type => 'boolean',
-       description => "Specifies whether a VM will be started during system bootup.",
+       description => "Specifies whether a container will be started during system bootup.",
        default => 0,
     },
     startup => get_standard_option('pve-startup-order'),
@@ -462,7 +465,7 @@ my $confdesc = {
     arch => {
        optional => 1,
        type => 'string',
-       enum => ['amd64', 'i386', 'arm64', 'armhf'],
+       enum => ['amd64', 'i386', 'arm64', 'armhf', 'riscv32', 'riscv64'],
        description => "OS architecture type.",
        default => 'amd64',
     },
@@ -504,22 +507,25 @@ my $confdesc = {
     cpuunits => {
        optional => 1,
        type => 'integer',
-       description => "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to the weights of all the other running VMs.\n\nNOTE: You can disable fair-scheduler configuration by setting this to 0.",
+       description => "CPU weight for a container, will be clamped to [1, 10000] in cgroup v2.",
+       verbose_description => "CPU weight for a container. Argument is used in the kernel fair "
+           ."scheduler. The larger the number is, the more CPU time this container gets. Number "
+           ."is relative to the weights of all the other running guests.",
        minimum => 0,
        maximum => 500000,
-       default => 1024,
+       default => 'cgroup v1: 1024, cgroup v2: 100',
     },
     memory => {
        optional => 1,
        type => 'integer',
-       description => "Amount of RAM for the VM in MB.",
+       description => "Amount of RAM for the container in MB.",
        minimum => 16,
        default => 512,
     },
     swap => {
        optional => 1,
        type => 'integer',
-       description => "Amount of SWAP for the VM in MB.",
+       description => "Amount of SWAP for the container in MB.",
        minimum => 0,
        default => 512,
     },
@@ -752,6 +758,7 @@ our $netconf_desc = {
        type => 'integer',
        description => 'Maximum transfer unit of the interface. (lxc.network.mtu)',
        minimum => 64, # minimum ethernet frame is 64 bytes
+       maximum => 65535,
        optional => 1,
     },
     ip => {
@@ -807,6 +814,12 @@ our $netconf_desc = {
        description => "Apply rate limiting to the interface",
        optional => 1,
     },
+    # TODO: Rename this option and the qemu-server one to `link-down` for PVE 8.0
+    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);
 
@@ -1107,6 +1120,16 @@ sub update_pct_config {
            $value = PVE::LXC::verify_searchdomain_list($value);
        } elsif ($opt eq 'unprivileged') {
            die "unable to modify read-only option: '$opt'\n";
+       } elsif ($opt eq 'tags') {
+           $value = PVE::GuestHelpers::get_unique_tags($value);
+       } elsif ($opt =~ m/^net(\d+)$/) {
+           my $res = PVE::JSONSchema::parse_property_string($netconf_desc, $value);
+
+           if (my $mtu = $res->{mtu}) {
+               my $bridge_mtu = PVE::Network::read_bridge_mtu($res->{bridge});
+               die "$opt: MTU size '$mtu' is bigger than bridge MTU '$bridge_mtu'\n"
+                   if ($mtu > $bridge_mtu);
+           }
        }
        $conf->{pending}->{$opt} = $value;
        $class->remove_from_pending_delete($conf, $opt);
@@ -1254,11 +1277,9 @@ sub print_lxc_network {
 sub parse_lxc_network {
     my ($class, $data) = @_;
 
-    my $res = {};
-
-    return $res if !$data;
+    return {} if !$data;
 
-    $res = PVE::JSONSchema::parse_property_string($netconf_desc, $data);
+    my $res = PVE::JSONSchema::parse_property_string($netconf_desc, $data);
 
     $res->{type} = 'veth';
     if (!$res->{hwaddr}) {
@@ -1282,6 +1303,22 @@ sub option_exists {
 }
 # END JSON config code
 
+# takes a max memory value as KiB and returns an tuple with max and high values
+sub calculate_memory_constraints {
+    my ($memory) = @_;
+
+    return if !defined($memory);
+
+    # cgroup memory usage is limited by the hard 'max' limit (OOM-killer enforced) and the soft
+    # 'high' limit (cgroup processes get throttled and put under heavy reclaim pressure).
+    my $memory_max = int($memory * 1024 * 1024);
+    # Set the high to 1016/1024 (~99.2%) of the 'max' hard limit clamped to 128 MiB max, to scale
+    # it for the lower range while having a decent 2^x based rest for 2^y memory configs.
+    my $memory_high = $memory >= 16 * 1024 ? int(($memory - 128) * 1024 * 1024) : int($memory * 1024 * 1016);
+
+    return ($memory_max, $memory_high);
+}
+
 my $LXC_FASTPLUG_OPTIONS= {
     'description' => 1,
     'onboot' => 1,
@@ -1318,11 +1355,11 @@ sub vmconfig_hotplug_pending {
     # memory (iow. memory+swap). This means we have to change them together.
     my $hotplug_memory_done;
     my $hotplug_memory = sub {
-       my ($wanted_memory, $wanted_swap) = @_;
+       my ($new_memory, $new_swap) = @_;
 
-       $wanted_memory = int($wanted_memory * 1024 * 1024) if defined($wanted_memory);
-       $wanted_swap = int($wanted_swap * 1024 * 1024) if defined($wanted_swap);
-       $cgroup->change_memory_limit($wanted_memory, $wanted_swap);
+       ($new_memory, my $new_memory_high) = calculate_memory_constraints($new_memory);
+       $new_swap = int($new_swap * 1024 * 1024) if defined($new_swap);
+       $cgroup->change_memory_limit($new_memory, $new_swap, $new_memory_high);
 
        $hotplug_memory_done = 1;
     };
@@ -1342,7 +1379,7 @@ sub vmconfig_hotplug_pending {
            } elsif ($opt eq 'cpulimit') {
                $cgroup->change_cpu_quota(undef, undef); # reset, cgroup module can better decide values
            } elsif ($opt eq 'cpuunits') {
-               $cgroup->change_cpu_shares(undef, $confdesc->{cpuunits}->{default});
+               $cgroup->change_cpu_shares(undef);
            } elsif ($opt =~ m/^net(\d)$/) {
                my $netid = $1;
                PVE::Network::veth_delete("veth${vmid}i$netid");
@@ -1367,7 +1404,7 @@ sub vmconfig_hotplug_pending {
                my $quota = 100000 * $value;
                $cgroup->change_cpu_quota(int(100000 * $value), 100000);
            } elsif ($opt eq 'cpuunits') {
-               $cgroup->change_cpu_shares($value, $confdesc->{cpuunits}->{default});
+               $cgroup->change_cpu_shares($value);
            } elsif ($opt =~ m/^net(\d+)$/) {
                my $netid = $1;
                my $net = $class->parse_lxc_network($value);
@@ -1717,4 +1754,16 @@ sub get_backup_volumes {
     return $return_volumes;
 }
 
+sub get_derived_property {
+    my ($class, $conf, $name) = @_;
+
+    if ($name eq 'max-cpu') {
+       return $conf->{cpulimit} || $conf->{cores} || 0;
+    } elsif ($name eq 'max-memory') {
+       return ($conf->{memory} || 512) * 1024 * 1024;
+    } else {
+       die "unknown derived property - $name\n";
+    }
+}
+
 1;