]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
vzdump: set max-workers QMP option when specified and supported
[qemu-server.git] / PVE / QemuServer.pm
CommitLineData
baa4f62d 1package PVE::QemuServer;
1e3baf05
DM
2
3use strict;
990fc5e2 4use warnings;
3ff84d6f 5
5da072fb
TL
6use Cwd 'abs_path';
7use Digest::SHA;
8use Fcntl ':flock';
9use Fcntl;
1e3baf05 10use File::Basename;
5da072fb 11use File::Copy qw(copy);
1e3baf05
DM
12use File::Path;
13use File::stat;
14use Getopt::Long;
5da072fb
TL
15use IO::Dir;
16use IO::File;
17use IO::Handle;
18use IO::Select;
19use IO::Socket::UNIX;
1e3baf05 20use IPC::Open3;
c971c4f2 21use JSON;
1f30ac3a 22use MIME::Base64;
5da072fb
TL
23use POSIX;
24use Storable qw(dclone);
f85951dc 25use Time::HiRes qw(gettimeofday usleep);
5da072fb 26use URI::Escape;
425441e6 27use UUID;
5da072fb 28
82841214 29use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file);
5b65b00d 30use PVE::CGroup;
48cf040f 31use PVE::DataCenterConfig;
5da072fb 32use PVE::Exception qw(raise raise_param_exc);
3b56383b 33use PVE::Format qw(render_duration render_bytes);
81d6e4e1 34use PVE::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne);
1e3baf05 35use PVE::INotify;
4df98f2f 36use PVE::JSONSchema qw(get_standard_option parse_property_string);
1e3baf05 37use PVE::ProcFSTools;
fbec3f89 38use PVE::PBSClient;
34e82fa2 39use PVE::RESTEnvironment qw(log_warn);
91bd6c90 40use PVE::RPCEnvironment;
5da072fb 41use PVE::Storage;
b71351a7 42use PVE::SysFSTools;
d04d6af1 43use PVE::Systemd;
82841214 44use PVE::Tools qw(run_command file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
5da072fb
TL
45
46use PVE::QMPClient;
47use PVE::QemuConfig;
2f18c84d 48use PVE::QemuServer::Helpers qw(min_version config_aware_timeout);
5da072fb 49use PVE::QemuServer::Cloudinit;
5b65b00d 50use PVE::QemuServer::CGroup;
d786a274 51use PVE::QemuServer::CPUConfig qw(print_cpu_device get_cpu_options);
75748d44 52use PVE::QemuServer::Drive qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom drive_is_read_only parse_drive print_drive);
2ea5fb7e 53use PVE::QemuServer::Machine;
5da072fb 54use PVE::QemuServer::Memory;
0a13e08e 55use PVE::QemuServer::Monitor qw(mon_cmd);
74c17b7a 56use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
5da072fb 57use PVE::QemuServer::USB qw(parse_usb_device);
1e3baf05 58
28e129cc
AD
59my $have_sdn;
60eval {
61 require PVE::Network::SDN::Zones;
62 $have_sdn = 1;
63};
64
102cf9d8 65my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
96ed3574 66my $OVMF = {
b5099b4f 67 x86_64 => {
90b20b15
DC
68 '4m-no-smm' => [
69 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
70 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
71 ],
72 '4m-no-smm-ms' => [
73 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
74 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
75 ],
b5099b4f
SR
76 '4m' => [
77 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
78 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
79 ],
80 '4m-ms' => [
81 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
82 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
83 ],
84 default => [
85 "$EDK2_FW_BASE/OVMF_CODE.fd",
86 "$EDK2_FW_BASE/OVMF_VARS.fd",
87 ],
88 },
89 aarch64 => {
90 default => [
91 "$EDK2_FW_BASE/AAVMF_CODE.fd",
92 "$EDK2_FW_BASE/AAVMF_VARS.fd",
93 ],
94 },
96ed3574 95};
2ddc0a5c 96
7f0b5beb 97my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
1e3baf05 98
8d88a594
TL
99# Note about locking: we use flock on the config file protect against concurent actions.
100# Aditionaly, we have a 'lock' setting in the config file. This can be set to 'migrate',
101# 'backup', 'snapshot' or 'rollback'. Most actions are not allowed when such lock is set.
102# But you can ignore this kind of lock with the --skiplock flag.
1e3baf05 103
97d62eb7 104cfs_register_file('/qemu-server/',
1858638f
DM
105 \&parse_vm_config,
106 \&write_vm_config);
1e3baf05 107
3ea94c60
DM
108PVE::JSONSchema::register_standard_option('pve-qm-stateuri', {
109 description => "Some command save/restore state from this location.",
110 type => 'string',
111 maxLength => 128,
112 optional => 1,
113});
114
c6737ef1
DC
115PVE::JSONSchema::register_standard_option('pve-qemu-machine', {
116 description => "Specifies the Qemu machine type.",
117 type => 'string',
9471e48b 118 pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
c6737ef1
DC
119 maxLength => 40,
120 optional => 1,
121});
122
bf8fc5a3
FG
123PVE::JSONSchema::register_standard_option('pve-targetstorage', {
124 description => "Mapping from source to target storages. Providing only a single storage ID maps all source storages to that storage. Providing the special value '1' will map each source storage to itself.",
125 type => 'string',
a4d828e3 126 format => 'storage-pair-list',
bf8fc5a3
FG
127 optional => 1,
128});
129
1e3baf05
DM
130#no warnings 'redefine';
131
38277afc
TL
132my $nodename_cache;
133sub nodename {
134 $nodename_cache //= PVE::INotify::nodename();
135 return $nodename_cache;
136}
1e3baf05 137
ec3582b5
WB
138my $watchdog_fmt = {
139 model => {
140 default_key => 1,
141 type => 'string',
142 enum => [qw(i6300esb ib700)],
143 description => "Watchdog type to emulate.",
144 default => 'i6300esb',
145 optional => 1,
146 },
147 action => {
148 type => 'string',
149 enum => [qw(reset shutdown poweroff pause debug none)],
150 description => "The action to perform if after activation the guest fails to poll the watchdog in time.",
151 optional => 1,
152 },
153};
154PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
155
9d66b397
SI
156my $agent_fmt = {
157 enabled => {
8d88a594 158 description => "Enable/disable communication with a Qemu Guest Agent (QGA) running in the VM.",
9d66b397
SI
159 type => 'boolean',
160 default => 0,
161 default_key => 1,
162 },
163 fstrim_cloned_disks => {
0a4aff09 164 description => "Run fstrim after moving a disk or migrating the VM.",
9d66b397
SI
165 type => 'boolean',
166 optional => 1,
167 default => 0
168 },
48657158
MD
169 type => {
170 description => "Select the agent type",
171 type => 'string',
172 default => 'virtio',
173 optional => 1,
174 enum => [qw(virtio isa)],
175 },
9d66b397
SI
176};
177
55655ebc
DC
178my $vga_fmt = {
179 type => {
180 description => "Select the VGA type.",
181 type => 'string',
182 default => 'std',
183 optional => 1,
184 default_key => 1,
6f070e39 185 enum => [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio virtio-gl vmware)],
55655ebc
DC
186 },
187 memory => {
188 description => "Sets the VGA memory (in MiB). Has no effect with serial display.",
189 type => 'integer',
190 optional => 1,
191 minimum => 4,
192 maximum => 512,
193 },
194};
195
6dbcb073
DC
196my $ivshmem_fmt = {
197 size => {
198 type => 'integer',
199 minimum => 1,
200 description => "The size of the file in MB.",
201 },
202 name => {
203 type => 'string',
204 pattern => '[a-zA-Z0-9\-]+',
205 optional => 1,
206 format_description => 'string',
207 description => "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
208 },
209};
210
1448547f
AL
211my $audio_fmt = {
212 device => {
213 type => 'string',
214 enum => [qw(ich9-intel-hda intel-hda AC97)],
215 description => "Configure an audio device."
216 },
217 driver => {
218 type => 'string',
211785ee 219 enum => ['spice', 'none'],
1448547f
AL
220 default => 'spice',
221 optional => 1,
222 description => "Driver backend for the audio device."
223 },
224};
225
c4df18db
AL
226my $spice_enhancements_fmt = {
227 foldersharing => {
228 type => 'boolean',
229 optional => 1,
d282a24d 230 default => '0',
c4df18db
AL
231 description => "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
232 },
233 videostreaming => {
234 type => 'string',
235 enum => ['off', 'all', 'filter'],
d282a24d 236 default => 'off',
c4df18db
AL
237 optional => 1,
238 description => "Enable video streaming. Uses compression for detected video streams."
239 },
240};
241
2cf61f33
SR
242my $rng_fmt = {
243 source => {
244 type => 'string',
245 enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
246 default_key => 1,
8d88a594
TL
247 description => "The file on the host to gather entropy from. In most cases '/dev/urandom'"
248 ." should be preferred over '/dev/random' to avoid entropy-starvation issues on the"
249 ." host. Using urandom does *not* decrease security in any meaningful way, as it's"
250 ." still seeded from real entropy, and the bytes provided will most likely be mixed"
251 ." with real entropy on the guest as well. '/dev/hwrng' can be used to pass through"
252 ." a hardware RNG from the host.",
2cf61f33
SR
253 },
254 max_bytes => {
255 type => 'integer',
8d88a594
TL
256 description => "Maximum bytes of entropy allowed to get injected into the guest every"
257 ." 'period' milliseconds. Prefer a lower value when using '/dev/random' as source. Use"
258 ." `0` to disable limiting (potentially dangerous!).",
2cf61f33
SR
259 optional => 1,
260
8d88a594
TL
261 # default is 1 KiB/s, provides enough entropy to the guest to avoid boot-starvation issues
262 # (e.g. systemd etc...) while allowing no chance of overwhelming the host, provided we're
263 # reading from /dev/urandom
2cf61f33
SR
264 default => 1024,
265 },
266 period => {
267 type => 'integer',
8d88a594
TL
268 description => "Every 'period' milliseconds the entropy-injection quota is reset, allowing"
269 ." the guest to retrieve another 'max_bytes' of entropy.",
2cf61f33
SR
270 optional => 1,
271 default => 1000,
272 },
273};
274
26b443c8
TL
275my $meta_info_fmt = {
276 'ctime' => {
277 type => 'integer',
278 description => "The guest creation timestamp as UNIX epoch time",
279 minimum => 0,
280 optional => 1,
281 },
af2a1a1c
TL
282 'creation-qemu' => {
283 type => 'string',
284 description => "The QEMU (machine) version from the time this VM was created.",
285 pattern => '\d+(\.\d+)+',
286 optional => 1,
287 },
26b443c8
TL
288};
289
1e3baf05
DM
290my $confdesc = {
291 onboot => {
292 optional => 1,
293 type => 'boolean',
294 description => "Specifies whether a VM will be started during system bootup.",
295 default => 0,
296 },
297 autostart => {
298 optional => 1,
299 type => 'boolean',
300 description => "Automatic restart after crash (currently ignored).",
301 default => 0,
302 },
2ff09f52 303 hotplug => {
483ceeab
TL
304 optional => 1,
305 type => 'string', format => 'pve-hotplug-features',
306 description => "Selectively enable hotplug features. This is a comma separated list of"
8d88a594
TL
307 ." hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable"
308 ." hotplug completely. Using '1' as value is an alias for the default `network,disk,usb`.",
b3c2bdd1 309 default => 'network,disk,usb',
2ff09f52 310 },
1e3baf05
DM
311 reboot => {
312 optional => 1,
313 type => 'boolean',
314 description => "Allow reboot. If set to '0' the VM exit on reboot.",
315 default => 1,
316 },
317 lock => {
318 optional => 1,
319 type => 'string',
320 description => "Lock/unlock the VM.",
159719e5 321 enum => [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
1e3baf05
DM
322 },
323 cpulimit => {
324 optional => 1,
c6f773b8 325 type => 'number',
52261945 326 description => "Limit of CPU usage.",
8d88a594
TL
327 verbose_description => "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has"
328 ." total of '2' CPU time. Value '0' indicates no CPU limit.",
1e3baf05 329 minimum => 0,
c6f773b8 330 maximum => 128,
483ceeab 331 default => 0,
1e3baf05
DM
332 },
333 cpuunits => {
334 optional => 1,
335 type => 'integer',
483ceeab 336 description => "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
67498860
TL
337 verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler."
338 ." The larger the number is, the more CPU time this VM gets. Number is relative to"
339 ." weights of all the other running VMs.",
e65e35ca 340 minimum => 1,
237239bf 341 maximum => 262144,
67498860 342 default => 'cgroup v1: 1024, cgroup v2: 100',
1e3baf05
DM
343 },
344 memory => {
345 optional => 1,
346 type => 'integer',
8d88a594
TL
347 description => "Amount of RAM for the VM in MB. This is the maximum available memory when"
348 ." you use the balloon device.",
1e3baf05
DM
349 minimum => 16,
350 default => 512,
351 },
13a48620 352 balloon => {
483ceeab
TL
353 optional => 1,
354 type => 'integer',
355 description => "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
8b1accf7
DM
356 minimum => 0,
357 },
358 shares => {
483ceeab
TL
359 optional => 1,
360 type => 'integer',
361 description => "Amount of memory shares for auto-ballooning. The larger the number is, the"
8d88a594
TL
362 ." more memory this VM gets. Number is relative to weights of all other running VMs."
363 ." Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
8b1accf7
DM
364 minimum => 0,
365 maximum => 50000,
366 default => 1000,
13a48620 367 },
1e3baf05
DM
368 keyboard => {
369 optional => 1,
370 type => 'string',
233fb336
DW
371 description => "Keyboard layout for VNC server. This option is generally not required and"
372 ." is often better handled from within the guest OS.",
e95fe75f 373 enum => PVE::Tools::kvmkeymaplist(),
aea47dd6 374 default => undef,
1e3baf05
DM
375 },
376 name => {
377 optional => 1,
7fabe17d 378 type => 'string', format => 'dns-name',
1e3baf05
DM
379 description => "Set a name for the VM. Only used on the configuration web interface.",
380 },
cdd20088
AD
381 scsihw => {
382 optional => 1,
383 type => 'string',
52261945 384 description => "SCSI controller model",
6731a4cf 385 enum => [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
cdd20088
AD
386 default => 'lsi',
387 },
1e3baf05
DM
388 description => {
389 optional => 1,
390 type => 'string',
a200af10
TL
391 description => "Description for the VM. Shown in the web-interface VM's summary."
392 ." This is saved as comment inside the configuration file.",
393 maxLength => 1024 * 8,
1e3baf05
DM
394 },
395 ostype => {
396 optional => 1,
397 type => 'string',
483ceeab 398 enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)],
52261945
DM
399 description => "Specify guest operating system.",
400 verbose_description => <<EODESC,
401Specify guest operating system. This is used to enable special
402optimization/features for specific operating systems:
403
404[horizontal]
405other;; unspecified OS
406wxp;; Microsoft Windows XP
407w2k;; Microsoft Windows 2000
408w2k3;; Microsoft Windows 2003
409w2k8;; Microsoft Windows 2008
410wvista;; Microsoft Windows Vista
411win7;; Microsoft Windows 7
44c2a647 412win8;; Microsoft Windows 8/2012/2012r2
1f5828f2 413win10;; Microsoft Windows 10/2016/2019
179b9f1b 414win11;; Microsoft Windows 11/2022
52261945 415l24;; Linux 2.4 Kernel
a5269260 416l26;; Linux 2.6 - 5.X Kernel
52261945 417solaris;; Solaris/OpenSolaris/OpenIndiania kernel
1e3baf05
DM
418EODESC
419 },
420 boot => {
421 optional => 1,
2141a802 422 type => 'string', format => 'pve-qm-boot',
483ceeab
TL
423 description => "Specify guest boot order. Use the 'order=' sub-property as usage with no"
424 ." key or 'legacy=' is deprecated.",
1e3baf05
DM
425 },
426 bootdisk => {
427 optional => 1,
428 type => 'string', format => 'pve-qm-bootdisk',
2141a802 429 description => "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
03e480fc 430 pattern => '(ide|sata|scsi|virtio)\d+',
1e3baf05
DM
431 },
432 smp => {
433 optional => 1,
434 type => 'integer',
435 description => "The number of CPUs. Please use option -sockets instead.",
436 minimum => 1,
437 default => 1,
438 },
439 sockets => {
440 optional => 1,
441 type => 'integer',
442 description => "The number of CPU sockets.",
443 minimum => 1,
444 default => 1,
445 },
446 cores => {
447 optional => 1,
448 type => 'integer',
449 description => "The number of cores per socket.",
450 minimum => 1,
451 default => 1,
452 },
8a010eae
AD
453 numa => {
454 optional => 1,
455 type => 'boolean',
1917695c 456 description => "Enable/disable NUMA.",
8a010eae
AD
457 default => 0,
458 },
7023f3ea
AD
459 hugepages => {
460 optional => 1,
461 type => 'string',
462 description => "Enable/disable hugepages memory.",
463 enum => [qw(any 2 1024)],
464 },
f36e9894
SR
465 keephugepages => {
466 optional => 1,
467 type => 'boolean',
468 default => 0,
4df98f2f
TL
469 description => "Use together with hugepages. If enabled, hugepages will not not be deleted"
470 ." after VM shutdown and can be used for subsequent starts.",
f36e9894 471 },
de9d1e55 472 vcpus => {
3bd18e48
AD
473 optional => 1,
474 type => 'integer',
de9d1e55 475 description => "Number of hotplugged vcpus.",
3bd18e48 476 minimum => 1,
de9d1e55 477 default => 0,
3bd18e48 478 },
1e3baf05
DM
479 acpi => {
480 optional => 1,
481 type => 'boolean',
482 description => "Enable/disable ACPI.",
483 default => 1,
484 },
bc84dcca 485 agent => {
ab6a046f 486 optional => 1,
8d88a594 487 description => "Enable/disable communication with the Qemu Guest Agent and its properties.",
9d66b397
SI
488 type => 'string',
489 format => $agent_fmt,
ab6a046f 490 },
1e3baf05
DM
491 kvm => {
492 optional => 1,
493 type => 'boolean',
494 description => "Enable/disable KVM hardware virtualization.",
495 default => 1,
496 },
497 tdf => {
498 optional => 1,
499 type => 'boolean',
8c559505
DM
500 description => "Enable/disable time drift fix.",
501 default => 0,
1e3baf05 502 },
19672434 503 localtime => {
1e3baf05
DM
504 optional => 1,
505 type => 'boolean',
8d88a594
TL
506 description => "Set the real time clock (RTC) to local time. This is enabled by default if"
507 ." the `ostype` indicates a Microsoft Windows OS.",
1e3baf05
DM
508 },
509 freeze => {
510 optional => 1,
511 type => 'boolean',
512 description => "Freeze CPU at startup (use 'c' monitor command to start execution).",
513 },
514 vga => {
515 optional => 1,
55655ebc
DC
516 type => 'string', format => $vga_fmt,
517 description => "Configure the VGA hardware.",
4df98f2f
TL
518 verbose_description => "Configure the VGA Hardware. If you want to use high resolution"
519 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
520 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
521 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
522 ." display server. For win* OS you can select how many independent displays you want,"
523 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
524 ." using a serial device as terminal.",
1e3baf05 525 },
0ea9541d
DM
526 watchdog => {
527 optional => 1,
528 type => 'string', format => 'pve-qm-watchdog',
52261945 529 description => "Create a virtual hardware watchdog device.",
4df98f2f
TL
530 verbose_description => "Create a virtual hardware watchdog device. Once enabled (by a guest"
531 ." action), the watchdog must be periodically polled by an agent inside the guest or"
532 ." else the watchdog will reset the guest (or execute the respective action specified)",
0ea9541d 533 },
1e3baf05
DM
534 startdate => {
535 optional => 1,
19672434 536 type => 'string',
1e3baf05 537 typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
4df98f2f
TL
538 description => "Set the initial date of the real time clock. Valid format for date are:"
539 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
1e3baf05
DM
540 pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
541 default => 'now',
542 },
43574f73 543 startup => get_standard_option('pve-startup-order'),
68eda3ab
AD
544 template => {
545 optional => 1,
546 type => 'boolean',
547 description => "Enable/disable Template.",
548 default => 0,
549 },
1e3baf05
DM
550 args => {
551 optional => 1,
552 type => 'string',
52261945
DM
553 description => "Arbitrary arguments passed to kvm.",
554 verbose_description => <<EODESCR,
c7a8aad6 555Arbitrary arguments passed to kvm, for example:
1e3baf05
DM
556
557args: -no-reboot -no-hpet
c7a8aad6
FG
558
559NOTE: this option is for experts only.
1e3baf05
DM
560EODESCR
561 },
562 tablet => {
563 optional => 1,
564 type => 'boolean',
565 default => 1,
52261945 566 description => "Enable/disable the USB tablet device.",
4df98f2f
TL
567 verbose_description => "Enable/disable the USB tablet device. This device is usually needed"
568 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
569 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
570 ." may consider disabling this to save some context switches. This is turned off by"
571 ." default if you use spice (`qm set <vmid> --vga qxl`).",
1e3baf05
DM
572 },
573 migrate_speed => {
574 optional => 1,
575 type => 'integer',
576 description => "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
577 minimum => 0,
578 default => 0,
579 },
580 migrate_downtime => {
581 optional => 1,
04432191 582 type => 'number',
1e3baf05
DM
583 description => "Set maximum tolerated downtime (in seconds) for migrations.",
584 minimum => 0,
04432191 585 default => 0.1,
1e3baf05
DM
586 },
587 cdrom => {
588 optional => 1,
b799312f 589 type => 'string', format => 'pve-qm-ide',
8485b9ba 590 typetext => '<volume>',
1e3baf05
DM
591 description => "This is an alias for option -ide2",
592 },
593 cpu => {
594 optional => 1,
595 description => "Emulated CPU type.",
596 type => 'string',
5d008ad3 597 format => 'pve-vm-cpu-conf',
1e3baf05 598 },
b7ba6b79
DM
599 parent => get_standard_option('pve-snapshot-name', {
600 optional => 1,
601 description => "Parent snapshot name. This is used internally, and should not be modified.",
602 }),
982c7f12
DM
603 snaptime => {
604 optional => 1,
605 description => "Timestamp for snapshots.",
606 type => 'integer',
607 minimum => 0,
608 },
18bfb361
DM
609 vmstate => {
610 optional => 1,
611 type => 'string', format => 'pve-volume-id',
4df98f2f
TL
612 description => "Reference to a volume which stores the VM state. This is used internally"
613 ." for snapshots.",
18bfb361 614 },
253624c7
FG
615 vmstatestorage => get_standard_option('pve-storage-id', {
616 description => "Default storage for VM state volumes/files.",
617 optional => 1,
618 }),
c6737ef1 619 runningmachine => get_standard_option('pve-qemu-machine', {
4df98f2f
TL
620 description => "Specifies the QEMU machine type of the running vm. This is used internally"
621 ." for snapshots.",
c6737ef1 622 }),
ea1c2110 623 runningcpu => {
4df98f2f
TL
624 description => "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
625 ." internally for snapshots.",
ea1c2110
SR
626 optional => 1,
627 type => 'string',
628 pattern => $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re,
629 format_description => 'QEMU -cpu parameter'
630 },
c6737ef1 631 machine => get_standard_option('pve-qemu-machine'),
d731ecbe
WB
632 arch => {
633 description => "Virtual processor architecture. Defaults to the host.",
634 optional => 1,
635 type => 'string',
636 enum => [qw(x86_64 aarch64)],
637 },
2796e7d5
DM
638 smbios1 => {
639 description => "Specify SMBIOS type 1 fields.",
640 type => 'string', format => 'pve-qm-smbios1',
5d004b00 641 maxLength => 512,
2796e7d5
DM
642 optional => 1,
643 },
cb0e4540
AG
644 protection => {
645 optional => 1,
646 type => 'boolean',
4df98f2f
TL
647 description => "Sets the protection flag of the VM. This will disable the remove VM and"
648 ." remove disk operations.",
cb0e4540
AG
649 default => 0,
650 },
3edb45e7 651 bios => {
a783c78e 652 optional => 1,
3edb45e7
DM
653 type => 'string',
654 enum => [ qw(seabios ovmf) ],
655 description => "Select BIOS implementation.",
656 default => 'seabios',
a783c78e 657 },
6ee499ff
DC
658 vmgenid => {
659 type => 'string',
660 pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
661 format_description => 'UUID',
4df98f2f
TL
662 description => "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
663 ." to disable explicitly.",
664 verbose_description => "The VM generation ID (vmgenid) device exposes a 128-bit integer"
665 ." value identifier to the guest OS. This allows to notify the guest operating system"
666 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
667 ." execution or creation from a template). The guest operating system notices the"
668 ." change, and is then able to react as appropriate by marking its copies of"
669 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
670 ."Note that auto-creation only works when done through API/CLI create or update methods"
671 .", but not when manually editing the config file.",
f7ed64e7 672 default => "1 (autogenerated)",
6ee499ff
DC
673 optional => 1,
674 },
9e784b11
DC
675 hookscript => {
676 type => 'string',
677 format => 'pve-volume-id',
678 optional => 1,
679 description => "Script that will be executed during various steps in the vms lifetime.",
680 },
6dbcb073
DC
681 ivshmem => {
682 type => 'string',
683 format => $ivshmem_fmt,
4df98f2f
TL
684 description => "Inter-VM shared memory. Useful for direct communication between VMs, or to"
685 ." the host.",
6dbcb073 686 optional => 1,
2e7b5925
AL
687 },
688 audio0 => {
689 type => 'string',
1448547f 690 format => $audio_fmt,
194b65f1 691 description => "Configure a audio device, useful in combination with QXL/Spice.",
2e7b5925
AL
692 optional => 1
693 },
c4df18db
AL
694 spice_enhancements => {
695 type => 'string',
696 format => $spice_enhancements_fmt,
697 description => "Configure additional enhancements for SPICE.",
698 optional => 1
699 },
b8e7068a
DC
700 tags => {
701 type => 'string', format => 'pve-tag-list',
702 description => 'Tags of the VM. This is only meta information.',
703 optional => 1,
704 },
2cf61f33
SR
705 rng0 => {
706 type => 'string',
707 format => $rng_fmt,
708 description => "Configure a VirtIO-based Random Number Generator.",
709 optional => 1,
710 },
26b443c8
TL
711 meta => {
712 type => 'string',
713 format => $meta_info_fmt,
714 description => "Some (read-only) meta-information about this guest.",
715 optional => 1,
716 },
9ed7a77c
WB
717};
718
cb702ebe
DL
719my $cicustom_fmt = {
720 meta => {
721 type => 'string',
722 optional => 1,
4df98f2f
TL
723 description => 'Specify a custom file containing all meta data passed to the VM via"
724 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
cb702ebe
DL
725 format => 'pve-volume-id',
726 format_description => 'volume',
727 },
728 network => {
729 type => 'string',
730 optional => 1,
4df98f2f
TL
731 description => 'Specify a custom file containing all network data passed to the VM via'
732 .' cloud-init.',
cb702ebe
DL
733 format => 'pve-volume-id',
734 format_description => 'volume',
735 },
736 user => {
737 type => 'string',
738 optional => 1,
4df98f2f
TL
739 description => 'Specify a custom file containing all user data passed to the VM via'
740 .' cloud-init.',
cb702ebe
DL
741 format => 'pve-volume-id',
742 format_description => 'volume',
743 },
101beafe
CH
744 vendor => {
745 type => 'string',
746 optional => 1,
747 description => 'Specify a custom file containing all vendor data passed to the VM via'
748 .' cloud-init.',
749 format => 'pve-volume-id',
750 format_description => 'volume',
751 },
cb702ebe
DL
752};
753PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
754
9ed7a77c 755my $confdesc_cloudinit = {
41cd94a0
WB
756 citype => {
757 optional => 1,
758 type => 'string',
4df98f2f
TL
759 description => 'Specifies the cloud-init configuration format. The default depends on the'
760 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
761 .' and `configdrive2` for windows.',
545eec65 762 enum => ['configdrive2', 'nocloud', 'opennebula'],
41cd94a0 763 },
7b42f951
WB
764 ciuser => {
765 optional => 1,
766 type => 'string',
4df98f2f
TL
767 description => "cloud-init: User name to change ssh keys and password for instead of the"
768 ." image's configured default user.",
7b42f951
WB
769 },
770 cipassword => {
771 optional => 1,
772 type => 'string',
4df98f2f
TL
773 description => 'cloud-init: Password to assign the user. Using this is generally not'
774 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
775 .' support hashed passwords.',
7b42f951 776 },
cb702ebe
DL
777 cicustom => {
778 optional => 1,
779 type => 'string',
4df98f2f
TL
780 description => 'cloud-init: Specify custom files to replace the automatically generated'
781 .' ones at start.',
cb702ebe
DL
782 format => 'pve-qm-cicustom',
783 },
0c9a7596
AD
784 searchdomain => {
785 optional => 1,
786 type => 'string',
bd49ecb4 787 description => 'cloud-init: Sets DNS search domains for a container. Create will'
4df98f2f 788 .' automatically use the setting from the host if neither searchdomain nor nameserver'
bd49ecb4 789 .' are set.',
0c9a7596
AD
790 },
791 nameserver => {
792 optional => 1,
793 type => 'string', format => 'address-list',
bd49ecb4 794 description => 'cloud-init: Sets DNS server IP address for a container. Create will'
4df98f2f 795 .' automatically use the setting from the host if neither searchdomain nor nameserver'
bd49ecb4 796 .' are set.',
0c9a7596
AD
797 },
798 sshkeys => {
799 optional => 1,
800 type => 'string',
801 format => 'urlencoded',
1d1c4e1c 802 description => "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
0c9a7596 803 },
1e3baf05
DM
804};
805
806# what about other qemu settings ?
807#cpu => 'string',
808#machine => 'string',
809#fda => 'file',
810#fdb => 'file',
811#mtdblock => 'file',
812#sd => 'file',
813#pflash => 'file',
814#snapshot => 'bool',
815#bootp => 'file',
816##tftp => 'dir',
817##smb => 'dir',
818#kernel => 'file',
819#append => 'string',
820#initrd => 'file',
821##soundhw => 'string',
822
823while (my ($k, $v) = each %$confdesc) {
824 PVE::JSONSchema::register_standard_option("pve-qm-$k", $v);
825}
826
1e3baf05 827my $MAX_USB_DEVICES = 5;
5bdcf937 828my $MAX_NETS = 32;
bae179aa 829my $MAX_SERIAL_PORTS = 4;
1989a89c 830my $MAX_PARALLEL_PORTS = 3;
2ed5d572
AD
831my $MAX_NUMA = 8;
832
ffc0d8c7
WB
833my $numa_fmt = {
834 cpus => {
835 type => "string",
836 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 837 description => "CPUs accessing this NUMA node.",
ffc0d8c7
WB
838 format_description => "id[-id];...",
839 },
840 memory => {
841 type => "number",
52261945 842 description => "Amount of memory this NUMA node provides.",
ffc0d8c7
WB
843 optional => 1,
844 },
845 hostnodes => {
846 type => "string",
847 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 848 description => "Host NUMA nodes to use.",
ffc0d8c7
WB
849 format_description => "id[-id];...",
850 optional => 1,
851 },
852 policy => {
853 type => 'string',
854 enum => [qw(preferred bind interleave)],
52261945 855 description => "NUMA allocation policy.",
ffc0d8c7
WB
856 optional => 1,
857 },
858};
859PVE::JSONSchema::register_format('pve-qm-numanode', $numa_fmt);
2ed5d572
AD
860my $numadesc = {
861 optional => 1,
ffc0d8c7 862 type => 'string', format => $numa_fmt,
52261945 863 description => "NUMA topology.",
2ed5d572
AD
864};
865PVE::JSONSchema::register_standard_option("pve-qm-numanode", $numadesc);
866
867for (my $i = 0; $i < $MAX_NUMA; $i++) {
868 $confdesc->{"numa$i"} = $numadesc;
869}
1e3baf05 870
f7bc17ca
TL
871my $nic_model_list = [
872 'e1000',
873 'e1000-82540em',
874 'e1000-82544gc',
875 'e1000-82545em',
e83dd50a 876 'e1000e',
f7bc17ca
TL
877 'i82551',
878 'i82557b',
879 'i82559er',
880 'ne2k_isa',
881 'ne2k_pci',
882 'pcnet',
883 'rtl8139',
884 'virtio',
885 'vmxnet3',
886];
6b64503e 887my $nic_model_list_txt = join(' ', sort @$nic_model_list);
1e3baf05 888
52261945
DM
889my $net_fmt_bridge_descr = <<__EOD__;
890Bridge to attach the network device to. The Proxmox VE standard bridge
891is called 'vmbr0'.
892
893If you do not specify a bridge, we create a kvm user (NATed) network
894device, which provides DHCP and DNS services. The following addresses
895are used:
896
897 10.0.2.2 Gateway
898 10.0.2.3 DNS Server
899 10.0.2.4 SMB Server
900
901The DHCP server assign addresses to the guest starting from 10.0.2.15.
902__EOD__
903
cd9c34d1 904my $net_fmt = {
399d96db 905 macaddr => get_standard_option('mac-addr', {
4df98f2f
TL
906 description => "MAC address. That address must be unique withing your network. This is"
907 ." automatically generated if not specified.",
399d96db 908 }),
7f694a71
DM
909 model => {
910 type => 'string',
4df98f2f
TL
911 description => "Network Card Model. The 'virtio' model provides the best performance with"
912 ." very low CPU overhead. If your guest does not support this driver, it is usually"
913 ." best to use 'e1000'.",
7f694a71
DM
914 enum => $nic_model_list,
915 default_key => 1,
916 },
917 (map { $_ => { keyAlias => 'model', alias => 'macaddr' }} @$nic_model_list),
dbdcc5cd 918 bridge => get_standard_option('pve-bridge-id', {
52261945 919 description => $net_fmt_bridge_descr,
cd9c34d1 920 optional => 1,
dbdcc5cd 921 }),
cd9c34d1
WB
922 queues => {
923 type => 'integer',
924 minimum => 0, maximum => 16,
925 description => 'Number of packet queues to be used on the device.',
cd9c34d1
WB
926 optional => 1,
927 },
928 rate => {
929 type => 'number',
930 minimum => 0,
52261945 931 description => "Rate limit in mbps (megabytes per second) as floating point number.",
cd9c34d1
WB
932 optional => 1,
933 },
934 tag => {
935 type => 'integer',
9f41a659 936 minimum => 1, maximum => 4094,
cd9c34d1 937 description => 'VLAN tag to apply to packets on this interface.',
cd9c34d1
WB
938 optional => 1,
939 },
940 trunks => {
941 type => 'string',
942 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
943 description => 'VLAN trunks to pass through this interface.',
7f694a71 944 format_description => 'vlanid[;vlanid...]',
cd9c34d1
WB
945 optional => 1,
946 },
947 firewall => {
948 type => 'boolean',
949 description => 'Whether this interface should be protected by the firewall.',
cd9c34d1
WB
950 optional => 1,
951 },
952 link_down => {
953 type => 'boolean',
52261945 954 description => 'Whether this interface should be disconnected (like pulling the plug).',
cd9c34d1
WB
955 optional => 1,
956 },
61a14cde
AD
957 mtu => {
958 type => 'integer',
959 minimum => 1, maximum => 65520,
0530177b 960 description => "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
61a14cde
AD
961 optional => 1,
962 },
cd9c34d1 963};
52261945 964
1e3baf05
DM
965my $netdesc = {
966 optional => 1,
7f694a71 967 type => 'string', format => $net_fmt,
52261945 968 description => "Specify network devices.",
1e3baf05 969};
52261945 970
1e3baf05
DM
971PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
972
0c9a7596
AD
973my $ipconfig_fmt = {
974 ip => {
975 type => 'string',
976 format => 'pve-ipv4-config',
977 format_description => 'IPv4Format/CIDR',
978 description => 'IPv4 address in CIDR format.',
979 optional => 1,
980 default => 'dhcp',
981 },
982 gw => {
983 type => 'string',
984 format => 'ipv4',
985 format_description => 'GatewayIPv4',
986 description => 'Default gateway for IPv4 traffic.',
987 optional => 1,
988 requires => 'ip',
989 },
990 ip6 => {
991 type => 'string',
992 format => 'pve-ipv6-config',
993 format_description => 'IPv6Format/CIDR',
994 description => 'IPv6 address in CIDR format.',
995 optional => 1,
996 default => 'dhcp',
997 },
998 gw6 => {
999 type => 'string',
1000 format => 'ipv6',
1001 format_description => 'GatewayIPv6',
1002 description => 'Default gateway for IPv6 traffic.',
1003 optional => 1,
1004 requires => 'ip6',
1005 },
1006};
1007PVE::JSONSchema::register_format('pve-qm-ipconfig', $ipconfig_fmt);
1008my $ipconfigdesc = {
1009 optional => 1,
1010 type => 'string', format => 'pve-qm-ipconfig',
1011 description => <<'EODESCR',
1012cloud-init: Specify IP addresses and gateways for the corresponding interface.
1013
1014IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
1015
4df98f2f
TL
1016The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
1017gateway should be provided.
988be8d0
ML
1018For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
1019cloud-init 19.4 or newer.
0c9a7596 1020
4df98f2f
TL
1021If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
1022dhcp on IPv4.
0c9a7596
AD
1023EODESCR
1024};
1025PVE::JSONSchema::register_standard_option("pve-qm-ipconfig", $netdesc);
1026
1e3baf05
DM
1027for (my $i = 0; $i < $MAX_NETS; $i++) {
1028 $confdesc->{"net$i"} = $netdesc;
9ed7a77c
WB
1029 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
1030}
1031
1032foreach my $key (keys %$confdesc_cloudinit) {
1033 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1e3baf05
DM
1034}
1035
ffa42b86
DC
1036PVE::JSONSchema::register_format('pve-volume-id-or-qm-path', \&verify_volume_id_or_qm_path);
1037sub verify_volume_id_or_qm_path {
822c8a07
WB
1038 my ($volid, $noerr) = @_;
1039
6e55f579
FE
1040 return $volid if $volid eq 'none' || $volid eq 'cdrom';
1041
1042 return verify_volume_id_or_absolute_path($volid, $noerr);
1043}
1044
1045PVE::JSONSchema::register_format('pve-volume-id-or-absolute-path', \&verify_volume_id_or_absolute_path);
1046sub verify_volume_id_or_absolute_path {
1047 my ($volid, $noerr) = @_;
1048
1049 return $volid if $volid =~ m|^/|;
ffa42b86 1050
822c8a07
WB
1051 $volid = eval { PVE::JSONSchema::check_format('pve-volume-id', $volid, '') };
1052 if ($@) {
d1c1af4b 1053 return if $noerr;
822c8a07
WB
1054 die $@;
1055 }
1056 return $volid;
1057}
1058
ff6ffe20 1059my $usb_fmt = {
a6b9aee4
DC
1060 host => {
1061 default_key => 1,
1062 type => 'string', format => 'pve-qm-usb-device',
1063 format_description => 'HOSTUSBDEVICE|spice',
52261945
DM
1064 description => <<EODESCR,
1065The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1066
1067 'bus-port(.port)*' (decimal numbers) or
1068 'vendor_id:product_id' (hexadeciaml numbers) or
1069 'spice'
1070
1071You can use the 'lsusb -t' command to list existing usb devices.
1072
4df98f2f
TL
1073NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1074machines - use with special care.
52261945
DM
1075
1076The value 'spice' can be used to add a usb redirection devices for spice.
1077EODESCR
a6b9aee4
DC
1078 },
1079 usb3 => {
1080 optional => 1,
1081 type => 'boolean',
97ef5356 1082 description => "Specifies whether if given host option is a USB3 device or port.",
52261945 1083 default => 0,
a6b9aee4
DC
1084 },
1085};
1086
1e3baf05
DM
1087my $usbdesc = {
1088 optional => 1,
ff6ffe20 1089 type => 'string', format => $usb_fmt,
52261945 1090 description => "Configure an USB device (n is 0 to 4).",
1e3baf05
DM
1091};
1092PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
1093
bae179aa
DA
1094my $serialdesc = {
1095 optional => 1,
ca0cef26 1096 type => 'string',
1b0b51ed 1097 pattern => '(/dev/.+|socket)',
52261945
DM
1098 description => "Create a serial device inside the VM (n is 0 to 3)",
1099 verbose_description => <<EODESCR,
52261945
DM
1100Create a serial device inside the VM (n is 0 to 3), and pass through a
1101host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1102host side (use 'qm terminal' to open a terminal connection).
bae179aa 1103
4df98f2f
TL
1104NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1105use with special care.
bae179aa 1106
52261945 1107CAUTION: Experimental! User reported problems with this option.
bae179aa
DA
1108EODESCR
1109};
bae179aa 1110
1989a89c
DA
1111my $paralleldesc= {
1112 optional => 1,
ca0cef26 1113 type => 'string',
9ecc8431 1114 pattern => '/dev/parport\d+|/dev/usb/lp\d+',
52261945
DM
1115 description => "Map host parallel devices (n is 0 to 2).",
1116 verbose_description => <<EODESCR,
19672434 1117Map host parallel devices (n is 0 to 2).
1989a89c 1118
4df98f2f
TL
1119NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1120machines - use with special care.
1989a89c 1121
52261945 1122CAUTION: Experimental! User reported problems with this option.
1989a89c
DA
1123EODESCR
1124};
1989a89c
DA
1125
1126for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1127 $confdesc->{"parallel$i"} = $paralleldesc;
1128}
1129
bae179aa
DA
1130for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1131 $confdesc->{"serial$i"} = $serialdesc;
1132}
1133
74c17b7a
SR
1134for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++) {
1135 $confdesc->{"hostpci$i"} = $PVE::QemuServer::PCI::hostpcidesc;
040b06b7 1136}
1e3baf05 1137
e0fd2b2f
FE
1138for my $key (keys %{$PVE::QemuServer::Drive::drivedesc_hash}) {
1139 $confdesc->{$key} = $PVE::QemuServer::Drive::drivedesc_hash->{$key};
cdb0931f
DA
1140}
1141
1e3baf05
DM
1142for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1143 $confdesc->{"usb$i"} = $usbdesc;
1144}
1145
5cfa9f5f
SR
1146my $boot_fmt = {
1147 legacy => {
1148 optional => 1,
1149 default_key => 1,
1150 type => 'string',
1151 description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1152 . " Deprecated, use 'order=' instead.",
1153 pattern => '[acdn]{1,4}',
1154 format_description => "[acdn]{1,4}",
1155
1156 # note: this is also the fallback if boot: is not given at all
1157 default => 'cdn',
1158 },
1159 order => {
1160 optional => 1,
1161 type => 'string',
1162 format => 'pve-qm-bootdev-list',
1163 format_description => "device[;device...]",
1164 description => <<EODESC,
1165The guest will attempt to boot from devices in the order they appear here.
1166
1167Disks, optical drives and passed-through storage USB devices will be directly
1168booted from, NICs will load PXE, and PCIe devices will either behave like disks
1169(e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1170
1171Note that only devices in this list will be marked as bootable and thus loaded
1172by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1173(e.g. software-raid), you need to specify all of them here.
1174
1175Overrides the deprecated 'legacy=[acdn]*' value when given.
1176EODESC
1177 },
1178};
1179PVE::JSONSchema::register_format('pve-qm-boot', $boot_fmt);
1180
1181PVE::JSONSchema::register_format('pve-qm-bootdev', \&verify_bootdev);
1182sub verify_bootdev {
1183 my ($dev, $noerr) = @_;
1184
f9dde219
SR
1185 my $special = $dev =~ m/^efidisk/ || $dev =~ m/^tpmstate/;
1186 return $dev if PVE::QemuServer::Drive::is_valid_drivename($dev) && !$special;
5cfa9f5f
SR
1187
1188 my $check = sub {
1189 my ($base) = @_;
1190 return 0 if $dev !~ m/^$base\d+$/;
1191 return 0 if !$confdesc->{$dev};
1192 return 1;
1193 };
1194
1195 return $dev if $check->("net");
1196 return $dev if $check->("usb");
1197 return $dev if $check->("hostpci");
1198
d1c1af4b 1199 return if $noerr;
5cfa9f5f
SR
1200 die "invalid boot device '$dev'\n";
1201}
1202
1203sub print_bootorder {
1204 my ($devs) = @_;
4c27b18c 1205 return "" if !@$devs;
5cfa9f5f
SR
1206 my $data = { order => join(';', @$devs) };
1207 return PVE::JSONSchema::print_property_string($data, $boot_fmt);
1208}
1209
1e3baf05
DM
1210my $kvm_api_version = 0;
1211
1212sub kvm_version {
1e3baf05
DM
1213 return $kvm_api_version if $kvm_api_version;
1214
808a65b5 1215 open my $fh, '<', '/dev/kvm' or return;
1e3baf05 1216
646f2df4
WB
1217 # 0xae00 => KVM_GET_API_VERSION
1218 $kvm_api_version = ioctl($fh, 0xae00, 0);
808a65b5 1219 close($fh);
1e3baf05 1220
646f2df4 1221 return $kvm_api_version;
1e3baf05
DM
1222}
1223
1476b99f
DC
1224my $kvm_user_version = {};
1225my $kvm_mtime = {};
1e3baf05
DM
1226
1227sub kvm_user_version {
1476b99f 1228 my ($binary) = @_;
1e3baf05 1229
1476b99f
DC
1230 $binary //= get_command_for_arch(get_host_arch()); # get the native arch by default
1231 my $st = stat($binary);
1e3baf05 1232
1476b99f
DC
1233 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1234 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1235 $cachedmtime == $st->mtime;
1236
1237 $kvm_user_version->{$binary} = 'unknown';
1238 $kvm_mtime->{$binary} = $st->mtime;
1e3baf05 1239
09b11429
TL
1240 my $code = sub {
1241 my $line = shift;
1242 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1476b99f 1243 $kvm_user_version->{$binary} = $2;
09b11429
TL
1244 }
1245 };
19672434 1246
1476b99f 1247 eval { run_command([$binary, '--version'], outfunc => $code); };
09b11429 1248 warn $@ if $@;
1e3baf05 1249
1476b99f 1250 return $kvm_user_version->{$binary};
1e3baf05
DM
1251
1252}
4df98f2f
TL
1253my sub extract_version {
1254 my ($machine_type, $version) = @_;
1255 $version = kvm_user_version() if !defined($version);
8eb73377 1256 return PVE::QemuServer::Machine::extract_version($machine_type, $version)
4df98f2f 1257}
1e3baf05 1258
db70021b
TL
1259sub kernel_has_vhost_net {
1260 return -c '/dev/vhost-net';
1261}
1e3baf05 1262
1e3baf05
DM
1263sub option_exists {
1264 my $key = shift;
1265 return defined($confdesc->{$key});
19672434 1266}
1e3baf05 1267
1e3baf05 1268my $cdrom_path;
1e3baf05
DM
1269sub get_cdrom_path {
1270
1271 return $cdrom_path if $cdrom_path;
1272
1273 return $cdrom_path = "/dev/cdrom" if -l "/dev/cdrom";
1274 return $cdrom_path = "/dev/cdrom1" if -l "/dev/cdrom1";
1275 return $cdrom_path = "/dev/cdrom2" if -l "/dev/cdrom2";
1276}
1277
1278sub get_iso_path {
1279 my ($storecfg, $vmid, $cdrom) = @_;
1280
1281 if ($cdrom eq 'cdrom') {
1282 return get_cdrom_path();
1283 } elsif ($cdrom eq 'none') {
1284 return '';
1285 } elsif ($cdrom =~ m|^/|) {
1286 return $cdrom;
1287 } else {
6b64503e 1288 return PVE::Storage::path($storecfg, $cdrom);
1e3baf05
DM
1289 }
1290}
1291
1292# try to convert old style file names to volume IDs
1293sub filename_to_volume_id {
1294 my ($vmid, $file, $media) = @_;
1295
0c9a7596 1296 if (!($file eq 'none' || $file eq 'cdrom' ||
1e3baf05 1297 $file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
19672434 1298
d1c1af4b 1299 return if $file =~ m|/|;
19672434 1300
1e3baf05
DM
1301 if ($media && $media eq 'cdrom') {
1302 $file = "local:iso/$file";
1303 } else {
1304 $file = "local:$vmid/$file";
1305 }
1306 }
1307
1308 return $file;
1309}
1310
1311sub verify_media_type {
1312 my ($opt, $vtype, $media) = @_;
1313
1314 return if !$media;
1315
1316 my $etype;
1317 if ($media eq 'disk') {
a125592c 1318 $etype = 'images';
1e3baf05
DM
1319 } elsif ($media eq 'cdrom') {
1320 $etype = 'iso';
1321 } else {
1322 die "internal error";
1323 }
1324
1325 return if ($vtype eq $etype);
19672434 1326
1e3baf05
DM
1327 raise_param_exc({ $opt => "unexpected media type ($vtype != $etype)" });
1328}
1329
1330sub cleanup_drive_path {
1331 my ($opt, $storecfg, $drive) = @_;
1332
1333 # try to convert filesystem paths to volume IDs
1334
1335 if (($drive->{file} !~ m/^(cdrom|none)$/) &&
1336 ($drive->{file} !~ m|^/dev/.+|) &&
1337 ($drive->{file} !~ m/^([^:]+):(.+)$/) &&
19672434 1338 ($drive->{file} !~ m/^\d+$/)) {
1e3baf05 1339 my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
4df98f2f
TL
1340 raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1341 if !$vtype;
1e3baf05
DM
1342 $drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
1343 verify_media_type($opt, $vtype, $drive->{media});
1344 $drive->{file} = $volid;
1345 }
1346
1347 $drive->{media} = 'cdrom' if !$drive->{media} && $drive->{file} =~ m/^(cdrom|none)$/;
1348}
1349
b3c2bdd1
DM
1350sub parse_hotplug_features {
1351 my ($data) = @_;
1352
1353 my $res = {};
1354
1355 return $res if $data eq '0';
a1b7d579 1356
b3c2bdd1
DM
1357 $data = $confdesc->{hotplug}->{default} if $data eq '1';
1358
45827685 1359 foreach my $feature (PVE::Tools::split_list($data)) {
b3c2bdd1
DM
1360 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1361 $res->{$1} = 1;
1362 } else {
596a0a20 1363 die "invalid hotplug feature '$feature'\n";
b3c2bdd1
DM
1364 }
1365 }
1366 return $res;
1367}
1368
1369PVE::JSONSchema::register_format('pve-hotplug-features', \&pve_verify_hotplug_features);
1370sub pve_verify_hotplug_features {
1371 my ($value, $noerr) = @_;
1372
1373 return $value if parse_hotplug_features($value);
1374
d1c1af4b 1375 return if $noerr;
b3c2bdd1
DM
1376
1377 die "unable to parse hotplug option\n";
1378}
1379
28ef82d3
DM
1380sub scsi_inquiry {
1381 my($fh, $noerr) = @_;
1382
1383 my $SG_IO = 0x2285;
1384 my $SG_GET_VERSION_NUM = 0x2282;
1385
1386 my $versionbuf = "\x00" x 8;
1387 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1388 if (!$ret) {
1389 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
d1c1af4b 1390 return;
28ef82d3 1391 }
97d62eb7 1392 my $version = unpack("I", $versionbuf);
28ef82d3
DM
1393 if ($version < 30000) {
1394 die "scsi generic interface too old\n" if !$noerr;
d1c1af4b 1395 return;
28ef82d3 1396 }
97d62eb7 1397
28ef82d3
DM
1398 my $buf = "\x00" x 36;
1399 my $sensebuf = "\x00" x 8;
f334aa3e 1400 my $cmd = pack("C x3 C x1", 0x12, 36);
97d62eb7 1401
28ef82d3
DM
1402 # see /usr/include/scsi/sg.h
1403 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1404
f606d5bd
TL
1405 my $packet = pack(
1406 $sg_io_hdr_t, ord('S'), -3, length($cmd), length($sensebuf), 0, length($buf), $buf, $cmd, $sensebuf, 6000
1407 );
28ef82d3
DM
1408
1409 $ret = ioctl($fh, $SG_IO, $packet);
1410 if (!$ret) {
1411 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
d1c1af4b 1412 return;
28ef82d3 1413 }
97d62eb7 1414
28ef82d3
DM
1415 my @res = unpack($sg_io_hdr_t, $packet);
1416 if ($res[17] || $res[18]) {
1417 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
d1c1af4b 1418 return;
28ef82d3
DM
1419 }
1420
1421 my $res = {};
f606d5bd 1422 $res->@{qw(type removable vendor product revision)} = unpack("C C x6 A8 A16 A4", $buf);
28ef82d3 1423
f606d5bd
TL
1424 $res->{removable} = $res->{removable} & 128 ? 1 : 0;
1425 $res->{type} &= 0x1F;
09984754 1426
28ef82d3
DM
1427 return $res;
1428}
1429
1430sub path_is_scsi {
1431 my ($path) = @_;
1432
d1c1af4b 1433 my $fh = IO::File->new("+<$path") || return;
28ef82d3
DM
1434 my $res = scsi_inquiry($fh, 1);
1435 close($fh);
1436
1437 return $res;
1438}
1439
db656e5f 1440sub print_tabletdevice_full {
d559309f 1441 my ($conf, $arch) = @_;
b467f79a 1442
3392d6ca 1443 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f
DM
1444
1445 # we use uhci for old VMs because tablet driver was buggy in older qemu
d559309f 1446 my $usbbus;
3392d6ca 1447 if (PVE::QemuServer::Machine::machine_type_is_q35($conf) || $arch eq 'aarch64') {
d559309f
WB
1448 $usbbus = 'ehci';
1449 } else {
1450 $usbbus = 'uhci';
1451 }
b467f79a 1452
db656e5f
DM
1453 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1454}
1455
d559309f 1456sub print_keyboarddevice_full {
6971c38e 1457 my ($conf, $arch) = @_;
d559309f 1458
d1c1af4b 1459 return if $arch ne 'aarch64';
d559309f
WB
1460
1461 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1462}
1463
a183df68
TL
1464my sub get_drive_id {
1465 my ($drive) = @_;
1466 return "$drive->{interface}$drive->{index}";
1467}
1468
ca916ecc 1469sub print_drivedevice_full {
d559309f 1470 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
ca916ecc
DA
1471
1472 my $device = '';
1473 my $maxdev = 0;
19672434 1474
a183df68 1475 my $drive_id = get_drive_id($drive);
ca916ecc 1476 if ($drive->{interface} eq 'virtio') {
4df98f2f
TL
1477 my $pciaddr = print_pci_addr("$drive_id", $bridges, $arch, $machine_type);
1478 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1479 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread};
2ed36a41 1480 } elsif ($drive->{interface} eq 'scsi') {
6731a4cf 1481
ee034f5c 1482 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
2ed36a41
DM
1483 my $unit = $drive->{index} % $maxdev;
1484 my $devicetype = 'hd';
69bcf246
WB
1485 my $path = '';
1486 if (drive_is_cdrom($drive)) {
1487 $devicetype = 'cd';
29b19529 1488 } else {
69bcf246
WB
1489 if ($drive->{file} =~ m|^/|) {
1490 $path = $drive->{file};
1491 if (my $info = path_is_scsi($path)) {
8e3c33ab 1492 if ($info->{type} == 0 && $drive->{scsiblock}) {
69bcf246
WB
1493 $devicetype = 'block';
1494 } elsif ($info->{type} == 1) { # tape
1495 $devicetype = 'generic';
1496 }
1497 }
1498 } else {
1499 $path = PVE::Storage::path($storecfg, $drive->{file});
1500 }
1501
a034e3d6 1502 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
4df98f2f 1503 my $version = extract_version($machine_type, kvm_user_version());
a034e3d6 1504 if ($path =~ m/^iscsi\:\/\// &&
2ea5fb7e 1505 !min_version($version, 4, 1)) {
69bcf246
WB
1506 $devicetype = 'generic';
1507 }
1508 }
1509
ef88eaaa 1510 if (!$conf->{scsihw} || $conf->{scsihw} =~ m/^lsi/ || $conf->{scsihw} eq 'pvscsi') {
4df98f2f 1511 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
69bcf246 1512 } else {
4df98f2f
TL
1513 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1514 .",lun=$drive->{index}";
69bcf246 1515 }
4df98f2f 1516 $device .= ",drive=drive-$drive_id,id=$drive_id";
cdd20088 1517
6c875f9f
NC
1518 if ($drive->{ssd} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1519 $device .= ",rotation_rate=1";
1520 }
e741c516 1521 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
6c875f9f
NC
1522
1523 } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') {
e0fd2b2f 1524 my $maxdev = ($drive->{interface} eq 'sata') ? $PVE::QemuServer::Drive::MAX_SATA_DISKS : 2;
2ed36a41
DM
1525 my $controller = int($drive->{index} / $maxdev);
1526 my $unit = $drive->{index} % $maxdev;
1527 my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
1528
6c875f9f
NC
1529 $device = "ide-$devicetype";
1530 if ($drive->{interface} eq 'ide') {
1531 $device .= ",bus=ide.$controller,unit=$unit";
1532 } else {
1533 $device .= ",bus=ahci$controller.$unit";
1534 }
4df98f2f 1535 $device .= ",drive=drive-$drive_id,id=$drive_id";
6c875f9f
NC
1536
1537 if ($devicetype eq 'hd') {
1538 if (my $model = $drive->{model}) {
1539 $model = URI::Escape::uri_unescape($model);
1540 $device .= ",model=$model";
1541 }
1542 if ($drive->{ssd}) {
1543 $device .= ",rotation_rate=1";
1544 }
0f2812c2 1545 }
e741c516 1546 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
2ed36a41
DM
1547 } elsif ($drive->{interface} eq 'usb') {
1548 die "implement me";
1549 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1550 } else {
1551 die "unsupported interface type";
ca916ecc
DA
1552 }
1553
3b408e82
DM
1554 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex};
1555
a70e7e6c
TL
1556 if (my $serial = $drive->{serial}) {
1557 $serial = URI::Escape::uri_unescape($serial);
1558 $device .= ",serial=$serial";
1559 }
1560
1561
ca916ecc
DA
1562 return $device;
1563}
1564
15b21acc 1565sub get_initiator_name {
46f58b5f 1566 my $initiator;
15b21acc 1567
d1c1af4b 1568 my $fh = IO::File->new('/etc/iscsi/initiatorname.iscsi') || return;
46f58b5f
DM
1569 while (defined(my $line = <$fh>)) {
1570 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
15b21acc
MR
1571 $initiator = $1;
1572 last;
1573 }
46f58b5f
DM
1574 $fh->close();
1575
15b21acc
MR
1576 return $initiator;
1577}
1578
776c5f50 1579sub print_drive_commandline_full {
6d5673c3 1580 my ($storecfg, $vmid, $drive, $pbs_name, $io_uring) = @_;
1e3baf05 1581
d81f0f09
DM
1582 my $path;
1583 my $volid = $drive->{file};
5921764c 1584 my $format = $drive->{format};
a183df68 1585 my $drive_id = get_drive_id($drive);
370b05e7 1586
0fe779a6
WB
1587 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
1588 my $scfg = $storeid ? PVE::Storage::storage_config($storecfg, $storeid) : undef;
1589
d81f0f09
DM
1590 if (drive_is_cdrom($drive)) {
1591 $path = get_iso_path($storecfg, $vmid, $volid);
a183df68 1592 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
d81f0f09 1593 } else {
d81f0f09
DM
1594 if ($storeid) {
1595 $path = PVE::Storage::path($storecfg, $volid);
5921764c 1596 $format //= qemu_img_format($scfg, $volname);
d81f0f09
DM
1597 } else {
1598 $path = $volid;
5921764c 1599 $format //= "raw";
d81f0f09
DM
1600 }
1601 }
1602
5921764c
SR
1603 my $is_rbd = $path =~ m/^rbd:/;
1604
1e3baf05 1605 my $opts = '';
5921764c 1606 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1e3baf05 1607 foreach my $o (@qemu_drive_options) {
5fc74861 1608 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
19672434 1609 }
8a267708
DC
1610
1611 # snapshot only accepts on|off
1612 if (defined($drive->{snapshot})) {
1613 my $v = $drive->{snapshot} ? 'on' : 'off';
1614 $opts .= ",snapshot=$v";
1615 }
1616
1f91f7b4
TL
1617 if (defined($drive->{ro})) { # ro maps to QEMUs `readonly`, which accepts `on` or `off` only
1618 $opts .= ",readonly=" . ($drive->{ro} ? 'on' : 'off');
12e1d472
DC
1619 }
1620
fb8e95a2
WB
1621 foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) {
1622 my ($dir, $qmpname) = @$type;
1623 if (my $v = $drive->{"mbps$dir"}) {
1624 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1625 }
1626 if (my $v = $drive->{"mbps${dir}_max"}) {
1627 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1628 }
1629 if (my $v = $drive->{"bps${dir}_max_length"}) {
1630 $opts .= ",throttling.bps$qmpname-max-length=$v";
1631 }
1632 if (my $v = $drive->{"iops${dir}"}) {
1633 $opts .= ",throttling.iops$qmpname=$v";
1634 }
1635 if (my $v = $drive->{"iops${dir}_max"}) {
8aca1654 1636 $opts .= ",throttling.iops$qmpname-max=$v";
fb8e95a2
WB
1637 }
1638 if (my $v = $drive->{"iops${dir}_max_length"}) {
8aca1654 1639 $opts .= ",throttling.iops$qmpname-max-length=$v";
fb8e95a2
WB
1640 }
1641 }
1642
5921764c
SR
1643 if ($pbs_name) {
1644 $format = "rbd" if $is_rbd;
a183df68
TL
1645 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1646 if !$format;
5921764c
SR
1647 $opts .= ",format=alloc-track,file.driver=$format";
1648 } elsif ($format) {
1649 $opts .= ",format=$format";
1650 }
d81f0f09 1651
b2ee900e
WB
1652 my $cache_direct = 0;
1653
1654 if (my $cache = $drive->{cache}) {
1655 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
0fe779a6 1656 } elsif (!drive_is_cdrom($drive) && !($scfg && $scfg->{type} eq 'btrfs' && !$scfg->{nocow})) {
b2ee900e
WB
1657 $opts .= ",cache=none";
1658 $cache_direct = 1;
1659 }
1660
628937f5
SR
1661 # io_uring with cache mode writeback or writethrough on krbd will hang...
1662 my $rbd_no_io_uring = $scfg && $scfg->{type} eq 'rbd' && $scfg->{krbd} && !$cache_direct;
1663
78a3ada7
TL
1664 # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
1665 # sometimes, just plain disable...
1666 my $lvm_no_io_uring = $scfg && $scfg->{type} eq 'lvm';
ec5d198e 1667
b2ee900e 1668 if (!$drive->{aio}) {
ec5d198e 1669 if ($io_uring && !$rbd_no_io_uring && !$lvm_no_io_uring) {
6d5673c3
SR
1670 # io_uring supports all cache modes
1671 $opts .= ",aio=io_uring";
b2ee900e 1672 } else {
6d5673c3
SR
1673 # aio native works only with O_DIRECT
1674 if($cache_direct) {
1675 $opts .= ",aio=native";
1676 } else {
1677 $opts .= ",aio=threads";
1678 }
b2ee900e
WB
1679 }
1680 }
11490cf2 1681
6e47c3b4
WB
1682 if (!drive_is_cdrom($drive)) {
1683 my $detectzeroes;
7d4e30f3 1684 if (defined($drive->{detect_zeroes}) && !$drive->{detect_zeroes}) {
6e47c3b4
WB
1685 $detectzeroes = 'off';
1686 } elsif ($drive->{discard}) {
1687 $detectzeroes = $drive->{discard} eq 'on' ? 'unmap' : 'on';
1688 } else {
1689 # This used to be our default with discard not being specified:
1690 $detectzeroes = 'on';
1691 }
5921764c
SR
1692
1693 # note: 'detect-zeroes' works per blockdev and we want it to persist
1694 # after the alloc-track is removed, so put it on 'file' directly
1695 my $dz_param = $pbs_name ? "file.detect-zeroes" : "detect-zeroes";
1696 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
6e47c3b4 1697 }
f1e05305 1698
5921764c
SR
1699 if ($pbs_name) {
1700 $opts .= ",backing=$pbs_name";
1701 $opts .= ",auto-remove=on";
1702 }
1703
1704 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1705 my $file_param = "file";
1706 if ($pbs_name) {
1707 # non-rbd drivers require the underlying file to be a seperate block
1708 # node, so add a second .file indirection
1709 $file_param .= ".file" if !$is_rbd;
1710 $file_param .= ".filename";
1711 }
1712 my $pathinfo = $path ? "$file_param=$path," : '';
1e3baf05 1713
3ebfcc86 1714 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1e3baf05
DM
1715}
1716
5921764c
SR
1717sub print_pbs_blockdev {
1718 my ($pbs_conf, $pbs_name) = @_;
1719 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1720 $blockdev .= ",repository=$pbs_conf->{repository}";
2dda626d 1721 $blockdev .= ",namespace=$pbs_conf->{namespace}" if $pbs_conf->{namespace};
5921764c
SR
1722 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1723 $blockdev .= ",archive=$pbs_conf->{archive}";
1724 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile};
1725 return $blockdev;
1726}
1727
cc4d6182 1728sub print_netdevice_full {
d559309f 1729 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
cc4d6182 1730
cc4d6182
DA
1731 my $device = $net->{model};
1732 if ($net->{model} eq 'virtio') {
1733 $device = 'virtio-net-pci';
1734 };
1735
d559309f 1736 my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $machine_type);
5e2068d2 1737 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
a9410357 1738 if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
4df98f2f
TL
1739 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1740 # and out of each queue plus one config interrupt and control vector queue
a9410357
AD
1741 my $vectors = $net->{queues} * 2 + 2;
1742 $tmpstr .= ",vectors=$vectors,mq=on";
1743 }
cc4d6182 1744 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
ba9e1000 1745
0530177b
TL
1746 if (my $mtu = $net->{mtu}) {
1747 if ($net->{model} eq 'virtio' && $net->{bridge}) {
1748 my $bridge_mtu = PVE::Network::read_bridge_mtu($net->{bridge});
1749 if ($mtu == 1) {
1750 $mtu = $bridge_mtu;
1751 } elsif ($mtu < 576) {
1752 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1753 } elsif ($mtu > $bridge_mtu) {
1754 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1755 }
1756 $tmpstr .= ",host_mtu=$mtu";
1757 } else {
1758 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
61a14cde 1759 }
61a14cde
AD
1760 }
1761
ba9e1000
DM
1762 if ($use_old_bios_files) {
1763 my $romfile;
1764 if ($device eq 'virtio-net-pci') {
1765 $romfile = 'pxe-virtio.rom';
1766 } elsif ($device eq 'e1000') {
1767 $romfile = 'pxe-e1000.rom';
e83dd50a
TL
1768 } elsif ($device eq 'e1000e') {
1769 $romfile = 'pxe-e1000e.rom';
ba9e1000
DM
1770 } elsif ($device eq 'ne2k') {
1771 $romfile = 'pxe-ne2k_pci.rom';
1772 } elsif ($device eq 'pcnet') {
1773 $romfile = 'pxe-pcnet.rom';
1774 } elsif ($device eq 'rtl8139') {
1775 $romfile = 'pxe-rtl8139.rom';
1776 }
1777 $tmpstr .= ",romfile=$romfile" if $romfile;
1778 }
1779
cc4d6182
DA
1780 return $tmpstr;
1781}
1782
1783sub print_netdev_full {
d559309f 1784 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
cc4d6182
DA
1785
1786 my $i = '';
1787 if ($netid =~ m/^net(\d+)$/) {
1788 $i = int($1);
1789 }
1790
1791 die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
1792
1793 my $ifname = "tap${vmid}i$i";
1794
1795 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1796 die "interface name '$ifname' is too long (max 15 character)\n"
1797 if length($ifname) >= 16;
1798
1799 my $vhostparam = '';
6f0cb675 1800 if (is_native($arch)) {
db70021b 1801 $vhostparam = ',vhost=on' if kernel_has_vhost_net() && $net->{model} eq 'virtio';
6f0cb675 1802 }
cc4d6182
DA
1803
1804 my $vmname = $conf->{name} || "vm$vmid";
1805
a9410357 1806 my $netdev = "";
208ba94e 1807 my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
a9410357 1808
cc4d6182 1809 if ($net->{bridge}) {
4df98f2f
TL
1810 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1811 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
cc4d6182 1812 } else {
a9410357 1813 $netdev = "type=user,id=$netid,hostname=$vmname";
cc4d6182 1814 }
a9410357
AD
1815
1816 $netdev .= ",queues=$net->{queues}" if ($net->{queues} && $net->{model} eq 'virtio');
1817
1818 return $netdev;
cc4d6182 1819}
1e3baf05 1820
55655ebc
DC
1821my $vga_map = {
1822 'cirrus' => 'cirrus-vga',
1823 'std' => 'VGA',
1824 'vmware' => 'vmware-svga',
1825 'virtio' => 'virtio-vga',
6f070e39 1826 'virtio-gl' => 'virtio-vga-gl',
55655ebc
DC
1827};
1828
1829sub print_vga_device {
2ea5fb7e 1830 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
55655ebc
DC
1831
1832 my $type = $vga_map->{$vga->{type}};
86c9fafe 1833 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
d559309f
WB
1834 $type = 'virtio-gpu';
1835 }
55655ebc 1836 my $vgamem_mb = $vga->{memory};
6021c7a5
AL
1837
1838 my $max_outputs = '';
55655ebc
DC
1839 if ($qxlnum) {
1840 $type = $id ? 'qxl' : 'qxl-vga';
6021c7a5 1841
c5a4c92c 1842 if (!$conf->{ostype} || $conf->{ostype} =~ m/^(?:l\d\d)|(?:other)$/) {
6021c7a5 1843 # set max outputs so linux can have up to 4 qxl displays with one device
2ea5fb7e 1844 if (min_version($machine_version, 4, 1)) {
9e8976ea
TL
1845 $max_outputs = ",max_outputs=4";
1846 }
6021c7a5 1847 }
55655ebc 1848 }
6021c7a5 1849
55655ebc
DC
1850 die "no devicetype for $vga->{type}\n" if !$type;
1851
1852 my $memory = "";
1853 if ($vgamem_mb) {
6f070e39 1854 if ($vga->{type} =~ /^virtio/) {
55655ebc
DC
1855 my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
1856 $memory = ",max_hostmem=$bytes";
1857 } elsif ($qxlnum) {
1858 # from https://www.spice-space.org/multiple-monitors.html
1859 $memory = ",vgamem_mb=$vga->{memory}";
1860 my $ram = $vgamem_mb * 4;
1861 my $vram = $vgamem_mb * 2;
1862 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1863 } else {
1864 $memory = ",vgamem_mb=$vga->{memory}";
1865 }
1866 } elsif ($qxlnum && $id) {
1867 $memory = ",ram_size=67108864,vram_size=33554432";
1868 }
1869
789fe8e8
AL
1870 my $edidoff = "";
1871 if ($type eq 'VGA' && windows_version($conf->{ostype})) {
b5d32c6b 1872 $edidoff=",edid=off" if (!defined($conf->{bios}) || $conf->{bios} ne 'ovmf');
789fe8e8
AL
1873 }
1874
3392d6ca 1875 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
55655ebc
DC
1876 my $vgaid = "vga" . ($id // '');
1877 my $pciaddr;
1878 if ($q35 && $vgaid eq 'vga') {
daadd5a4 1879 # the first display uses pcie.0 bus on q35 machines
d559309f 1880 $pciaddr = print_pcie_addr($vgaid, $bridges, $arch, $machine);
55655ebc 1881 } else {
d559309f 1882 $pciaddr = print_pci_addr($vgaid, $bridges, $arch, $machine);
55655ebc
DC
1883 }
1884
9f979d9f 1885 if ($vga->{type} eq 'virtio-gl') {
8884a8bf
TL
1886 my $base = '/usr/lib/x86_64-linux-gnu/lib';
1887 die "missing libraries for '$vga->{type}' detected! Please install 'libgl1' and 'libegl1'\n"
1888 if !-e "${base}EGL.so.1" || !-e "${base}GL.so.1";
9f979d9f 1889
8884a8bf
TL
1890 die "no DRM render node detected (/dev/dri/renderD*), no GPU? - needed for '$vga->{type}' display\n"
1891 if !PVE::Tools::dir_glob_regex('/dev/dri/', "renderD.*");
9f979d9f
SI
1892 }
1893
789fe8e8 1894 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
55655ebc
DC
1895}
1896
ffc0d8c7
WB
1897sub parse_number_sets {
1898 my ($set) = @_;
1899 my $res = [];
1900 foreach my $part (split(/;/, $set)) {
1901 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1902 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1903 push @$res, [ $1, $2 ];
2ed5d572 1904 } else {
ffc0d8c7 1905 die "invalid range: $part\n";
2ed5d572
AD
1906 }
1907 }
ffc0d8c7
WB
1908 return $res;
1909}
2ed5d572 1910
ffc0d8c7
WB
1911sub parse_numa {
1912 my ($data) = @_;
1913
4df98f2f 1914 my $res = parse_property_string($numa_fmt, $data);
ffc0d8c7
WB
1915 $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
1916 $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
2ed5d572
AD
1917 return $res;
1918}
1919
1e3baf05
DM
1920# netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1921sub parse_net {
1922 my ($data) = @_;
1923
4df98f2f 1924 my $res = eval { parse_property_string($net_fmt, $data) };
cd9c34d1
WB
1925 if ($@) {
1926 warn $@;
d1c1af4b 1927 return;
1e3baf05 1928 }
b5b99790
WB
1929 if (!defined($res->{macaddr})) {
1930 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
1931 $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
1932 }
0c9a7596
AD
1933 return $res;
1934}
1935
1936# ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1937sub parse_ipconfig {
1938 my ($data) = @_;
1939
4df98f2f 1940 my $res = eval { parse_property_string($ipconfig_fmt, $data) };
0c9a7596
AD
1941 if ($@) {
1942 warn $@;
d1c1af4b 1943 return;
0c9a7596
AD
1944 }
1945
1946 if ($res->{gw} && !$res->{ip}) {
1947 warn 'gateway specified without specifying an IP address';
d1c1af4b 1948 return;
0c9a7596
AD
1949 }
1950 if ($res->{gw6} && !$res->{ip6}) {
1951 warn 'IPv6 gateway specified without specifying an IPv6 address';
d1c1af4b 1952 return;
0c9a7596
AD
1953 }
1954 if ($res->{gw} && $res->{ip} eq 'dhcp') {
1955 warn 'gateway specified together with DHCP';
d1c1af4b 1956 return;
0c9a7596
AD
1957 }
1958 if ($res->{gw6} && $res->{ip6} !~ /^$IPV6RE/) {
1959 # gw6 + auto/dhcp
1960 warn "IPv6 gateway specified together with $res->{ip6} address";
d1c1af4b 1961 return;
0c9a7596
AD
1962 }
1963
1964 if (!$res->{ip} && !$res->{ip6}) {
1965 return { ip => 'dhcp', ip6 => 'dhcp' };
1966 }
1967
1e3baf05
DM
1968 return $res;
1969}
1970
1971sub print_net {
1972 my $net = shift;
1973
cd9c34d1 1974 return PVE::JSONSchema::print_property_string($net, $net_fmt);
1e3baf05
DM
1975}
1976
1977sub add_random_macs {
1978 my ($settings) = @_;
1979
1980 foreach my $opt (keys %$settings) {
1981 next if $opt !~ m/^net(\d+)$/;
1982 my $net = parse_net($settings->{$opt});
1983 next if !$net;
1984 $settings->{$opt} = print_net($net);
1985 }
1986}
1987
055d554d
DM
1988sub vm_is_volid_owner {
1989 my ($storecfg, $vmid, $volid) = @_;
1990
1991 if ($volid !~ m|^/|) {
1992 my ($path, $owner);
1993 eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
1994 if ($owner && ($owner == $vmid)) {
1995 return 1;
1996 }
1997 }
1998
d1c1af4b 1999 return;
055d554d
DM
2000}
2001
055d554d
DM
2002sub vmconfig_register_unused_drive {
2003 my ($storecfg, $vmid, $conf, $drive) = @_;
2004
2d9ddec5
WB
2005 if (drive_is_cloudinit($drive)) {
2006 eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
2007 warn $@ if $@;
2008 } elsif (!drive_is_cdrom($drive)) {
055d554d
DM
2009 my $volid = $drive->{file};
2010 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
8793d495 2011 PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
055d554d
DM
2012 }
2013 }
2014}
2015
1f30ac3a 2016# smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
ff6ffe20 2017my $smbios1_fmt = {
bd27e851
WB
2018 uuid => {
2019 type => 'string',
2020 pattern => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2021 format_description => 'UUID',
52261945 2022 description => "Set SMBIOS1 UUID.",
bd27e851
WB
2023 optional => 1,
2024 },
2025 version => {
2026 type => 'string',
1f30ac3a
CE
2027 pattern => '[A-Za-z0-9+\/]+={0,2}',
2028 format_description => 'Base64 encoded string',
52261945 2029 description => "Set SMBIOS1 version.",
bd27e851
WB
2030 optional => 1,
2031 },
2032 serial => {
2033 type => 'string',
1f30ac3a
CE
2034 pattern => '[A-Za-z0-9+\/]+={0,2}',
2035 format_description => 'Base64 encoded string',
52261945 2036 description => "Set SMBIOS1 serial number.",
bd27e851
WB
2037 optional => 1,
2038 },
2039 manufacturer => {
2040 type => 'string',
1f30ac3a
CE
2041 pattern => '[A-Za-z0-9+\/]+={0,2}',
2042 format_description => 'Base64 encoded string',
52261945 2043 description => "Set SMBIOS1 manufacturer.",
bd27e851
WB
2044 optional => 1,
2045 },
2046 product => {
2047 type => 'string',
1f30ac3a
CE
2048 pattern => '[A-Za-z0-9+\/]+={0,2}',
2049 format_description => 'Base64 encoded string',
52261945 2050 description => "Set SMBIOS1 product ID.",
bd27e851
WB
2051 optional => 1,
2052 },
2053 sku => {
2054 type => 'string',
1f30ac3a
CE
2055 pattern => '[A-Za-z0-9+\/]+={0,2}',
2056 format_description => 'Base64 encoded string',
52261945 2057 description => "Set SMBIOS1 SKU string.",
bd27e851
WB
2058 optional => 1,
2059 },
2060 family => {
2061 type => 'string',
1f30ac3a
CE
2062 pattern => '[A-Za-z0-9+\/]+={0,2}',
2063 format_description => 'Base64 encoded string',
52261945 2064 description => "Set SMBIOS1 family string.",
bd27e851
WB
2065 optional => 1,
2066 },
1f30ac3a
CE
2067 base64 => {
2068 type => 'boolean',
2069 description => 'Flag to indicate that the SMBIOS values are base64 encoded',
2070 optional => 1,
2071 },
2796e7d5
DM
2072};
2073
2796e7d5
DM
2074sub parse_smbios1 {
2075 my ($data) = @_;
2076
4df98f2f 2077 my $res = eval { parse_property_string($smbios1_fmt, $data) };
bd27e851 2078 warn $@ if $@;
2796e7d5
DM
2079 return $res;
2080}
2081
cd11416f
DM
2082sub print_smbios1 {
2083 my ($smbios1) = @_;
ff6ffe20 2084 return PVE::JSONSchema::print_property_string($smbios1, $smbios1_fmt);
cd11416f
DM
2085}
2086
ff6ffe20 2087PVE::JSONSchema::register_format('pve-qm-smbios1', $smbios1_fmt);
2796e7d5 2088
0ea9541d
DM
2089sub parse_watchdog {
2090 my ($value) = @_;
2091
d1c1af4b 2092 return if !$value;
0ea9541d 2093
4df98f2f 2094 my $res = eval { parse_property_string($watchdog_fmt, $value) };
ec3582b5 2095 warn $@ if $@;
0ea9541d
DM
2096 return $res;
2097}
2098
9d66b397 2099sub parse_guest_agent {
a2af1bbe 2100 my ($conf) = @_;
9d66b397 2101
a2af1bbe 2102 return {} if !defined($conf->{agent});
9d66b397 2103
a2af1bbe 2104 my $res = eval { parse_property_string($agent_fmt, $conf->{agent}) };
9d66b397
SI
2105 warn $@ if $@;
2106
2107 # if the agent is disabled ignore the other potentially set properties
2108 return {} if !$res->{enabled};
2109 return $res;
2110}
2111
a2af1bbe
TL
2112sub get_qga_key {
2113 my ($conf, $key) = @_;
2114 return undef if !defined($conf->{agent});
2115
2116 my $agent = parse_guest_agent($conf);
2117 return $agent->{$key};
2118}
2119
55655ebc
DC
2120sub parse_vga {
2121 my ($value) = @_;
2122
2123 return {} if !$value;
4df98f2f 2124 my $res = eval { parse_property_string($vga_fmt, $value) };
55655ebc
DC
2125 warn $@ if $@;
2126 return $res;
2127}
2128
2cf61f33
SR
2129sub parse_rng {
2130 my ($value) = @_;
2131
d1c1af4b 2132 return if !$value;
2cf61f33 2133
4df98f2f 2134 my $res = eval { parse_property_string($rng_fmt, $value) };
2cf61f33
SR
2135 warn $@ if $@;
2136 return $res;
2137}
2138
26b443c8
TL
2139sub parse_meta_info {
2140 my ($value) = @_;
2141
2142 return if !$value;
2143
2144 my $res = eval { parse_property_string($meta_info_fmt, $value) };
2145 warn $@ if $@;
2146 return $res;
2147}
2148
2149sub new_meta_info_string {
2150 my () = @_; # for now do not allow to override any value
2151
2152 return PVE::JSONSchema::print_property_string(
2153 {
af2a1a1c 2154 'creation-qemu' => kvm_user_version(),
26b443c8
TL
2155 ctime => "". int(time()),
2156 },
2157 $meta_info_fmt
2158 );
2159}
2160
cc181036
TL
2161sub qemu_created_version_fixups {
2162 my ($conf, $forcemachine, $kvmver) = @_;
2163
2164 my $meta = parse_meta_info($conf->{meta}) // {};
2165 my $forced_vers = PVE::QemuServer::Machine::extract_version($forcemachine);
2166
2167 # check if we need to apply some handling for VMs that always use the latest machine version but
2168 # had a machine version transition happen that affected HW such that, e.g., an OS config change
2169 # would be required (we do not want to pin machine version for non-windows OS type)
2170 if (
2171 (!defined($conf->{machine}) || $conf->{machine} =~ m/^(?:pc|q35|virt)$/) # non-versioned machine
2172 && (!defined($meta->{'creation-qemu'}) || !min_version($meta->{'creation-qemu'}, 6, 1)) # created before 6.1
2173 && (!$forced_vers || min_version($forced_vers, 6, 1)) # handle snapshot-rollback/migrations
2174 && min_version($kvmver, 6, 1) # only need to apply the change since 6.1
2175 ) {
2176 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
2177 if ($q35 && $conf->{ostype} && $conf->{ostype} eq 'l26') {
2178 # this changed to default-on in Q 6.1 for q35 machines, it will mess with PCI slot view
2179 # and thus with the predictable interface naming of systemd
2180 return ['-global', 'ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off'];
2181 }
2182 }
2183 return;
2184}
2185
1e3baf05
DM
2186PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
2187sub verify_usb_device {
2188 my ($value, $noerr) = @_;
2189
2190 return $value if parse_usb_device($value);
2191
d1c1af4b 2192 return if $noerr;
19672434 2193
1e3baf05
DM
2194 die "unable to parse usb device\n";
2195}
2196
1e3baf05
DM
2197# add JSON properties for create and set function
2198sub json_config_properties {
c1accf9d 2199 my ($prop, $with_disk_alloc) = @_;
1e3baf05 2200
5a08fb9c
TL
2201 my $skip_json_config_opts = {
2202 parent => 1,
2203 snaptime => 1,
2204 vmstate => 1,
2205 runningmachine => 1,
2206 runningcpu => 1,
26b443c8 2207 meta => 1,
5a08fb9c
TL
2208 };
2209
1e3baf05 2210 foreach my $opt (keys %$confdesc) {
5a08fb9c 2211 next if $skip_json_config_opts->{$opt};
c1accf9d
FE
2212
2213 if ($with_disk_alloc && is_valid_drivename($opt)) {
2214 $prop->{$opt} = $PVE::QemuServer::Drive::drivedesc_hash_with_alloc->{$opt};
2215 } else {
2216 $prop->{$opt} = $confdesc->{$opt};
2217 }
1e3baf05
DM
2218 }
2219
2220 return $prop;
2221}
2222
39051ac0
FE
2223# Properties that we can read from an OVF file
2224sub json_ovf_properties {
2225 my $prop = {};
2226
2227 for my $device (PVE::QemuServer::Drive::valid_drive_names()) {
2228 $prop->{$device} = {
2229 type => 'string',
2230 format => 'pve-volume-id-or-absolute-path',
2231 description => "Disk image that gets imported to $device",
2232 optional => 1,
2233 };
2234 }
2235
2236 $prop->{cores} = {
2237 type => 'integer',
2238 description => "The number of CPU cores.",
2239 optional => 1,
2240 };
2241 $prop->{memory} = {
2242 type => 'integer',
2243 description => "Amount of RAM for the VM in MB.",
2244 optional => 1,
2245 };
2246 $prop->{name} = {
2247 type => 'string',
2248 description => "Name of the VM.",
2249 optional => 1,
2250 };
2251
2252 return $prop;
2253}
2254
d41121fd
DM
2255# return copy of $confdesc_cloudinit to generate documentation
2256sub cloudinit_config_properties {
2257
2258 return dclone($confdesc_cloudinit);
2259}
2260
1e3baf05
DM
2261sub check_type {
2262 my ($key, $value) = @_;
2263
2264 die "unknown setting '$key'\n" if !$confdesc->{$key};
2265
2266 my $type = $confdesc->{$key}->{type};
2267
6b64503e 2268 if (!defined($value)) {
1e3baf05
DM
2269 die "got undefined value\n";
2270 }
2271
2272 if ($value =~ m/[\n\r]/) {
2273 die "property contains a line feed\n";
2274 }
2275
2276 if ($type eq 'boolean') {
19672434
DM
2277 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2278 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2279 die "type check ('boolean') failed - got '$value'\n";
1e3baf05
DM
2280 } elsif ($type eq 'integer') {
2281 return int($1) if $value =~ m/^(\d+)$/;
2282 die "type check ('integer') failed - got '$value'\n";
04432191
AD
2283 } elsif ($type eq 'number') {
2284 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2285 die "type check ('number') failed - got '$value'\n";
1e3baf05
DM
2286 } elsif ($type eq 'string') {
2287 if (my $fmt = $confdesc->{$key}->{format}) {
1e3baf05 2288 PVE::JSONSchema::check_format($fmt, $value);
19672434
DM
2289 return $value;
2290 }
1e3baf05 2291 $value =~ s/^\"(.*)\"$/$1/;
19672434 2292 return $value;
1e3baf05
DM
2293 } else {
2294 die "internal error"
2295 }
2296}
2297
1e3baf05 2298sub destroy_vm {
75854662 2299 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
1e3baf05 2300
ffda963f 2301 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2302
ffda963f 2303 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 2304
5e67a2d2
DC
2305 if ($conf->{template}) {
2306 # check if any base image is still used by a linked clone
3ab0f925 2307 PVE::QemuConfig->foreach_volume_full($conf, { include_unused => 1 }, sub {
5e67a2d2 2308 my ($ds, $drive) = @_;
5e67a2d2
DC
2309 return if drive_is_cdrom($drive);
2310
2311 my $volid = $drive->{file};
5e67a2d2
DC
2312 return if !$volid || $volid =~ m|^/|;
2313
2314 die "base volume '$volid' is still in use by linked cloned\n"
2315 if PVE::Storage::volume_is_base_and_used($storecfg, $volid);
2316
2317 });
2318 }
2319
3e07c6d5 2320 my $volids = {};
ba1a1984 2321 my $remove_owned_drive = sub {
1e3baf05 2322 my ($ds, $drive) = @_;
9c52f5ed 2323 return if drive_is_cdrom($drive, 1);
1e3baf05
DM
2324
2325 my $volid = $drive->{file};
ff1a2432 2326 return if !$volid || $volid =~ m|^/|;
3e07c6d5 2327 return if $volids->{$volid};
1e3baf05 2328
6b64503e 2329 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
ff1a2432 2330 return if !$path || !$owner || ($owner != $vmid);
1e3baf05 2331
3e07c6d5 2332 $volids->{$volid} = 1;
a2f50f01 2333 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
31b52247 2334 warn "Could not remove disk '$volid', check manually: $@" if $@;
ba1a1984
FE
2335 };
2336
2337 # only remove disks owned by this VM (referenced in the config)
2338 my $include_opts = {
2339 include_unused => 1,
2340 extra_keys => ['vmstate'],
2341 };
2342 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2343
2344 for my $snap (values %{$conf->{snapshots}}) {
2345 next if !defined($snap->{vmstate});
2346 my $drive = PVE::QemuConfig->parse_volume('vmstate', $snap->{vmstate}, 1);
2347 next if !defined($drive);
2348 $remove_owned_drive->('vmstate', $drive);
2349 }
19672434 2350
3e07c6d5
FG
2351 PVE::QemuConfig->foreach_volume_full($conf->{pending}, $include_opts, $remove_owned_drive);
2352
75854662 2353 if ($purge_unreferenced) { # also remove unreferenced disk
d0ff75d9 2354 my $vmdisks = PVE::Storage::vdisk_list($storecfg, undef, $vmid, undef, 'images');
75854662
TL
2355 PVE::Storage::foreach_volid($vmdisks, sub {
2356 my ($volid, $sid, $volname, $d) = @_;
2357 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
2358 warn $@ if $@;
2359 });
2360 }
dfda979e 2361
b04ea584 2362 if (defined $replacement_conf) {
8baf8bc7 2363 PVE::QemuConfig->write_config($vmid, $replacement_conf);
dfda979e
DJ
2364 } else {
2365 PVE::QemuConfig->destroy_config($vmid);
2366 }
1e3baf05
DM
2367}
2368
1e3baf05 2369sub parse_vm_config {
ad5812d8 2370 my ($filename, $raw, $strict) = @_;
1e3baf05 2371
d1c1af4b 2372 return if !defined($raw);
1e3baf05 2373
554ac7e7 2374 my $res = {
fc1ddcdc 2375 digest => Digest::SHA::sha1_hex($raw),
0d18dcfc 2376 snapshots => {},
0d732d16 2377 pending => {},
554ac7e7 2378 };
1e3baf05 2379
ad5812d8
FG
2380 my $handle_error = sub {
2381 my ($msg) = @_;
2382
2383 if ($strict) {
2384 die $msg;
2385 } else {
2386 warn $msg;
2387 }
2388 };
2389
19672434 2390 $filename =~ m|/qemu-server/(\d+)\.conf$|
1e3baf05
DM
2391 || die "got strange filename '$filename'";
2392
2393 my $vmid = $1;
2394
0d18dcfc 2395 my $conf = $res;
b0ec896e 2396 my $descr;
e297c490 2397 my $section = '';
0581fe4f 2398
0d18dcfc
DM
2399 my @lines = split(/\n/, $raw);
2400 foreach my $line (@lines) {
1e3baf05 2401 next if $line =~ m/^\s*$/;
be190583 2402
eab09f4e 2403 if ($line =~ m/^\[PENDING\]\s*$/i) {
e297c490 2404 $section = 'pending';
b0ec896e
DM
2405 if (defined($descr)) {
2406 $descr =~ s/\s+$//;
2407 $conf->{description} = $descr;
2408 }
2409 $descr = undef;
e297c490 2410 $conf = $res->{$section} = {};
eab09f4e
AD
2411 next;
2412
0d732d16 2413 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
e297c490 2414 $section = $1;
b0ec896e
DM
2415 if (defined($descr)) {
2416 $descr =~ s/\s+$//;
2417 $conf->{description} = $descr;
2418 }
2419 $descr = undef;
e297c490 2420 $conf = $res->{snapshots}->{$section} = {};
0d18dcfc
DM
2421 next;
2422 }
1e3baf05 2423
d1e7b922 2424 if ($line =~ m/^\#(.*)$/) {
b0ec896e 2425 $descr = '' if !defined($descr);
0581fe4f
DM
2426 $descr .= PVE::Tools::decode_text($1) . "\n";
2427 next;
2428 }
2429
1e3baf05 2430 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
b0ec896e 2431 $descr = '' if !defined($descr);
0581fe4f 2432 $descr .= PVE::Tools::decode_text($2);
0d18dcfc
DM
2433 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2434 $conf->{snapstate} = $1;
1e3baf05
DM
2435 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2436 my $key = $1;
2437 my $value = $2;
0d18dcfc 2438 $conf->{$key} = $value;
ef824322 2439 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
e297c490 2440 my $value = $1;
ef824322
DM
2441 if ($section eq 'pending') {
2442 $conf->{delete} = $value; # we parse this later
2443 } else {
ad5812d8 2444 $handle_error->("vm $vmid - property 'delete' is only allowed in [PENDING]\n");
eab09f4e 2445 }
15cf7698 2446 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
1e3baf05
DM
2447 my $key = $1;
2448 my $value = $2;
2449 eval { $value = check_type($key, $value); };
2450 if ($@) {
ad5812d8 2451 $handle_error->("vm $vmid - unable to parse value of '$key' - $@");
1e3baf05 2452 } else {
b799312f 2453 $key = 'ide2' if $key eq 'cdrom';
1e3baf05 2454 my $fmt = $confdesc->{$key}->{format};
b799312f 2455 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
1e3baf05
DM
2456 my $v = parse_drive($key, $value);
2457 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
2458 $v->{file} = $volid;
71c58bb7 2459 $value = print_drive($v);
1e3baf05 2460 } else {
ad5812d8 2461 $handle_error->("vm $vmid - unable to parse value of '$key'\n");
1e3baf05
DM
2462 next;
2463 }
2464 }
2465
b799312f 2466 $conf->{$key} = $value;
1e3baf05 2467 }
f8d2a1ce 2468 } else {
ad5812d8 2469 $handle_error->("vm $vmid - unable to parse config: $line\n");
1e3baf05
DM
2470 }
2471 }
2472
b0ec896e
DM
2473 if (defined($descr)) {
2474 $descr =~ s/\s+$//;
2475 $conf->{description} = $descr;
2476 }
0d18dcfc 2477 delete $res->{snapstate}; # just to be sure
1e3baf05
DM
2478
2479 return $res;
2480}
2481
1858638f
DM
2482sub write_vm_config {
2483 my ($filename, $conf) = @_;
1e3baf05 2484
0d18dcfc
DM
2485 delete $conf->{snapstate}; # just to be sure
2486
1858638f
DM
2487 if ($conf->{cdrom}) {
2488 die "option ide2 conflicts with cdrom\n" if $conf->{ide2};
2489 $conf->{ide2} = $conf->{cdrom};
2490 delete $conf->{cdrom};
2491 }
1e3baf05
DM
2492
2493 # we do not use 'smp' any longer
1858638f
DM
2494 if ($conf->{sockets}) {
2495 delete $conf->{smp};
2496 } elsif ($conf->{smp}) {
2497 $conf->{sockets} = $conf->{smp};
2498 delete $conf->{cores};
2499 delete $conf->{smp};
1e3baf05
DM
2500 }
2501
ee2f90b1 2502 my $used_volids = {};
0d18dcfc 2503
ee2f90b1 2504 my $cleanup_config = sub {
ef824322 2505 my ($cref, $pending, $snapname) = @_;
1858638f 2506
ee2f90b1
DM
2507 foreach my $key (keys %$cref) {
2508 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
ef824322 2509 $key eq 'snapstate' || $key eq 'pending';
ee2f90b1 2510 my $value = $cref->{$key};
ef824322
DM
2511 if ($key eq 'delete') {
2512 die "propertry 'delete' is only allowed in [PENDING]\n"
2513 if !$pending;
2514 # fixme: check syntax?
2515 next;
2516 }
ee2f90b1
DM
2517 eval { $value = check_type($key, $value); };
2518 die "unable to parse value of '$key' - $@" if $@;
1858638f 2519
ee2f90b1
DM
2520 $cref->{$key} = $value;
2521
74479ee9 2522 if (!$snapname && is_valid_drivename($key)) {
ed221350 2523 my $drive = parse_drive($key, $value);
ee2f90b1
DM
2524 $used_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
2525 }
1e3baf05 2526 }
ee2f90b1
DM
2527 };
2528
2529 &$cleanup_config($conf);
ef824322
DM
2530
2531 &$cleanup_config($conf->{pending}, 1);
2532
ee2f90b1 2533 foreach my $snapname (keys %{$conf->{snapshots}}) {
15c6e277 2534 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
ef824322 2535 &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
1e3baf05
DM
2536 }
2537
1858638f
DM
2538 # remove 'unusedX' settings if we re-add a volume
2539 foreach my $key (keys %$conf) {
2540 my $value = $conf->{$key};
ee2f90b1 2541 if ($key =~ m/^unused/ && $used_volids->{$value}) {
1858638f 2542 delete $conf->{$key};
1e3baf05 2543 }
1858638f 2544 }
be190583 2545
0d18dcfc 2546 my $generate_raw_config = sub {
b0ec896e 2547 my ($conf, $pending) = @_;
0581fe4f 2548
0d18dcfc
DM
2549 my $raw = '';
2550
2551 # add description as comment to top of file
b0ec896e
DM
2552 if (defined(my $descr = $conf->{description})) {
2553 if ($descr) {
2554 foreach my $cl (split(/\n/, $descr)) {
2555 $raw .= '#' . PVE::Tools::encode_text($cl) . "\n";
2556 }
2557 } else {
2558 $raw .= "#\n" if $pending;
2559 }
0d18dcfc
DM
2560 }
2561
2562 foreach my $key (sort keys %$conf) {
4df98f2f 2563 next if $key =~ /^(digest|description|pending|snapshots)$/;
0d18dcfc
DM
2564 $raw .= "$key: $conf->{$key}\n";
2565 }
2566 return $raw;
2567 };
0581fe4f 2568
0d18dcfc 2569 my $raw = &$generate_raw_config($conf);
ef824322
DM
2570
2571 if (scalar(keys %{$conf->{pending}})){
2572 $raw .= "\n[PENDING]\n";
b0ec896e 2573 $raw .= &$generate_raw_config($conf->{pending}, 1);
ef824322
DM
2574 }
2575
0d18dcfc
DM
2576 foreach my $snapname (sort keys %{$conf->{snapshots}}) {
2577 $raw .= "\n[$snapname]\n";
2578 $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
1858638f 2579 }
1e3baf05 2580
1858638f
DM
2581 return $raw;
2582}
1e3baf05 2583
19672434 2584sub load_defaults {
1e3baf05
DM
2585
2586 my $res = {};
2587
2588 # we use static defaults from our JSON schema configuration
2589 foreach my $key (keys %$confdesc) {
2590 if (defined(my $default = $confdesc->{$key}->{default})) {
2591 $res->{$key} = $default;
2592 }
2593 }
19672434 2594
1e3baf05
DM
2595 return $res;
2596}
2597
2598sub config_list {
2599 my $vmlist = PVE::Cluster::get_vmlist();
2600 my $res = {};
2601 return $res if !$vmlist || !$vmlist->{ids};
2602 my $ids = $vmlist->{ids};
38277afc 2603 my $nodename = nodename();
1e3baf05 2604
1e3baf05
DM
2605 foreach my $vmid (keys %$ids) {
2606 my $d = $ids->{$vmid};
2607 next if !$d->{node} || $d->{node} ne $nodename;
5ee957cc 2608 next if !$d->{type} || $d->{type} ne 'qemu';
1e3baf05
DM
2609 $res->{$vmid}->{exists} = 1;
2610 }
2611 return $res;
2612}
2613
64e13401
DM
2614# test if VM uses local resources (to prevent migration)
2615sub check_local_resources {
2616 my ($conf, $noerr) = @_;
2617
ca6abacf 2618 my @loc_res = ();
19672434 2619
ca6abacf
TM
2620 push @loc_res, "hostusb" if $conf->{hostusb}; # old syntax
2621 push @loc_res, "hostpci" if $conf->{hostpci}; # old syntax
64e13401 2622
ca6abacf 2623 push @loc_res, "ivshmem" if $conf->{ivshmem};
6dbcb073 2624
0d29ab3b 2625 foreach my $k (keys %$conf) {
a9ce7583 2626 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
d44712fc
EK
2627 # sockets are safe: they will recreated be on the target side post-migrate
2628 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
ca6abacf 2629 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
64e13401
DM
2630 }
2631
ca6abacf 2632 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
64e13401 2633
ca6abacf 2634 return \@loc_res;
64e13401
DM
2635}
2636
719893a9 2637# check if used storages are available on all nodes (use by migrate)
47152e2e
DM
2638sub check_storage_availability {
2639 my ($storecfg, $conf, $node) = @_;
2640
912792e2 2641 PVE::QemuConfig->foreach_volume($conf, sub {
47152e2e
DM
2642 my ($ds, $drive) = @_;
2643
2644 my $volid = $drive->{file};
2645 return if !$volid;
2646
2647 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2648 return if !$sid;
2649
2650 # check if storage is available on both nodes
0d2db084
FE
2651 my $scfg = PVE::Storage::storage_check_enabled($storecfg, $sid);
2652 PVE::Storage::storage_check_enabled($storecfg, $sid, $node);
24b84b47 2653
3148f0b0
TL
2654 my ($vtype) = PVE::Storage::parse_volname($storecfg, $volid);
2655
2656 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2657 if !$scfg->{content}->{$vtype};
47152e2e
DM
2658 });
2659}
2660
719893a9
DM
2661# list nodes where all VM images are available (used by has_feature API)
2662sub shared_nodes {
2663 my ($conf, $storecfg) = @_;
2664
2665 my $nodelist = PVE::Cluster::get_nodelist();
2666 my $nodehash = { map { $_ => 1 } @$nodelist };
38277afc 2667 my $nodename = nodename();
be190583 2668
912792e2 2669 PVE::QemuConfig->foreach_volume($conf, sub {
719893a9
DM
2670 my ($ds, $drive) = @_;
2671
2672 my $volid = $drive->{file};
2673 return if !$volid;
2674
2675 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2676 if ($storeid) {
2677 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2678 if ($scfg->{disable}) {
2679 $nodehash = {};
2680 } elsif (my $avail = $scfg->{nodes}) {
2681 foreach my $node (keys %$nodehash) {
2682 delete $nodehash->{$node} if !$avail->{$node};
2683 }
2684 } elsif (!$scfg->{shared}) {
2685 foreach my $node (keys %$nodehash) {
2686 delete $nodehash->{$node} if $node ne $nodename
2687 }
2688 }
2689 }
2690 });
2691
2692 return $nodehash
2693}
2694
f25852c2
TM
2695sub check_local_storage_availability {
2696 my ($conf, $storecfg) = @_;
2697
2698 my $nodelist = PVE::Cluster::get_nodelist();
2699 my $nodehash = { map { $_ => {} } @$nodelist };
2700
912792e2 2701 PVE::QemuConfig->foreach_volume($conf, sub {
f25852c2
TM
2702 my ($ds, $drive) = @_;
2703
2704 my $volid = $drive->{file};
2705 return if !$volid;
2706
2707 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2708 if ($storeid) {
2709 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2710
2711 if ($scfg->{disable}) {
2712 foreach my $node (keys %$nodehash) {
32075a2c 2713 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2714 }
2715 } elsif (my $avail = $scfg->{nodes}) {
2716 foreach my $node (keys %$nodehash) {
2717 if (!$avail->{$node}) {
32075a2c 2718 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2719 }
2720 }
2721 }
2722 }
2723 });
2724
32075a2c
TL
2725 foreach my $node (values %$nodehash) {
2726 if (my $unavail = $node->{unavailable_storages}) {
2727 $node->{unavailable_storages} = [ sort keys %$unavail ];
2728 }
2729 }
2730
f25852c2
TM
2731 return $nodehash
2732}
2733
babf613a 2734# Compat only, use assert_config_exists_on_node and vm_running_locally where possible
1e3baf05 2735sub check_running {
7e8dcf2c 2736 my ($vmid, $nocheck, $node) = @_;
1e3baf05 2737
babf613a
SR
2738 PVE::QemuConfig::assert_config_exists_on_node($vmid, $node) if !$nocheck;
2739 return PVE::QemuServer::Helpers::vm_running_locally($vmid);
1e3baf05
DM
2740}
2741
2742sub vzlist {
19672434 2743
1e3baf05
DM
2744 my $vzlist = config_list();
2745
d036e418 2746 my $fd = IO::Dir->new($PVE::QemuServer::Helpers::var_run_tmpdir) || return $vzlist;
1e3baf05 2747
19672434 2748 while (defined(my $de = $fd->read)) {
1e3baf05
DM
2749 next if $de !~ m/^(\d+)\.pid$/;
2750 my $vmid = $1;
6b64503e
DM
2751 next if !defined($vzlist->{$vmid});
2752 if (my $pid = check_running($vmid)) {
1e3baf05
DM
2753 $vzlist->{$vmid}->{pid} = $pid;
2754 }
2755 }
2756
2757 return $vzlist;
2758}
2759
b1a70cab
DM
2760our $vmstatus_return_properties = {
2761 vmid => get_standard_option('pve-vmid'),
2762 status => {
2763 description => "Qemu process status.",
2764 type => 'string',
2765 enum => ['stopped', 'running'],
2766 },
2767 maxmem => {
2768 description => "Maximum memory in bytes.",
2769 type => 'integer',
2770 optional => 1,
2771 renderer => 'bytes',
2772 },
2773 maxdisk => {
2774 description => "Root disk size in bytes.",
2775 type => 'integer',
2776 optional => 1,
2777 renderer => 'bytes',
2778 },
2779 name => {
2780 description => "VM name.",
2781 type => 'string',
2782 optional => 1,
2783 },
2784 qmpstatus => {
2785 description => "Qemu QMP agent status.",
2786 type => 'string',
2787 optional => 1,
2788 },
2789 pid => {
2790 description => "PID of running qemu process.",
2791 type => 'integer',
2792 optional => 1,
2793 },
2794 uptime => {
2795 description => "Uptime.",
2796 type => 'integer',
2797 optional => 1,
2798 renderer => 'duration',
2799 },
2800 cpus => {
2801 description => "Maximum usable CPUs.",
2802 type => 'number',
2803 optional => 1,
2804 },
e6ed61b4 2805 lock => {
11efdfa5 2806 description => "The current config lock, if any.",
e6ed61b4
DC
2807 type => 'string',
2808 optional => 1,
b8e7068a
DC
2809 },
2810 tags => {
2811 description => "The current configured tags, if any",
2812 type => 'string',
2813 optional => 1,
2814 },
949112c3
FE
2815 'running-machine' => {
2816 description => "The currently running machine type (if running).",
2817 type => 'string',
2818 optional => 1,
2819 },
2820 'running-qemu' => {
2821 description => "The currently running QEMU version (if running).",
2822 type => 'string',
2823 optional => 1,
2824 },
b1a70cab
DM
2825};
2826
1e3baf05
DM
2827my $last_proc_pid_stat;
2828
03a33f30
DM
2829# get VM status information
2830# This must be fast and should not block ($full == false)
2831# We only query KVM using QMP if $full == true (this can be slow)
1e3baf05 2832sub vmstatus {
03a33f30 2833 my ($opt_vmid, $full) = @_;
1e3baf05
DM
2834
2835 my $res = {};
2836
19672434 2837 my $storecfg = PVE::Storage::config();
1e3baf05
DM
2838
2839 my $list = vzlist();
3618ee99
EK
2840 my $defaults = load_defaults();
2841
694fcad4 2842 my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
1e3baf05 2843
ae4915a2
DM
2844 my $cpucount = $cpuinfo->{cpus} || 1;
2845
1e3baf05
DM
2846 foreach my $vmid (keys %$list) {
2847 next if $opt_vmid && ($vmid ne $opt_vmid);
2848
9f78b695 2849 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2850
ad2cad72 2851 my $d = { vmid => int($vmid) };
8a0addab 2852 $d->{pid} = int($list->{$vmid}->{pid}) if $list->{$vmid}->{pid};
1e3baf05
DM
2853
2854 # fixme: better status?
2855 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
2856
776c5f50 2857 my $size = PVE::QemuServer::Drive::bootdisk_size($storecfg, $conf);
af990afe
DM
2858 if (defined($size)) {
2859 $d->{disk} = 0; # no info available
1e3baf05
DM
2860 $d->{maxdisk} = $size;
2861 } else {
2862 $d->{disk} = 0;
2863 $d->{maxdisk} = 0;
2864 }
2865
3618ee99
EK
2866 $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
2867 * ($conf->{cores} || $defaults->{cores});
ae4915a2 2868 $d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
d7c8364b 2869 $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
ae4915a2 2870
1e3baf05 2871 $d->{name} = $conf->{name} || "VM $vmid";
3618ee99
EK
2872 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
2873 : $defaults->{memory}*(1024*1024);
1e3baf05 2874
8b1accf7 2875 if ($conf->{balloon}) {
4bdb0514 2876 $d->{balloon_min} = $conf->{balloon}*(1024*1024);
3618ee99
EK
2877 $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
2878 : $defaults->{shares};
8b1accf7
DM
2879 }
2880
1e3baf05
DM
2881 $d->{uptime} = 0;
2882 $d->{cpu} = 0;
1e3baf05
DM
2883 $d->{mem} = 0;
2884
2885 $d->{netout} = 0;
2886 $d->{netin} = 0;
2887
2888 $d->{diskread} = 0;
2889 $d->{diskwrite} = 0;
2890
75a2a423 2891 $d->{template} = 1 if PVE::QemuConfig->is_template($conf);
4d8c851b 2892
8107b378 2893 $d->{serial} = 1 if conf_has_serial($conf);
e6ed61b4 2894 $d->{lock} = $conf->{lock} if $conf->{lock};
b8e7068a 2895 $d->{tags} = $conf->{tags} if defined($conf->{tags});
8107b378 2896
1e3baf05
DM
2897 $res->{$vmid} = $d;
2898 }
2899
2900 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
2901 foreach my $dev (keys %$netdev) {
2902 next if $dev !~ m/^tap([1-9]\d*)i/;
2903 my $vmid = $1;
2904 my $d = $res->{$vmid};
2905 next if !$d;
19672434 2906
1e3baf05
DM
2907 $d->{netout} += $netdev->{$dev}->{receive};
2908 $d->{netin} += $netdev->{$dev}->{transmit};
604ea644
AD
2909
2910 if ($full) {
ad2cad72
FE
2911 $d->{nics}->{$dev}->{netout} = int($netdev->{$dev}->{receive});
2912 $d->{nics}->{$dev}->{netin} = int($netdev->{$dev}->{transmit});
604ea644
AD
2913 }
2914
1e3baf05
DM
2915 }
2916
1e3baf05
DM
2917 my $ctime = gettimeofday;
2918
2919 foreach my $vmid (keys %$list) {
2920
2921 my $d = $res->{$vmid};
2922 my $pid = $d->{pid};
2923 next if !$pid;
2924
694fcad4
DM
2925 my $pstat = PVE::ProcFSTools::read_proc_pid_stat($pid);
2926 next if !$pstat; # not running
19672434 2927
694fcad4 2928 my $used = $pstat->{utime} + $pstat->{stime};
1e3baf05 2929
694fcad4 2930 $d->{uptime} = int(($uptime - $pstat->{starttime})/$cpuinfo->{user_hz});
1e3baf05 2931
694fcad4 2932 if ($pstat->{vsize}) {
6b64503e 2933 $d->{mem} = int(($pstat->{rss}/$pstat->{vsize})*$d->{maxmem});
1e3baf05
DM
2934 }
2935
2936 my $old = $last_proc_pid_stat->{$pid};
2937 if (!$old) {
19672434
DM
2938 $last_proc_pid_stat->{$pid} = {
2939 time => $ctime,
1e3baf05
DM
2940 used => $used,
2941 cpu => 0,
1e3baf05
DM
2942 };
2943 next;
2944 }
2945
7f0b5beb 2946 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz};
1e3baf05
DM
2947
2948 if ($dtime > 1000) {
2949 my $dutime = $used - $old->{used};
2950
ae4915a2 2951 $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
1e3baf05 2952 $last_proc_pid_stat->{$pid} = {
19672434 2953 time => $ctime,
1e3baf05
DM
2954 used => $used,
2955 cpu => $d->{cpu},
1e3baf05
DM
2956 };
2957 } else {
2958 $d->{cpu} = $old->{cpu};
1e3baf05
DM
2959 }
2960 }
2961
f5eb281a 2962 return $res if !$full;
03a33f30
DM
2963
2964 my $qmpclient = PVE::QMPClient->new();
2965
64e7fcf2
DM
2966 my $ballooncb = sub {
2967 my ($vmid, $resp) = @_;
2968
2969 my $info = $resp->{'return'};
38babf81
DM
2970 return if !$info->{max_mem};
2971
64e7fcf2
DM
2972 my $d = $res->{$vmid};
2973
38babf81
DM
2974 # use memory assigned to VM
2975 $d->{maxmem} = $info->{max_mem};
2976 $d->{balloon} = $info->{actual};
2977
2978 if (defined($info->{total_mem}) && defined($info->{free_mem})) {
2979 $d->{mem} = $info->{total_mem} - $info->{free_mem};
2980 $d->{freemem} = $info->{free_mem};
64e7fcf2
DM
2981 }
2982
604ea644 2983 $d->{ballooninfo} = $info;
64e7fcf2
DM
2984 };
2985
03a33f30
DM
2986 my $blockstatscb = sub {
2987 my ($vmid, $resp) = @_;
2988 my $data = $resp->{'return'} || [];
2989 my $totalrdbytes = 0;
2990 my $totalwrbytes = 0;
604ea644 2991
03a33f30
DM
2992 for my $blockstat (@$data) {
2993 $totalrdbytes = $totalrdbytes + $blockstat->{stats}->{rd_bytes};
2994 $totalwrbytes = $totalwrbytes + $blockstat->{stats}->{wr_bytes};
604ea644
AD
2995
2996 $blockstat->{device} =~ s/drive-//;
2997 $res->{$vmid}->{blockstat}->{$blockstat->{device}} = $blockstat->{stats};
03a33f30
DM
2998 }
2999 $res->{$vmid}->{diskread} = $totalrdbytes;
3000 $res->{$vmid}->{diskwrite} = $totalwrbytes;
3001 };
3002
949112c3
FE
3003 my $machinecb = sub {
3004 my ($vmid, $resp) = @_;
3005 my $data = $resp->{'return'} || [];
3006
3007 $res->{$vmid}->{'running-machine'} =
3008 PVE::QemuServer::Machine::current_from_query_machines($data);
3009 };
3010
3011 my $versioncb = sub {
3012 my ($vmid, $resp) = @_;
3013 my $data = $resp->{'return'} // {};
3014 my $version = 'unknown';
3015
3016 if (my $v = $data->{qemu}) {
3017 $version = $v->{major} . "." . $v->{minor} . "." . $v->{micro};
3018 }
3019
3020 $res->{$vmid}->{'running-qemu'} = $version;
3021 };
3022
03a33f30
DM
3023 my $statuscb = sub {
3024 my ($vmid, $resp) = @_;
64e7fcf2 3025
03a33f30 3026 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
949112c3
FE
3027 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
3028 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
64e7fcf2
DM
3029 # this fails if ballon driver is not loaded, so this must be
3030 # the last commnand (following command are aborted if this fails).
38babf81 3031 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
03a33f30
DM
3032
3033 my $status = 'unknown';
3034 if (!defined($status = $resp->{'return'}->{status})) {
3035 warn "unable to get VM status\n";
3036 return;
3037 }
3038
3039 $res->{$vmid}->{qmpstatus} = $resp->{'return'}->{status};
3040 };
3041
3042 foreach my $vmid (keys %$list) {
3043 next if $opt_vmid && ($vmid ne $opt_vmid);
3044 next if !$res->{$vmid}->{pid}; # not running
3045 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3046 }
3047
b017fbda 3048 $qmpclient->queue_execute(undef, 2);
03a33f30 3049
6891fd70
SR
3050 foreach my $vmid (keys %$list) {
3051 next if $opt_vmid && ($vmid ne $opt_vmid);
e5b18771
FG
3052 next if !$res->{$vmid}->{pid}; #not running
3053
6891fd70
SR
3054 # we can't use the $qmpclient since it might have already aborted on
3055 # 'query-balloon', but this might also fail for older versions...
3056 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
3057 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
3058 }
3059
03a33f30
DM
3060 foreach my $vmid (keys %$list) {
3061 next if $opt_vmid && ($vmid ne $opt_vmid);
3062 $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
3063 }
3064
1e3baf05
DM
3065 return $res;
3066}
3067
8107b378
DC
3068sub conf_has_serial {
3069 my ($conf) = @_;
3070
3071 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3072 if ($conf->{"serial$i"}) {
3073 return 1;
3074 }
3075 }
3076
3077 return 0;
3078}
3079
d5535a00
TL
3080sub conf_has_audio {
3081 my ($conf, $id) = @_;
3082
3083 $id //= 0;
3084 my $audio = $conf->{"audio$id"};
d1c1af4b 3085 return if !defined($audio);
d5535a00 3086
4df98f2f 3087 my $audioproperties = parse_property_string($audio_fmt, $audio);
d5535a00
TL
3088 my $audiodriver = $audioproperties->{driver} // 'spice';
3089
3090 return {
3091 dev => $audioproperties->{device},
b0f96836 3092 dev_id => "audiodev$id",
d5535a00
TL
3093 backend => $audiodriver,
3094 backend_id => "$audiodriver-backend${id}",
3095 };
3096}
3097
b01de199 3098sub audio_devs {
1cc5ed1b 3099 my ($audio, $audiopciaddr, $machine_version) = @_;
b01de199
TL
3100
3101 my $devs = [];
3102
3103 my $id = $audio->{dev_id};
1cc5ed1b
AL
3104 my $audiodev = "";
3105 if (min_version($machine_version, 4, 2)) {
3106 $audiodev = ",audiodev=$audio->{backend_id}";
3107 }
b01de199
TL
3108
3109 if ($audio->{dev} eq 'AC97') {
1cc5ed1b 3110 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
b01de199
TL
3111 } elsif ($audio->{dev} =~ /intel\-hda$/) {
3112 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
1cc5ed1b
AL
3113 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
3114 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
b01de199
TL
3115 } else {
3116 die "unkown audio device '$audio->{dev}', implement me!";
3117 }
3118
3119 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
3120
3121 return $devs;
3122}
3123
f9dde219
SR
3124sub get_tpm_paths {
3125 my ($vmid) = @_;
3126 return {
3127 socket => "/var/run/qemu-server/$vmid.swtpm",
3128 pid => "/var/run/qemu-server/$vmid.swtpm.pid",
3129 };
3130}
3131
3132sub add_tpm_device {
3133 my ($vmid, $devices, $conf) = @_;
3134
3135 return if !$conf->{tpmstate0};
3136
3137 my $paths = get_tpm_paths($vmid);
3138
3139 push @$devices, "-chardev", "socket,id=tpmchar,path=$paths->{socket}";
3140 push @$devices, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar";
3141 push @$devices, "-device", "tpm-tis,tpmdev=tpmdev";
3142}
3143
3144sub start_swtpm {
3145 my ($storecfg, $vmid, $tpmdrive, $migration) = @_;
3146
3147 return if !$tpmdrive;
3148
3149 my $state;
3150 my $tpm = parse_drive("tpmstate0", $tpmdrive);
3151 my ($storeid, $volname) = PVE::Storage::parse_volume_id($tpm->{file}, 1);
3152 if ($storeid) {
3153 $state = PVE::Storage::map_volume($storecfg, $tpm->{file});
3154 } else {
3155 $state = $tpm->{file};
3156 }
3157
3158 my $paths = get_tpm_paths($vmid);
3159
3160 # during migration, we will get state from remote
3161 #
3162 if (!$migration) {
3163 # run swtpm_setup to create a new TPM state if it doesn't exist yet
3164 my $setup_cmd = [
3165 "swtpm_setup",
3166 "--tpmstate",
3167 "file://$state",
3168 "--createek",
3169 "--create-ek-cert",
3170 "--create-platform-cert",
3171 "--lock-nvram",
3172 "--config",
3173 "/etc/swtpm_setup.conf", # do not use XDG configs
3174 "--runas",
3175 "0", # force creation as root, error if not possible
3176 "--not-overwrite", # ignore existing state, do not modify
3177 ];
3178
3179 push @$setup_cmd, "--tpm2" if $tpm->{version} eq 'v2.0';
3180 # TPM 2.0 supports ECC crypto, use if possible
3181 push @$setup_cmd, "--ecc" if $tpm->{version} eq 'v2.0';
3182
3183 run_command($setup_cmd, outfunc => sub {
3184 print "swtpm_setup: $1\n";
3185 });
3186 }
3187
3188 my $emulator_cmd = [
3189 "swtpm",
3190 "socket",
3191 "--tpmstate",
3192 "backend-uri=file://$state,mode=0600",
3193 "--ctrl",
3194 "type=unixio,path=$paths->{socket},mode=0600",
3195 "--pid",
3196 "file=$paths->{pid}",
3197 "--terminate", # terminate on QEMU disconnect
3198 "--daemon",
3199 ];
3200 push @$emulator_cmd, "--tpm2" if $tpm->{version} eq 'v2.0';
3201 run_command($emulator_cmd, outfunc => sub { print $1; });
3202
6bbcd71f 3203 my $tries = 100; # swtpm may take a bit to start before daemonizing, wait up to 5s for pid
f85951dc 3204 while (! -e $paths->{pid}) {
90c41bac 3205 die "failed to start swtpm: pid file '$paths->{pid}' wasn't created.\n" if --$tries == 0;
6bbcd71f 3206 usleep(50_000);
f85951dc
SR
3207 }
3208
f9dde219
SR
3209 # return untainted PID of swtpm daemon so it can be killed on error
3210 file_read_firstline($paths->{pid}) =~ m/(\d+)/;
3211 return $1;
3212}
3213
86b8228b
DM
3214sub vga_conf_has_spice {
3215 my ($vga) = @_;
3216
55655ebc
DC
3217 my $vgaconf = parse_vga($vga);
3218 my $vgatype = $vgaconf->{type};
3219 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
590e698c
DM
3220
3221 return $1 || 1;
86b8228b
DM
3222}
3223
d731ecbe
WB
3224sub is_native($) {
3225 my ($arch) = @_;
3226 return get_host_arch() eq $arch;
3227}
3228
045749f2
TL
3229sub get_vm_arch {
3230 my ($conf) = @_;
3231 return $conf->{arch} // get_host_arch();
3232}
3233
d731ecbe
WB
3234my $default_machines = {
3235 x86_64 => 'pc',
3236 aarch64 => 'virt',
3237};
3238
0761e619
TL
3239sub get_installed_machine_version {
3240 my ($kvmversion) = @_;
3241 $kvmversion = kvm_user_version() if !defined($kvmversion);
3242 $kvmversion =~ m/^(\d+\.\d+)/;
3243 return $1;
3244}
3245
3246sub windows_get_pinned_machine_version {
3247 my ($machine, $base_version, $kvmversion) = @_;
3248
3249 my $pin_version = $base_version;
3250 if (!defined($base_version) ||
3251 !PVE::QemuServer::Machine::can_run_pve_machine_version($base_version, $kvmversion)
3252 ) {
3253 $pin_version = get_installed_machine_version($kvmversion);
3254 }
3255 if (!$machine || $machine eq 'pc') {
3256 $machine = "pc-i440fx-$pin_version";
3257 } elsif ($machine eq 'q35') {
3258 $machine = "pc-q35-$pin_version";
3259 } elsif ($machine eq 'virt') {
3260 $machine = "virt-$pin_version";
3261 } else {
3262 warn "unknown machine type '$machine', not touching that!\n";
3263 }
3264
3265 return $machine;
3266}
3267
045749f2 3268sub get_vm_machine {
ac0077cc 3269 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
045749f2
TL
3270
3271 my $machine = $forcemachine || $conf->{machine};
d731ecbe 3272
9471e48b 3273 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
4dd1e83c
TL
3274 $kvmversion //= kvm_user_version();
3275 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3276 # layout which confuses windows quite a bit and may result in various regressions..
3277 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3278 if (windows_version($conf->{ostype})) {
0761e619 3279 $machine = windows_get_pinned_machine_version($machine, '5.1', $kvmversion);
4dd1e83c 3280 }
045749f2
TL
3281 $arch //= 'x86_64';
3282 $machine ||= $default_machines->{$arch};
ac0077cc 3283 if ($add_pve_version) {
ac0077cc
SR
3284 my $pvever = PVE::QemuServer::Machine::get_pve_version($kvmversion);
3285 $machine .= "+pve$pvever";
3286 }
3287 }
3288
d4be7f31
SR
3289 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3290 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3291 $machine = $1 if $is_pxe;
3292
ac0077cc
SR
3293 # for version-pinned machines that do not include a pve-version (e.g.
3294 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3295 $machine .= '+pve0';
d4be7f31
SR
3296
3297 $machine .= '.pxe' if $is_pxe;
045749f2
TL
3298 }
3299
3300 return $machine;
d731ecbe
WB
3301}
3302
90b20b15
DC
3303sub get_ovmf_files($$$) {
3304 my ($arch, $efidisk, $smm) = @_;
96ed3574 3305
b5099b4f 3306 my $types = $OVMF->{$arch}
96ed3574
WB
3307 or die "no OVMF images known for architecture '$arch'\n";
3308
b5099b4f
SR
3309 my $type = 'default';
3310 if (defined($efidisk->{efitype}) && $efidisk->{efitype} eq '4m') {
90b20b15
DC
3311 $type = $smm ? "4m" : "4m-no-smm";
3312 $type .= '-ms' if $efidisk->{'pre-enrolled-keys'};
b5099b4f
SR
3313 }
3314
3315 return $types->{$type}->@*;
96ed3574
WB
3316}
3317
6908fd9b
WB
3318my $Arch2Qemu = {
3319 aarch64 => '/usr/bin/qemu-system-aarch64',
3320 x86_64 => '/usr/bin/qemu-system-x86_64',
3321};
3322sub get_command_for_arch($) {
3323 my ($arch) = @_;
3324 return '/usr/bin/kvm' if is_native($arch);
3325
3326 my $cmd = $Arch2Qemu->{$arch}
3327 or die "don't know how to emulate architecture '$arch'\n";
3328 return $cmd;
3329}
3330
05a4c550
SR
3331# To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3332# to use in a QEMU command line (-cpu element), first array_intersect the result
3333# of query_supported_ with query_understood_. This is necessary because:
3334#
3335# a) query_understood_ returns flags the host cannot use and
3336# b) query_supported_ (rather the QMP call) doesn't actually return CPU
3337# flags, but CPU settings - with most of them being flags. Those settings
3338# (and some flags, curiously) cannot be specified as a "-cpu" argument.
3339#
3340# query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3341# expensive. If you need the value returned from this, you can get it much
3342# cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3343# $accel being 'kvm' or 'tcg'.
3344#
3345# pvestatd calls this function on startup and whenever the QEMU/KVM version
3346# changes, automatically populating pmxcfs.
3347#
3348# Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3349# since kvm and tcg machines support different flags
3350#
3351sub query_supported_cpu_flags {
52cffab6 3352 my ($arch) = @_;
05a4c550 3353
52cffab6
SR
3354 $arch //= get_host_arch();
3355 my $default_machine = $default_machines->{$arch};
3356
3357 my $flags = {};
05a4c550
SR
3358
3359 # FIXME: Once this is merged, the code below should work for ARM as well:
3360 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3361 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3362 $arch eq "aarch64";
3363
3364 my $kvm_supported = defined(kvm_version());
3365 my $qemu_cmd = get_command_for_arch($arch);
3366 my $fakevmid = -1;
3367 my $pidfile = PVE::QemuServer::Helpers::pidfile_name($fakevmid);
3368
3369 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3370 my $query_supported_run_qemu = sub {
3371 my ($kvm) = @_;
3372
3373 my $flags = {};
3374 my $cmd = [
3375 $qemu_cmd,
3376 '-machine', $default_machine,
3377 '-display', 'none',
378ad769 3378 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
05a4c550
SR
3379 '-mon', 'chardev=qmp,mode=control',
3380 '-pidfile', $pidfile,
3381 '-S', '-daemonize'
3382 ];
3383
3384 if (!$kvm) {
3385 push @$cmd, '-accel', 'tcg';
3386 }
3387
3388 my $rc = run_command($cmd, noerr => 1, quiet => 0);
3389 die "QEMU flag querying VM exited with code " . $rc if $rc;
3390
3391 eval {
3392 my $cmd_result = mon_cmd(
3393 $fakevmid,
3394 'query-cpu-model-expansion',
3395 type => 'full',
3396 model => { name => 'host' }
3397 );
3398
3399 my $props = $cmd_result->{model}->{props};
3400 foreach my $prop (keys %$props) {
3401 next if $props->{$prop} ne '1';
3402 # QEMU returns some flags multiple times, with '_', '.' or '-'
3403 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3404 # We only keep those with underscores, to match /proc/cpuinfo
3405 $prop =~ s/\.|-/_/g;
3406 $flags->{$prop} = 1;
3407 }
3408 };
3409 my $err = $@;
3410
6bbcd71f 3411 # force stop with 10 sec timeout and 'nocheck', always stop, even if QMP failed
05a4c550
SR
3412 vm_stop(undef, $fakevmid, 1, 1, 10, 0, 1);
3413
3414 die $err if $err;
3415
3416 return [ sort keys %$flags ];
3417 };
3418
3419 # We need to query QEMU twice, since KVM and TCG have different supported flags
3420 PVE::QemuConfig->lock_config($fakevmid, sub {
3421 $flags->{tcg} = eval { $query_supported_run_qemu->(0) };
3422 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3423
3424 if ($kvm_supported) {
3425 $flags->{kvm} = eval { $query_supported_run_qemu->(1) };
3426 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3427 }
3428 });
3429
3430 return $flags;
3431}
3432
3433# Understood CPU flags are written to a file at 'pve-qemu' compile time
3434my $understood_cpu_flag_dir = "/usr/share/kvm";
3435sub query_understood_cpu_flags {
3436 my $arch = get_host_arch();
3437 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3438
3439 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3440 if ! -e $filepath;
3441
3442 my $raw = file_get_contents($filepath);
3443 $raw =~ s/^\s+|\s+$//g;
3444 my @flags = split(/\s+/, $raw);
3445
3446 return \@flags;
3447}
3448
d3f9db4d
TL
3449my sub get_cpuunits {
3450 my ($conf) = @_;
f43d7f67
TL
3451 my $is_cgroupv2 = PVE::CGroup::cgroup_mode() == 2;
3452
3453 my $cpuunits = $conf->{cpuunits};
3454 return $is_cgroupv2 ? 100 : 1024 if !defined($cpuunits);
3455
3456 if ($is_cgroupv2) {
3457 $cpuunits = 10000 if $cpuunits >= 10000; # v1 can be higher, so clamp v2 there
e65e35ca
TL
3458 } else {
3459 $cpuunits = 2 if $cpuunits < 2; # v2 can be lower, so clamp v1 there
f43d7f67
TL
3460 }
3461 return $cpuunits;
d3f9db4d 3462}
e5a6919c
FE
3463
3464# Since commit 277d33454f77ec1d1e0bc04e37621e4dd2424b67 in pve-qemu, smm is not off by default
3465# anymore. But smm=off seems to be required when using SeaBIOS and serial display.
3466my sub should_disable_smm {
3467 my ($conf, $vga) = @_;
3468
3469 return (!defined($conf->{bios}) || $conf->{bios} eq 'seabios') &&
bec87424 3470 $vga->{type} && $vga->{type} =~ m/^(serial\d+|none)$/;
e5a6919c
FE
3471}
3472
1e3baf05 3473sub config_to_command {
5921764c
SR
3474 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3475 $pbs_backing) = @_;
1e3baf05
DM
3476
3477 my $cmd = [];
3326ae19 3478 my ($globalFlags, $machineFlags, $rtcFlags) = ([], [], []);
5bdcf937 3479 my $devices = [];
5bdcf937 3480 my $bridges = {};
b42d3cf9 3481 my $ostype = $conf->{ostype};
4317f69f 3482 my $winversion = windows_version($ostype);
d731ecbe 3483 my $kvm = $conf->{kvm};
38277afc 3484 my $nodename = nodename();
d731ecbe 3485
045749f2 3486 my $arch = get_vm_arch($conf);
1476b99f
DC
3487 my $kvm_binary = get_command_for_arch($arch);
3488 my $kvmver = kvm_user_version($kvm_binary);
045749f2 3489
a04dd5c4
SR
3490 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3491 $kvmver //= "undefined";
3492 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3493 }
3494
9471e48b
TL
3495 my $add_pve_version = min_version($kvmver, 4, 1);
3496
3497 my $machine_type = get_vm_machine($conf, $forcemachine, $arch, $add_pve_version);
4df98f2f 3498 my $machine_version = extract_version($machine_type, $kvmver);
d731ecbe 3499 $kvm //= 1 if is_native($arch);
4317f69f 3500
a77a53ae 3501 $machine_version =~ m/(\d+)\.(\d+)/;
ac0077cc 3502 my ($machine_major, $machine_minor) = ($1, $2);
ac0077cc 3503
b516c848
SR
3504 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3505 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3506 } elsif (!min_version($kvmver, $machine_major, $machine_minor)) {
4df98f2f
TL
3507 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3508 ." please upgrade node '$nodename'\n"
b516c848 3509 } elsif (!PVE::QemuServer::Machine::can_run_pve_machine_version($machine_version, $kvmver)) {
ac0077cc 3510 my $max_pve_version = PVE::QemuServer::Machine::get_pve_version($machine_version);
4df98f2f
TL
3511 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3512 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3513 ." node '$nodename'\n";
ac0077cc
SR
3514 }
3515
3516 # if a specific +pve version is required for a feature, use $version_guard
3517 # instead of min_version to allow machines to be run with the minimum
3518 # required version
3519 my $required_pve_version = 0;
3520 my $version_guard = sub {
3521 my ($major, $minor, $pve) = @_;
3522 return 0 if !min_version($machine_version, $major, $minor, $pve);
47f35977
SR
3523 my $max_pve = PVE::QemuServer::Machine::get_pve_version("$major.$minor");
3524 return 1 if min_version($machine_version, $major, $minor, $max_pve+1);
ac0077cc
SR
3525 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3526 return 1;
3527 };
a77a53ae 3528
4df98f2f
TL
3529 if ($kvm && !defined kvm_version()) {
3530 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3531 ." or enable in BIOS.\n";
d731ecbe 3532 }
bfcd9b7e 3533
3392d6ca 3534 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
4d3f29ed 3535 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
249c4a6c
AD
3536 my $use_old_bios_files = undef;
3537 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
db656e5f 3538
1476b99f 3539 push @$cmd, $kvm_binary;
1e3baf05
DM
3540
3541 push @$cmd, '-id', $vmid;
3542
e4d4cda1
HR
3543 my $vmname = $conf->{name} || "vm$vmid";
3544
6884a7d7 3545 push @$cmd, '-name', "$vmname,debug-threads=on";
e4d4cda1 3546
27b25d03
SR
3547 push @$cmd, '-no-shutdown';
3548
1e3baf05
DM
3549 my $use_virtio = 0;
3550
d036e418 3551 my $qmpsocket = PVE::QemuServer::Helpers::qmp_socket($vmid);
378ad769 3552 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
c971c4f2
AD
3553 push @$cmd, '-mon', "chardev=qmp,mode=control";
3554
2ea5fb7e 3555 if (min_version($machine_version, 2, 12)) {
b4496b9e 3556 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
71bd73b5
DC
3557 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3558 }
1e3baf05 3559
d036e418 3560 push @$cmd, '-pidfile' , PVE::QemuServer::Helpers::pidfile_name($vmid);
19672434 3561
1e3baf05
DM
3562 push @$cmd, '-daemonize';
3563
2796e7d5 3564 if ($conf->{smbios1}) {
1f30ac3a
CE
3565 my $smbios_conf = parse_smbios1($conf->{smbios1});
3566 if ($smbios_conf->{base64}) {
3567 # Do not pass base64 flag to qemu
3568 delete $smbios_conf->{base64};
3569 my $smbios_string = "";
3570 foreach my $key (keys %$smbios_conf) {
3571 my $value;
3572 if ($key eq "uuid") {
3573 $value = $smbios_conf->{uuid}
3574 } else {
3575 $value = decode_base64($smbios_conf->{$key});
3576 }
3577 # qemu accepts any binary data, only commas need escaping by double comma
3578 $value =~ s/,/,,/g;
3579 $smbios_string .= "," . $key . "=" . $value if $value;
3580 }
3581 push @$cmd, '-smbios', "type=1" . $smbios_string;
3582 } else {
3583 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3584 }
2796e7d5
DM
3585 }
3586
3edb45e7 3587 if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
b5099b4f
SR
3588 my $d;
3589 if (my $efidisk = $conf->{efidisk0}) {
3590 $d = parse_drive('efidisk0', $efidisk);
3591 }
3592
90b20b15 3593 my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch, $d, $q35);
818c3b8d 3594 die "uefi base image '$ovmf_code' not found\n" if ! -f $ovmf_code;
2ddc0a5c 3595
818c3b8d 3596 my ($path, $format);
b4dc6475 3597 my $read_only_str = '';
b5099b4f 3598 if ($d) {
2ddc0a5c 3599 my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
13bca7b4 3600 $format = $d->{format};
2ddc0a5c
DC
3601 if ($storeid) {
3602 $path = PVE::Storage::path($storecfg, $d->{file});
13bca7b4
WB
3603 if (!defined($format)) {
3604 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
3605 $format = qemu_img_format($scfg, $volname);
3606 }
2ddc0a5c
DC
3607 } else {
3608 $path = $d->{file};
13bca7b4
WB
3609 die "efidisk format must be specified\n"
3610 if !defined($format);
2ddc0a5c 3611 }
b4dc6475
FG
3612
3613 $read_only_str = ',readonly=on' if drive_is_read_only($conf, $d);
2ddc0a5c 3614 } else {
34e82fa2 3615 log_warn("no efidisk configured! Using temporary efivars disk.");
4dcce9ee 3616 $path = "/tmp/$vmid-ovmf.fd";
96ed3574 3617 PVE::Tools::file_copy($ovmf_vars, $path, -s $ovmf_vars);
13bca7b4 3618 $format = 'raw';
2ddc0a5c 3619 }
4dcce9ee 3620
818ce80e
DC
3621 my $size_str = "";
3622
3623 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3624 $size_str = ",size=" . (-s $ovmf_vars);
3625 }
3626
738dc81c
TL
3627 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3628 my $cache = "";
3629 if ($path =~ m/^rbd:/) {
3630 $cache = ',cache=writeback';
3631 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3632 }
6aaad230 3633
378ad769 3634 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
b4dc6475 3635 push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
a783c78e
AD
3636 }
3637
483ceeab 3638 if ($q35) { # tell QEMU to load q35 config early
7583d156 3639 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
2ea5fb7e 3640 if (min_version($machine_version, 4, 0)) {
7583d156
DC
3641 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3642 } else {
3643 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3644 }
3645 }
da8b4189 3646
cc181036
TL
3647 if (defined(my $fixups = qemu_created_version_fixups($conf, $forcemachine, $kvmver))) {
3648 push @$cmd, $fixups->@*;
3649 }
3650
844d8fa6
DC
3651 if ($conf->{vmgenid}) {
3652 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid};
3653 }
3654
d40e5e18 3655 # add usb controllers
4df98f2f
TL
3656 my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers(
3657 $conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
d40e5e18 3658 push @$devices, @usbcontrollers if @usbcontrollers;
55655ebc 3659 my $vga = parse_vga($conf->{vga});
2fa3151e 3660
55655ebc
DC
3661 my $qxlnum = vga_conf_has_spice($conf->{vga});
3662 $vga->{type} = 'qxl' if $qxlnum;
2fa3151e 3663
55655ebc 3664 if (!$vga->{type}) {
869ad4a7
WB
3665 if ($arch eq 'aarch64') {
3666 $vga->{type} = 'virtio';
2ea5fb7e 3667 } elsif (min_version($machine_version, 2, 9)) {
55655ebc 3668 $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3669 } else {
55655ebc 3670 $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3671 }
5acbfe9e
DM
3672 }
3673
1e3baf05 3674 # enable absolute mouse coordinates (needed by vnc)
fa3b3ce0
TL
3675 my $tablet = $conf->{tablet};
3676 if (!defined($tablet)) {
5acbfe9e 3677 $tablet = $defaults->{tablet};
590e698c 3678 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
55655ebc 3679 $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
5acbfe9e
DM
3680 }
3681
d559309f
WB
3682 if ($tablet) {
3683 push @$devices, '-device', print_tabletdevice_full($conf, $arch) if $tablet;
3684 my $kbd = print_keyboarddevice_full($conf, $arch);
3685 push @$devices, '-device', $kbd if defined($kbd);
3686 }
b467f79a 3687
e5d611c3 3688 my $bootorder = device_bootorder($conf);
2141a802 3689
74c17b7a 3690 # host pci device passthrough
13d68979 3691 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE::QemuServer::PCI::print_hostpci_devices(
41af2dfc 3692 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
1e3baf05
DM
3693
3694 # usb devices
ae36393d 3695 my $usb_dev_features = {};
2ea5fb7e 3696 $usb_dev_features->{spice_usb3} = 1 if min_version($machine_version, 4, 0);
ae36393d 3697
4df98f2f 3698 my @usbdevices = PVE::QemuServer::USB::get_usb_devices(
2141a802 3699 $conf, $usbdesc->{format}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
d40e5e18 3700 push @$devices, @usbdevices if @usbdevices;
2141a802 3701
1e3baf05 3702 # serial devices
bae179aa 3703 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
fa3b3ce0
TL
3704 my $path = $conf->{"serial$i"} or next;
3705 if ($path eq 'socket') {
3706 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3707 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3708 # On aarch64, serial0 is the UART device. Qemu only allows
3709 # connecting UART devices via the '-serial' command line, as
3710 # the device has a fixed slot on the hardware...
3711 if ($arch eq 'aarch64' && $i == 0) {
3712 push @$devices, '-serial', "chardev:serial$i";
9f9d2fb2 3713 } else {
9f9d2fb2
DM
3714 push @$devices, '-device', "isa-serial,chardev=serial$i";
3715 }
fa3b3ce0
TL
3716 } else {
3717 die "no such serial device\n" if ! -c $path;
3718 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3719 push @$devices, '-device', "isa-serial,chardev=serial$i";
34978be3 3720 }
1e3baf05
DM
3721 }
3722
3723 # parallel devices
1989a89c 3724 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
34978be3 3725 if (my $path = $conf->{"parallel$i"}) {
19672434 3726 die "no such parallel device\n" if ! -c $path;
32e69805 3727 my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
4c5dbaf6 3728 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
5bdcf937 3729 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
34978be3 3730 }
1e3baf05
DM
3731 }
3732
b01de199 3733 if (min_version($machine_version, 4, 0) && (my $audio = conf_has_audio($conf))) {
2e7b5925 3734 my $audiopciaddr = print_pci_addr("audio0", $bridges, $arch, $machine_type);
1cc5ed1b 3735 my $audio_devs = audio_devs($audio, $audiopciaddr, $machine_version);
b01de199 3736 push @$devices, @$audio_devs;
2e7b5925 3737 }
19672434 3738
f9dde219
SR
3739 add_tpm_device($vmid, $devices, $conf);
3740
1e3baf05
DM
3741 my $sockets = 1;
3742 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3743 $sockets = $conf->{sockets} if $conf->{sockets};
3744
3745 my $cores = $conf->{cores} || 1;
3bd18e48 3746
de9d1e55 3747 my $maxcpus = $sockets * $cores;
76267728 3748
de9d1e55 3749 my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
76267728 3750
de9d1e55
AD
3751 my $allowed_vcpus = $cpuinfo->{cpus};
3752
483ceeab 3753 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n" if ($allowed_vcpus < $maxcpus);
1e3baf05 3754
483ceeab 3755 if ($hotplug_features->{cpu} && min_version($machine_version, 2, 7)) {
69c81430
AD
3756 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3757 for (my $i = 2; $i <= $vcpus; $i++) {
3758 my $cpustr = print_cpu_device($conf,$i);
3759 push @$cmd, '-device', $cpustr;
3760 }
3761
3762 } else {
3763
3764 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3765 }
1e3baf05
DM
3766 push @$cmd, '-nodefaults';
3767
dbea4415 3768 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
1e3baf05 3769
6b64503e 3770 push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
1e3baf05 3771
6b64503e 3772 push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
1e3baf05 3773
84902837 3774 if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
4df98f2f
TL
3775 push @$devices, '-device', print_vga_device(
3776 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
6f070e39
TL
3777
3778 push @$cmd, '-display', 'egl-headless,gl=core' if $vga->{type} eq 'virtio-gl'; # VIRGL
3779
d036e418 3780 my $socket = PVE::QemuServer::Helpers::vnc_socket($vmid);
378ad769 3781 push @$cmd, '-vnc', "unix:$socket,password=on";
b7be4ba9 3782 } else {
55655ebc 3783 push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
b7be4ba9
AD
3784 push @$cmd, '-nographic';
3785 }
3786
1e3baf05 3787 # time drift fix
6b64503e 3788 my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
8c559505 3789 my $useLocaltime = $conf->{localtime};
1e3baf05 3790
4317f69f
AD
3791 if ($winversion >= 5) { # windows
3792 $useLocaltime = 1 if !defined($conf->{localtime});
7a131888 3793
4317f69f
AD
3794 # use time drift fix when acpi is enabled
3795 if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3796 $tdf = 1 if !defined($conf->{tdf});
462e8d19 3797 }
4317f69f 3798 }
462e8d19 3799
4317f69f
AD
3800 if ($winversion >= 6) {
3801 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3802 push @$cmd, '-no-hpet';
1e3baf05
DM
3803 }
3804
8c559505
DM
3805 push @$rtcFlags, 'driftfix=slew' if $tdf;
3806
2f6f002c 3807 if ($conf->{startdate} && $conf->{startdate} ne 'now') {
8c559505
DM
3808 push @$rtcFlags, "base=$conf->{startdate}";
3809 } elsif ($useLocaltime) {
3810 push @$rtcFlags, 'base=localtime';
3811 }
1e3baf05 3812
58c64ad5
SR
3813 if ($forcecpu) {
3814 push @$cmd, '-cpu', $forcecpu;
3815 } else {
2f6f002c 3816 push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
58c64ad5 3817 }
519ed28c 3818
0567a4d5 3819 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
370b05e7 3820
1e3baf05
DM
3821 push @$cmd, '-S' if $conf->{freeze};
3822
b20df606 3823 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
1e3baf05 3824
48657158
MD
3825 my $guest_agent = parse_guest_agent($conf);
3826
3827 if ($guest_agent->{enabled}) {
d036e418 3828 my $qgasocket = PVE::QemuServer::Helpers::qmp_socket($vmid, 1);
378ad769 3829 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
48657158 3830
60f03a11 3831 if (!$guest_agent->{type} || $guest_agent->{type} eq 'virtio') {
48657158
MD
3832 my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $machine_type);
3833 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3834 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3835 } elsif ($guest_agent->{type} eq 'isa') {
3836 push @$devices, '-device', "isa-serial,chardev=qga0";
3837 }
ab6a046f
AD
3838 }
3839
e5d611c3
TL
3840 my $rng = $conf->{rng0} ? parse_rng($conf->{rng0}) : undef;
3841 if ($rng && $version_guard->(4, 1, 2)) {
05853188
SR
3842 check_rng_source($rng->{source});
3843
2cf61f33
SR
3844 my $max_bytes = $rng->{max_bytes} // $rng_fmt->{max_bytes}->{default};
3845 my $period = $rng->{period} // $rng_fmt->{period}->{default};
2cf61f33
SR
3846 my $limiter_str = "";
3847 if ($max_bytes) {
3848 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3849 }
3850
2cf61f33 3851 my $rng_addr = print_pci_addr("rng0", $bridges, $arch, $machine_type);
2cf61f33
SR
3852 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3853 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3854 }
3855
1d794448 3856 my $spice_port;
2fa3151e 3857
f8ea1b30 3858 if ($qxlnum || $vga->{type} =~ /^virtio/) {
590e698c 3859 if ($qxlnum > 1) {
ac087616 3860 if ($winversion){
2f6f002c 3861 for (my $i = 1; $i < $qxlnum; $i++){
4df98f2f
TL
3862 push @$devices, '-device', print_vga_device(
3863 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
590e698c
DM
3864 }
3865 } else {
3866 # assume other OS works like Linux
55655ebc
DC
3867 my ($ram, $vram) = ("134217728", "67108864");
3868 if ($vga->{memory}) {
3869 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
3870 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
3871 }
3872 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3873 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
2fa3151e
AD
3874 }
3875 }
3876
d559309f 3877 my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type);
95a4b4a9 3878
af0eba7e 3879 my $pfamily = PVE::Tools::get_host_address_family($nodename);
91152441
WB
3880 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
3881 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
4d316a63
AL
3882
3883 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3884 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3885 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3886
91152441
WB
3887 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
3888 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
943340a6 3889
4df98f2f
TL
3890 my $spice_enhancement_str = $conf->{spice_enhancements} // '';
3891 my $spice_enhancement = parse_property_string($spice_enhancements_fmt, $spice_enhancement_str);
caab114a
TL
3892 if ($spice_enhancement->{foldersharing}) {
3893 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3894 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3895 }
c4df18db 3896
caab114a 3897 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
4df98f2f
TL
3898 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3899 if $spice_enhancement->{videostreaming};
3900
caab114a 3901 push @$devices, '-spice', "$spice_opts";
1011b570
DM
3902 }
3903
8d9ae0d2
DM
3904 # enable balloon by default, unless explicitly disabled
3905 if (!defined($conf->{balloon}) || $conf->{balloon}) {
3326ae19 3906 my $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
c70e4ec3
AD
3907 my $ballooncmd = "virtio-balloon-pci,id=balloon0$pciaddr";
3908 $ballooncmd .= ",free-page-reporting=on" if min_version($machine_version, 6, 2);
3909 push @$devices, '-device', $ballooncmd;
8d9ae0d2 3910 }
1e3baf05 3911
0ea9541d
DM
3912 if ($conf->{watchdog}) {
3913 my $wdopts = parse_watchdog($conf->{watchdog});
3326ae19 3914 my $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
0a40e8ea 3915 my $watchdog = $wdopts->{model} || 'i6300esb';
5bdcf937
AD
3916 push @$devices, '-device', "$watchdog$pciaddr";
3917 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
0ea9541d
DM
3918 }
3919
1e3baf05 3920 my $vollist = [];
941e0c42 3921 my $scsicontroller = {};
26ee04b6 3922 my $ahcicontroller = {};
cdd20088 3923 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
1e3baf05 3924
5881b913
DM
3925 # Add iscsi initiator name if available
3926 if (my $initiator = get_initiator_name()) {
3927 push @$devices, '-iscsi', "initiator-name=$initiator";
3928 }
3929
912792e2 3930 PVE::QemuConfig->foreach_volume($conf, sub {
1e3baf05
DM
3931 my ($ds, $drive) = @_;
3932
ff1a2432 3933 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
3f11f0d7 3934 check_volume_storage_type($storecfg, $drive->{file});
1e3baf05 3935 push @$vollist, $drive->{file};
ff1a2432 3936 }
afdb31d5 3937
4dcce9ee
TL
3938 # ignore efidisk here, already added in bios/fw handling code above
3939 return if $drive->{interface} eq 'efidisk';
f9dde219
SR
3940 # similar for TPM
3941 return if $drive->{interface} eq 'tpmstate';
4dcce9ee 3942
1e3baf05 3943 $use_virtio = 1 if $ds =~ m/^virtio/;
3b408e82 3944
2141a802 3945 $drive->{bootindex} = $bootorder->{$ds} if $bootorder->{$ds};
3b408e82 3946
2f6f002c 3947 if ($drive->{interface} eq 'virtio'){
51f492cd
AD
3948 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
3949 }
3950
2f6f002c 3951 if ($drive->{interface} eq 'scsi') {
cdd20088 3952
ee034f5c 3953 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
6731a4cf 3954
b8fb1c03
SR
3955 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3956 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3957
3326ae19 3958 my $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
a1b7d579 3959 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
fc8b40fd
AD
3960
3961 my $iothread = '';
3962 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
3963 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3964 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
e7a5104d
DC
3965 } elsif ($drive->{iothread}) {
3966 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
fc8b40fd
AD
3967 }
3968
6e11f143
AD
3969 my $queues = '';
3970 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
3971 $queues = ",num_queues=$drive->{queues}";
370b05e7 3972 }
6e11f143 3973
4df98f2f
TL
3974 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
3975 if !$scsicontroller->{$controller};
cdd20088 3976 $scsicontroller->{$controller}=1;
2f6f002c 3977 }
3b408e82 3978
26ee04b6 3979 if ($drive->{interface} eq 'sata') {
2f6f002c 3980 my $controller = int($drive->{index} / $PVE::QemuServer::Drive::MAX_SATA_DISKS);
3326ae19 3981 my $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
4df98f2f
TL
3982 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
3983 if !$ahcicontroller->{$controller};
2f6f002c 3984 $ahcicontroller->{$controller}=1;
26ee04b6 3985 }
46f58b5f 3986
5921764c
SR
3987 my $pbs_conf = $pbs_backing->{$ds};
3988 my $pbs_name = undef;
3989 if ($pbs_conf) {
3990 $pbs_name = "drive-$ds-pbs";
3991 push @$devices, '-blockdev', print_pbs_blockdev($pbs_conf, $pbs_name);
3992 }
3993
6d5673c3
SR
3994 my $drive_cmd = print_drive_commandline_full(
3995 $storecfg, $vmid, $drive, $pbs_name, min_version($kvmver, 6, 0));
3dc33a72
FG
3996
3997 # extra protection for templates, but SATA and IDE don't support it..
75748d44 3998 $drive_cmd .= ',readonly=on' if drive_is_read_only($conf, $drive);
4ef13a7f 3999
15b21acc 4000 push @$devices, '-drive',$drive_cmd;
4df98f2f
TL
4001 push @$devices, '-device', print_drivedevice_full(
4002 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
1e3baf05
DM
4003 });
4004
cc4d6182 4005 for (my $i = 0; $i < $MAX_NETS; $i++) {
2141a802
SR
4006 my $netname = "net$i";
4007
4008 next if !$conf->{$netname};
4009 my $d = parse_net($conf->{$netname});
d0a86b24 4010 next if !$d;
1e3baf05 4011
d0a86b24 4012 $use_virtio = 1 if $d->{model} eq 'virtio';
1e3baf05 4013
2141a802 4014 $d->{bootindex} = $bootorder->{$netname} if $bootorder->{$netname};
1e3baf05 4015
2141a802 4016 my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, $netname);
d0a86b24 4017 push @$devices, '-netdev', $netdevfull;
5bdcf937 4018
d0a86b24 4019 my $netdevicefull = print_netdevice_full(
2141a802 4020 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type);
4df98f2f 4021
d0a86b24 4022 push @$devices, '-device', $netdevicefull;
5bdcf937 4023 }
1e3baf05 4024
6dbcb073 4025 if ($conf->{ivshmem}) {
4df98f2f 4026 my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
e3c27a6a 4027
6dbcb073
DC
4028 my $bus;
4029 if ($q35) {
4030 $bus = print_pcie_addr("ivshmem");
4031 } else {
4032 $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
4033 }
e3c27a6a
TL
4034
4035 my $ivshmem_name = $ivshmem->{name} // $vmid;
4036 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4037
6dbcb073 4038 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4df98f2f
TL
4039 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
4040 .",size=$ivshmem->{size}M";
6dbcb073
DC
4041 }
4042
2513b862
DC
4043 # pci.4 is nested in pci.1
4044 $bridges->{1} = 1 if $bridges->{4};
4045
3326ae19
TL
4046 if (!$q35) { # add pci bridges
4047 if (min_version($machine_version, 2, 3)) {
fc79e813
AD
4048 $bridges->{1} = 1;
4049 $bridges->{2} = 1;
4050 }
6731a4cf 4051 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
2513b862
DC
4052 }
4053
4054 for my $k (sort {$b cmp $a} keys %$bridges) {
4055 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
13d68979
SR
4056
4057 my $k_name = $k;
4058 if ($k == 2 && $legacy_igd) {
4059 $k_name = "$k-igd";
4060 }
3326ae19 4061 my $pciaddr = print_pci_addr("pci.$k_name", undef, $arch, $machine_type);
2513b862 4062 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3326ae19
TL
4063
4064 if ($q35) { # add after -readconfig pve-q35.cfg
2513b862
DC
4065 splice @$devices, 2, 0, '-device', $devstr;
4066 } else {
4067 unshift @$devices, '-device', $devstr if $k > 0;
f8e83f05 4068 }
19672434
DM
4069 }
4070
ac0077cc
SR
4071 if (!$kvm) {
4072 push @$machineFlags, 'accel=tcg';
4073 }
4074
e5a6919c
FE
4075 push @$machineFlags, 'smm=off' if should_disable_smm($conf, $vga);
4076
ac0077cc
SR
4077 my $machine_type_min = $machine_type;
4078 if ($add_pve_version) {
4079 $machine_type_min =~ s/\+pve\d+$//;
4080 $machine_type_min .= "+pve$required_pve_version";
4081 }
4082 push @$machineFlags, "type=${machine_type_min}";
4083
5bdcf937 4084 push @$cmd, @$devices;
2f6f002c
TL
4085 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
4086 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
4087 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
8c559505 4088
7ceade4c
DC
4089 if (my $vmstate = $conf->{vmstate}) {
4090 my $statepath = PVE::Storage::path($storecfg, $vmstate);
24d1f93a 4091 push @$vollist, $vmstate;
7ceade4c 4092 push @$cmd, '-loadstate', $statepath;
b85666cf 4093 print "activating and using '$vmstate' as vmstate\n";
7ceade4c
DC
4094 }
4095
85fcf79e
FG
4096 if (PVE::QemuConfig->is_template($conf)) {
4097 # needed to workaround base volumes being read-only
4098 push @$cmd, '-snapshot';
4099 }
4100
76350670
DC
4101 # add custom args
4102 if ($conf->{args}) {
4103 my $aa = PVE::Tools::split_args($conf->{args});
4104 push @$cmd, @$aa;
4105 }
4106
1d794448 4107 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
1e3baf05 4108}
19672434 4109
05853188
SR
4110sub check_rng_source {
4111 my ($source) = @_;
4112
4113 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
4114 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
4115 if ! -e $source;
4116
4117 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
4118 if ($source eq '/dev/hwrng' && file_read_firstline($rng_current) eq 'none') {
4df98f2f
TL
4119 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
4120 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
4121 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
4122 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
4123 ." to the host.\n";
05853188
SR
4124 }
4125}
4126
943340a6 4127sub spice_port {
1011b570 4128 my ($vmid) = @_;
943340a6 4129
0a13e08e 4130 my $res = mon_cmd($vmid, 'query-spice');
943340a6
DM
4131
4132 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
1011b570
DM
4133}
4134
86fdcfb2
DA
4135sub vm_devices_list {
4136 my ($vmid) = @_;
4137
0a13e08e 4138 my $res = mon_cmd($vmid, 'query-pci');
f721624b 4139 my $devices_to_check = [];
ceea9078
DM
4140 my $devices = {};
4141 foreach my $pcibus (@$res) {
f721624b
DC
4142 push @$devices_to_check, @{$pcibus->{devices}},
4143 }
4144
4145 while (@$devices_to_check) {
4146 my $to_check = [];
4147 for my $d (@$devices_to_check) {
4148 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4149 next if !$d->{'pci_bridge'};
4150
4151 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
4152 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
f78cc802 4153 }
f721624b 4154 $devices_to_check = $to_check;
f78cc802
AD
4155 }
4156
0a13e08e 4157 my $resblock = mon_cmd($vmid, 'query-block');
f78cc802
AD
4158 foreach my $block (@$resblock) {
4159 if($block->{device} =~ m/^drive-(\S+)/){
4160 $devices->{$1} = 1;
1dc4f496
DM
4161 }
4162 }
86fdcfb2 4163
0a13e08e 4164 my $resmice = mon_cmd($vmid, 'query-mice');
3d7389fe
DM
4165 foreach my $mice (@$resmice) {
4166 if ($mice->{name} eq 'QEMU HID Tablet') {
4167 $devices->{tablet} = 1;
4168 last;
4169 }
4170 }
4171
deb091c5
DC
4172 # for usb devices there is no query-usb
4173 # but we can iterate over the entries in
4174 # qom-list path=/machine/peripheral
0a13e08e 4175 my $resperipheral = mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
deb091c5
DC
4176 foreach my $per (@$resperipheral) {
4177 if ($per->{name} =~ m/^usb\d+$/) {
4178 $devices->{$per->{name}} = 1;
4179 }
4180 }
4181
1dc4f496 4182 return $devices;
86fdcfb2
DA
4183}
4184
ec21aa11 4185sub vm_deviceplug {
d559309f 4186 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
ae57f6b3 4187
3392d6ca 4188 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f 4189
95d6343b
DA
4190 my $devices_list = vm_devices_list($vmid);
4191 return 1 if defined($devices_list->{$deviceid});
4192
4df98f2f
TL
4193 # add PCI bridge if we need it for the device
4194 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
fee46675 4195
3d7389fe 4196 if ($deviceid eq 'tablet') {
d559309f 4197 qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
d559309f 4198 } elsif ($deviceid eq 'keyboard') {
d559309f 4199 qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
4eb68604 4200 } elsif ($deviceid =~ m/^usb(\d+)$/) {
f745762b 4201 die "usb hotplug currently not reliable\n";
50bbe377
TL
4202 # since we can't reliably hot unplug all added usb devices and usb
4203 # passthrough breaks live migration we disable usb hotplugging for now
4204 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
fee46675 4205 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
22de899a
AD
4206 qemu_iothread_add($vmid, $deviceid, $device);
4207
3326ae19
TL
4208 qemu_driveadd($storecfg, $vmid, $device);
4209 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
fee46675 4210
3326ae19 4211 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4212 eval { qemu_deviceaddverify($vmid, $deviceid); };
4213 if (my $err = $@) {
63c2da2f
DM
4214 eval { qemu_drivedel($vmid, $deviceid); };
4215 warn $@ if $@;
fee46675 4216 die $err;
5e5dcb73 4217 }
2733141c 4218 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3326ae19
TL
4219 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
4220 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
a1b7d579 4221 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
2733141c 4222
3326ae19 4223 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
fee46675 4224
fc8b40fd
AD
4225 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
4226 qemu_iothread_add($vmid, $deviceid, $device);
4227 $devicefull .= ",iothread=iothread-$deviceid";
4228 }
4229
6e11f143
AD
4230 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
4231 $devicefull .= ",num_queues=$device->{queues}";
4232 }
4233
3326ae19
TL
4234 qemu_deviceadd($vmid, $devicefull);
4235 qemu_deviceaddverify($vmid, $deviceid);
fee46675 4236 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
d559309f 4237 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
fee46675 4238 qemu_driveadd($storecfg, $vmid, $device);
a1b7d579 4239
acfc6ef8 4240 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
fee46675
DM
4241 eval { qemu_deviceadd($vmid, $devicefull); };
4242 if (my $err = $@) {
63c2da2f
DM
4243 eval { qemu_drivedel($vmid, $deviceid); };
4244 warn $@ if $@;
fee46675 4245 die $err;
a4f091a0 4246 }
fee46675 4247 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
d1c1af4b 4248 return if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
8718099c 4249
3392d6ca 4250 my $machine_type = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
95d3be58
DC
4251 my $use_old_bios_files = undef;
4252 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
8718099c 4253
4df98f2f
TL
4254 my $netdevicefull = print_netdevice_full(
4255 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
95d3be58 4256 qemu_deviceadd($vmid, $netdevicefull);
79046fd1
DC
4257 eval {
4258 qemu_deviceaddverify($vmid, $deviceid);
4259 qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
4260 };
fee46675
DM
4261 if (my $err = $@) {
4262 eval { qemu_netdevdel($vmid, $deviceid); };
4263 warn $@ if $@;
4264 die $err;
95d3be58 4265 }
fee46675 4266 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
40f28a9f 4267 my $bridgeid = $2;
d559309f 4268 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
40f28a9f 4269 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
a1b7d579 4270
40f28a9f 4271 qemu_deviceadd($vmid, $devicefull);
fee46675 4272 qemu_deviceaddverify($vmid, $deviceid);
fee46675 4273 } else {
a1b7d579 4274 die "can't hotplug device '$deviceid'\n";
40f28a9f
AD
4275 }
4276
5e5dcb73 4277 return 1;
a4dea331
DA
4278}
4279
3eec5767 4280# fixme: this should raise exceptions on error!
ec21aa11 4281sub vm_deviceunplug {
f19d1c47 4282 my ($vmid, $conf, $deviceid) = @_;
873c2d69 4283
95d6343b
DA
4284 my $devices_list = vm_devices_list($vmid);
4285 return 1 if !defined($devices_list->{$deviceid});
4286
2141a802
SR
4287 my $bootdisks = PVE::QemuServer::Drive::get_bootdisks($conf);
4288 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
63c2da2f 4289
d559309f 4290 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
3d7389fe 4291 qemu_devicedel($vmid, $deviceid);
4eb68604 4292 } elsif ($deviceid =~ m/^usb\d+$/) {
f745762b 4293 die "usb hotplug currently not reliable\n";
50bbe377
TL
4294 # when unplugging usb devices this way, there may be remaining usb
4295 # controllers/hubs so we disable it for now
4296 #qemu_devicedel($vmid, $deviceid);
4297 #qemu_devicedelverify($vmid, $deviceid);
63c2da2f 4298 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
9a66c311 4299 my $device = parse_drive($deviceid, $conf->{$deviceid});
f19d1c47 4300
a8d0fec3
TL
4301 qemu_devicedel($vmid, $deviceid);
4302 qemu_devicedelverify($vmid, $deviceid);
4303 qemu_drivedel($vmid, $deviceid);
9a66c311 4304 qemu_iothread_del($vmid, $deviceid, $device);
2733141c 4305 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
63c2da2f 4306 qemu_devicedel($vmid, $deviceid);
8ce30dde 4307 qemu_devicedelverify($vmid, $deviceid);
63c2da2f 4308 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
9a66c311 4309 my $device = parse_drive($deviceid, $conf->{$deviceid});
cfc817c7 4310
a8d0fec3 4311 qemu_devicedel($vmid, $deviceid);
52b361af 4312 qemu_devicedelverify($vmid, $deviceid);
a8d0fec3 4313 qemu_drivedel($vmid, $deviceid);
a1b7d579 4314 qemu_deletescsihw($conf, $vmid, $deviceid);
8ce30dde 4315
9a66c311
FG
4316 qemu_iothread_del($vmid, "virtioscsi$device->{index}", $device)
4317 if $conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single');
63c2da2f 4318 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
a8d0fec3
TL
4319 qemu_devicedel($vmid, $deviceid);
4320 qemu_devicedelverify($vmid, $deviceid);
4321 qemu_netdevdel($vmid, $deviceid);
63c2da2f
DM
4322 } else {
4323 die "can't unplug device '$deviceid'\n";
2630d2a9
DA
4324 }
4325
5e5dcb73
DA
4326 return 1;
4327}
4328
4329sub qemu_deviceadd {
4330 my ($vmid, $devicefull) = @_;
873c2d69 4331
d695b5b7
AD
4332 $devicefull = "driver=".$devicefull;
4333 my %options = split(/[=,]/, $devicefull);
f19d1c47 4334
0a13e08e 4335 mon_cmd($vmid, "device_add" , %options);
5e5dcb73 4336}
afdb31d5 4337
5e5dcb73 4338sub qemu_devicedel {
fee46675 4339 my ($vmid, $deviceid) = @_;
63c2da2f 4340
0a13e08e 4341 my $ret = mon_cmd($vmid, "device_del", id => $deviceid);
5e5dcb73
DA
4342}
4343
22de899a 4344sub qemu_iothread_add {
a8d0fec3 4345 my ($vmid, $deviceid, $device) = @_;
22de899a
AD
4346
4347 if ($device->{iothread}) {
4348 my $iothreads = vm_iothreads_list($vmid);
4349 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4350 }
4351}
4352
4353sub qemu_iothread_del {
a8d0fec3 4354 my ($vmid, $deviceid, $device) = @_;
22de899a 4355
22de899a
AD
4356 if ($device->{iothread}) {
4357 my $iothreads = vm_iothreads_list($vmid);
4358 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4359 }
4360}
4361
4d3f29ed 4362sub qemu_objectadd {
a8d0fec3 4363 my ($vmid, $objectid, $qomtype) = @_;
4d3f29ed 4364
0a13e08e 4365 mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4d3f29ed
AD
4366
4367 return 1;
4368}
4369
4370sub qemu_objectdel {
a8d0fec3 4371 my ($vmid, $objectid) = @_;
4d3f29ed 4372
0a13e08e 4373 mon_cmd($vmid, "object-del", id => $objectid);
4d3f29ed
AD
4374
4375 return 1;
4376}
4377
5e5dcb73 4378sub qemu_driveadd {
fee46675 4379 my ($storecfg, $vmid, $device) = @_;
5e5dcb73 4380
6d5673c3
SR
4381 my $kvmver = get_running_qemu_version($vmid);
4382 my $io_uring = min_version($kvmver, 6, 0);
4383 my $drive = print_drive_commandline_full($storecfg, $vmid, $device, undef, $io_uring);
7a69fc3c 4384 $drive =~ s/\\/\\\\/g;
0a13e08e 4385 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_add auto \"$drive\"");
fee46675 4386
5e5dcb73 4387 # If the command succeeds qemu prints: "OK"
fee46675
DM
4388 return 1 if $ret =~ m/OK/s;
4389
4390 die "adding drive failed: $ret\n";
5e5dcb73 4391}
afdb31d5 4392
5e5dcb73 4393sub qemu_drivedel {
a8d0fec3 4394 my ($vmid, $deviceid) = @_;
873c2d69 4395
0a13e08e 4396 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-$deviceid");
5e5dcb73 4397 $ret =~ s/^\s+//;
a1b7d579 4398
63c2da2f 4399 return 1 if $ret eq "";
a1b7d579 4400
63c2da2f 4401 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
a1b7d579
DM
4402 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4403
63c2da2f 4404 die "deleting drive $deviceid failed : $ret\n";
5e5dcb73 4405}
f19d1c47 4406
5e5dcb73 4407sub qemu_deviceaddverify {
fee46675 4408 my ($vmid, $deviceid) = @_;
873c2d69 4409
5e5dcb73
DA
4410 for (my $i = 0; $i <= 5; $i++) {
4411 my $devices_list = vm_devices_list($vmid);
4412 return 1 if defined($devices_list->{$deviceid});
4413 sleep 1;
afdb31d5 4414 }
fee46675
DM
4415
4416 die "error on hotplug device '$deviceid'\n";
5e5dcb73 4417}
afdb31d5 4418
5e5dcb73
DA
4419
4420sub qemu_devicedelverify {
63c2da2f
DM
4421 my ($vmid, $deviceid) = @_;
4422
a1b7d579 4423 # need to verify that the device is correctly removed as device_del
63c2da2f 4424 # is async and empty return is not reliable
5e5dcb73 4425
5e5dcb73
DA
4426 for (my $i = 0; $i <= 5; $i++) {
4427 my $devices_list = vm_devices_list($vmid);
4428 return 1 if !defined($devices_list->{$deviceid});
4429 sleep 1;
afdb31d5 4430 }
63c2da2f
DM
4431
4432 die "error on hot-unplugging device '$deviceid'\n";
873c2d69
DA
4433}
4434
cdd20088 4435sub qemu_findorcreatescsihw {
d559309f 4436 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
cfc817c7 4437
ee034f5c 4438 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
2733141c
AD
4439
4440 my $scsihwid="$controller_prefix$controller";
cfc817c7
DA
4441 my $devices_list = vm_devices_list($vmid);
4442
a8d0fec3 4443 if (!defined($devices_list->{$scsihwid})) {
d559309f 4444 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
cfc817c7 4445 }
fee46675 4446
cfc817c7
DA
4447 return 1;
4448}
4449
8ce30dde
AD
4450sub qemu_deletescsihw {
4451 my ($conf, $vmid, $opt) = @_;
4452
4453 my $device = parse_drive($opt, $conf->{$opt});
4454
a1511b3c 4455 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
2733141c
AD
4456 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
4457 return 1;
4458 }
4459
ee034f5c 4460 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
8ce30dde
AD
4461
4462 my $devices_list = vm_devices_list($vmid);
4463 foreach my $opt (keys %{$devices_list}) {
e0fd2b2f
FE
4464 if (is_valid_drivename($opt)) {
4465 my $drive = parse_drive($opt, $conf->{$opt});
a8d0fec3 4466 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
8ce30dde
AD
4467 return 1;
4468 }
4469 }
4470 }
4471
4472 my $scsihwid="scsihw$controller";
4473
4474 vm_deviceunplug($vmid, $conf, $scsihwid);
4475
4476 return 1;
4477}
4478
281fedb3 4479sub qemu_add_pci_bridge {
d559309f 4480 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
40f28a9f
AD
4481
4482 my $bridges = {};
281fedb3
DM
4483
4484 my $bridgeid;
4485
d559309f 4486 print_pci_addr($device, $bridges, $arch, $machine_type);
40f28a9f
AD
4487
4488 while (my ($k, $v) = each %$bridges) {
4489 $bridgeid = $k;
4490 }
fee46675 4491 return 1 if !defined($bridgeid) || $bridgeid < 1;
281fedb3 4492
40f28a9f
AD
4493 my $bridge = "pci.$bridgeid";
4494 my $devices_list = vm_devices_list($vmid);
4495
281fedb3 4496 if (!defined($devices_list->{$bridge})) {
d559309f 4497 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
40f28a9f 4498 }
281fedb3 4499
40f28a9f
AD
4500 return 1;
4501}
4502
25088687
DM
4503sub qemu_set_link_status {
4504 my ($vmid, $device, $up) = @_;
4505
0a13e08e 4506 mon_cmd($vmid, "set_link", name => $device,
25088687
DM
4507 up => $up ? JSON::true : JSON::false);
4508}
4509
2630d2a9 4510sub qemu_netdevadd {
d559309f 4511 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
2630d2a9 4512
d559309f 4513 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
73aa03b8 4514 my %options = split(/[=,]/, $netdev);
2630d2a9 4515
bf5aef9b
DC
4516 if (defined(my $vhost = $options{vhost})) {
4517 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4518 }
4519
4520 if (defined(my $queues = $options{queues})) {
4521 $options{queues} = $queues + 0;
4522 }
4523
0a13e08e 4524 mon_cmd($vmid, "netdev_add", %options);
73aa03b8 4525 return 1;
2630d2a9
DA
4526}
4527
4528sub qemu_netdevdel {
4529 my ($vmid, $deviceid) = @_;
4530
0a13e08e 4531 mon_cmd($vmid, "netdev_del", id => $deviceid);
2630d2a9
DA
4532}
4533
16521d63 4534sub qemu_usb_hotplug {
d559309f 4535 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
16521d63
DC
4536
4537 return if !$device;
4538
4539 # remove the old one first
4540 vm_deviceunplug($vmid, $conf, $deviceid);
4541
4542 # check if xhci controller is necessary and available
4543 if ($device->{usb3}) {
4544
4545 my $devicelist = vm_devices_list($vmid);
4546
4547 if (!$devicelist->{xhci}) {
d559309f 4548 my $pciaddr = print_pci_addr("xhci", undef, $arch, $machine_type);
16521d63
DC
4549 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4550 }
4551 }
4552 my $d = parse_usb_device($device->{host});
4553 $d->{usb3} = $device->{usb3};
4554
4555 # add the new one
d559309f 4556 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
16521d63
DC
4557}
4558
838776ab 4559sub qemu_cpu_hotplug {
8edc9c08 4560 my ($vmid, $conf, $vcpus) = @_;
838776ab 4561
3392d6ca 4562 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
1e881b75 4563
8edc9c08
AD
4564 my $sockets = 1;
4565 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4566 $sockets = $conf->{sockets} if $conf->{sockets};
4567 my $cores = $conf->{cores} || 1;
4568 my $maxcpus = $sockets * $cores;
838776ab 4569
8edc9c08 4570 $vcpus = $maxcpus if !$vcpus;
3a11fadb 4571
8edc9c08
AD
4572 die "you can't add more vcpus than maxcpus\n"
4573 if $vcpus > $maxcpus;
3a11fadb 4574
8edc9c08 4575 my $currentvcpus = $conf->{vcpus} || $maxcpus;
1e881b75 4576
eba3e64d 4577 if ($vcpus < $currentvcpus) {
1e881b75 4578
2ea5fb7e 4579 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
1e881b75
AD
4580
4581 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4582 qemu_devicedel($vmid, "cpu$i");
4583 my $retry = 0;
4584 my $currentrunningvcpus = undef;
4585 while (1) {
65af8c31 4586 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
1e881b75 4587 last if scalar(@{$currentrunningvcpus}) == $i-1;
961af8a3 4588 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
1e881b75
AD
4589 $retry++;
4590 sleep 1;
4591 }
4592 #update conf after each succesfull cpu unplug
4593 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4594 PVE::QemuConfig->write_config($vmid, $conf);
4595 }
4596 } else {
961af8a3 4597 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
1e881b75
AD
4598 }
4599
4600 return;
4601 }
838776ab 4602
65af8c31 4603 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
961af8a3 4604 die "vcpus in running vm does not match its configuration\n"
8edc9c08 4605 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
838776ab 4606
2ea5fb7e 4607 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
eba3e64d
AD
4608
4609 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4610 my $cpustr = print_cpu_device($conf, $i);
4611 qemu_deviceadd($vmid, $cpustr);
4612
4613 my $retry = 0;
4614 my $currentrunningvcpus = undef;
4615 while (1) {
65af8c31 4616 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
eba3e64d 4617 last if scalar(@{$currentrunningvcpus}) == $i;
961af8a3 4618 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
eba3e64d
AD
4619 sleep 1;
4620 $retry++;
4621 }
4622 #update conf after each succesfull cpu hotplug
4623 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4624 PVE::QemuConfig->write_config($vmid, $conf);
4625 }
4626 } else {
4627
4628 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
0a13e08e 4629 mon_cmd($vmid, "cpu-add", id => int($i));
eba3e64d 4630 }
838776ab
AD
4631 }
4632}
4633
affd2f88 4634sub qemu_block_set_io_throttle {
277ca170
WB
4635 my ($vmid, $deviceid,
4636 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
9196a8ec
WB
4637 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4638 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4639 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
affd2f88 4640
f3f323a3
AD
4641 return if !check_running($vmid) ;
4642
0a13e08e 4643 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
277ca170
WB
4644 bps => int($bps),
4645 bps_rd => int($bps_rd),
4646 bps_wr => int($bps_wr),
4647 iops => int($iops),
4648 iops_rd => int($iops_rd),
4649 iops_wr => int($iops_wr),
4650 bps_max => int($bps_max),
4651 bps_rd_max => int($bps_rd_max),
4652 bps_wr_max => int($bps_wr_max),
4653 iops_max => int($iops_max),
4654 iops_rd_max => int($iops_rd_max),
9196a8ec
WB
4655 iops_wr_max => int($iops_wr_max),
4656 bps_max_length => int($bps_max_length),
4657 bps_rd_max_length => int($bps_rd_max_length),
4658 bps_wr_max_length => int($bps_wr_max_length),
4659 iops_max_length => int($iops_max_length),
4660 iops_rd_max_length => int($iops_rd_max_length),
4661 iops_wr_max_length => int($iops_wr_max_length),
277ca170 4662 );
f3f323a3 4663
affd2f88
AD
4664}
4665
c1175c92
AD
4666sub qemu_block_resize {
4667 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4668
ed221350 4669 my $running = check_running($vmid);
c1175c92 4670
7246e8f9 4671 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
c1175c92
AD
4672
4673 return if !$running;
4674
375db731
FE
4675 my $padding = (1024 - $size % 1024) % 1024;
4676 $size = $size + $padding;
4677
190c8461
SR
4678 mon_cmd(
4679 $vmid,
4680 "block_resize",
4681 device => $deviceid,
4682 size => int($size),
4683 timeout => 60,
4684 );
c1175c92
AD
4685}
4686
1ab0057c
AD
4687sub qemu_volume_snapshot {
4688 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4689
ed221350 4690 my $running = check_running($vmid);
1ab0057c 4691
9d83932d 4692 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
0a13e08e 4693 mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
e5eaa028
WL
4694 } else {
4695 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4696 }
1ab0057c
AD
4697}
4698
fc46aff9
AD
4699sub qemu_volume_snapshot_delete {
4700 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4701
ed221350 4702 my $running = check_running($vmid);
fc46aff9 4703
a2f1554b
AD
4704 if($running) {
4705
4706 $running = undef;
4707 my $conf = PVE::QemuConfig->load_config($vmid);
912792e2 4708 PVE::QemuConfig->foreach_volume($conf, sub {
a2f1554b
AD
4709 my ($ds, $drive) = @_;
4710 $running = 1 if $drive->{file} eq $volid;
4711 });
4712 }
4713
9d83932d 4714 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
0a13e08e 4715 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
1ef7592f
AD
4716 } else {
4717 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4718 }
fc46aff9
AD
4719}
4720
264e519f 4721sub set_migration_caps {
27a5be53 4722 my ($vmid, $savevm) = @_;
a89fded1 4723
acc10e51
SR
4724 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4725
27a5be53
SR
4726 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm' : 'pbs-dirty-bitmap-migration';
4727 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4728
8b8345f3 4729 my $cap_ref = [];
a89fded1
AD
4730
4731 my $enabled_cap = {
8b8345f3 4732 "auto-converge" => 1,
0b0a47e8 4733 "xbzrle" => 1,
8b8345f3
DM
4734 "x-rdma-pin-all" => 0,
4735 "zero-blocks" => 0,
acc10e51 4736 "compress" => 0,
27a5be53 4737 "dirty-bitmaps" => $dirty_bitmaps,
a89fded1
AD
4738 };
4739
0a13e08e 4740 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
a89fded1 4741
8b8345f3 4742 for my $supported_capability (@$supported_capabilities) {
b463a3ce
SP
4743 push @$cap_ref, {
4744 capability => $supported_capability->{capability},
22430fa2
DM
4745 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4746 };
a89fded1
AD
4747 }
4748
0a13e08e 4749 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
8b8345f3 4750}
a89fded1 4751
912792e2
FE
4752sub foreach_volid {
4753 my ($conf, $func, @param) = @_;
4754
4755 my $volhash = {};
4756
4757 my $test_volid = sub {
ae180b8f 4758 my ($key, $drive, $snapname) = @_;
912792e2 4759
ae180b8f 4760 my $volid = $drive->{file};
912792e2
FE
4761 return if !$volid;
4762
4763 $volhash->{$volid}->{cdrom} //= 1;
ae180b8f 4764 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
912792e2 4765
ae180b8f 4766 my $replicate = $drive->{replicate} // 1;
912792e2
FE
4767 $volhash->{$volid}->{replicate} //= 0;
4768 $volhash->{$volid}->{replicate} = 1 if $replicate;
4769
4770 $volhash->{$volid}->{shared} //= 0;
ae180b8f 4771 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
912792e2
FE
4772
4773 $volhash->{$volid}->{referenced_in_config} //= 0;
4774 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4775
4776 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4777 if defined($snapname);
ae180b8f
FE
4778
4779 my $size = $drive->{size};
4780 $volhash->{$volid}->{size} //= $size if $size;
4781
4782 $volhash->{$volid}->{is_vmstate} //= 0;
4783 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate';
4784
f9dde219
SR
4785 $volhash->{$volid}->{is_tpmstate} //= 0;
4786 $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0';
4787
ae180b8f
FE
4788 $volhash->{$volid}->{is_unused} //= 0;
4789 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
a6be63ac
FE
4790
4791 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
912792e2
FE
4792 };
4793
ae180b8f
FE
4794 my $include_opts = {
4795 extra_keys => ['vmstate'],
4796 include_unused => 1,
4797 };
4798
0b953b8e 4799 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
912792e2
FE
4800 foreach my $snapname (keys %{$conf->{snapshots}}) {
4801 my $snap = $conf->{snapshots}->{$snapname};
0b953b8e 4802 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
912792e2
FE
4803 }
4804
4805 foreach my $volid (keys %$volhash) {
4806 &$func($volid, $volhash->{$volid}, @param);
4807 }
4808}
4809
81d95ae1 4810my $fast_plug_option = {
7498eb64 4811 'lock' => 1,
81d95ae1 4812 'name' => 1,
a1b7d579 4813 'onboot' => 1,
81d95ae1
DM
4814 'shares' => 1,
4815 'startup' => 1,
b0ec896e 4816 'description' => 1,
ec647db4 4817 'protection' => 1,
8cad5e9b 4818 'vmstatestorage' => 1,
9e784b11 4819 'hookscript' => 1,
b8e7068a 4820 'tags' => 1,
81d95ae1
DM
4821};
4822
3a11fadb
DM
4823# hotplug changes in [PENDING]
4824# $selection hash can be used to only apply specified options, for
4825# example: { cores => 1 } (only apply changed 'cores')
4826# $errors ref is used to return error messages
c427973b 4827sub vmconfig_hotplug_pending {
3a11fadb 4828 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
c427973b 4829
8e90138a 4830 my $defaults = load_defaults();
045749f2
TL
4831 my $arch = get_vm_arch($conf);
4832 my $machine_type = get_vm_machine($conf, undef, $arch);
c427973b
DM
4833
4834 # commit values which do not have any impact on running VM first
3a11fadb
DM
4835 # Note: those option cannot raise errors, we we do not care about
4836 # $selection and always apply them.
4837
4838 my $add_error = sub {
4839 my ($opt, $msg) = @_;
4840 $errors->{$opt} = "hotplug problem - $msg";
4841 };
c427973b
DM
4842
4843 my $changes = 0;
4844 foreach my $opt (keys %{$conf->{pending}}) { # add/change
81d95ae1 4845 if ($fast_plug_option->{$opt}) {
c427973b
DM
4846 $conf->{$opt} = $conf->{pending}->{$opt};
4847 delete $conf->{pending}->{$opt};
4848 $changes = 1;
4849 }
4850 }
4851
4852 if ($changes) {
ffda963f 4853 PVE::QemuConfig->write_config($vmid, $conf);
c427973b
DM
4854 }
4855
b3c2bdd1 4856 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
c427973b 4857
5b65b00d 4858 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
98bc3aeb 4859 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4860 foreach my $opt (sort keys %$pending_delete_hash) {
3a11fadb 4861 next if $selection && !$selection->{$opt};
d321c4a9 4862 my $force = $pending_delete_hash->{$opt}->{force};
3a11fadb 4863 eval {
51a6f637
AD
4864 if ($opt eq 'hotplug') {
4865 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4866 } elsif ($opt eq 'tablet') {
b3c2bdd1 4867 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4868 if ($defaults->{tablet}) {
d559309f
WB
4869 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4870 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4871 if $arch eq 'aarch64';
3a11fadb 4872 } else {
d559309f
WB
4873 vm_deviceunplug($vmid, $conf, 'tablet');
4874 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4875 }
4eb68604 4876 } elsif ($opt =~ m/^usb\d+/) {
f745762b 4877 die "skip\n";
50bbe377
TL
4878 # since we cannot reliably hot unplug usb devices we are disabling it
4879 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4880 #vm_deviceunplug($vmid, $conf, $opt);
8edc9c08 4881 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4882 die "skip\n" if !$hotplug_features->{cpu};
8edc9c08 4883 qemu_cpu_hotplug($vmid, $conf, undef);
9c2f7069 4884 } elsif ($opt eq 'balloon') {
81d95ae1 4885 # enable balloon device is not hotpluggable
75b51053
DC
4886 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4887 # here we reset the ballooning value to memory
4888 my $balloon = $conf->{memory} || $defaults->{memory};
0a13e08e 4889 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
81d95ae1
DM
4890 } elsif ($fast_plug_option->{$opt}) {
4891 # do nothing
3eec5767 4892 } elsif ($opt =~ m/^net(\d+)$/) {
b3c2bdd1 4893 die "skip\n" if !$hotplug_features->{network};
3eec5767 4894 vm_deviceunplug($vmid, $conf, $opt);
74479ee9 4895 } elsif (is_valid_drivename($opt)) {
b3c2bdd1 4896 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
19120f99 4897 vm_deviceunplug($vmid, $conf, $opt);
3dc38fbb 4898 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4d3f29ed
AD
4899 } elsif ($opt =~ m/^memory$/) {
4900 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4901 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
c8effec3 4902 } elsif ($opt eq 'cpuunits') {
d3f9db4d 4903 $cgroup->change_cpu_shares(undef, 1024);
58be00f1 4904 } elsif ($opt eq 'cpulimit') {
25de70ae 4905 $cgroup->change_cpu_quota(undef, undef); # reset, cgroup module can better decide values
3d7389fe 4906 } else {
e56beeda 4907 die "skip\n";
3d7389fe 4908 }
3a11fadb
DM
4909 };
4910 if (my $err = $@) {
e56beeda
DM
4911 &$add_error($opt, $err) if $err ne "skip\n";
4912 } else {
3a11fadb 4913 delete $conf->{$opt};
98bc3aeb 4914 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
3d7389fe 4915 }
3d7389fe
DM
4916 }
4917
e5a66e48 4918 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
9ed7a77c 4919 $apply_pending_cloudinit = sub {
e5a66e48
WB
4920 return if $apply_pending_cloudinit_done; # once is enough
4921 $apply_pending_cloudinit_done = 1; # once is enough
4922
9ed7a77c 4923 my ($key, $value) = @_;
9ed7a77c
WB
4924
4925 my @cloudinit_opts = keys %$confdesc_cloudinit;
4926 foreach my $opt (keys %{$conf->{pending}}) {
4927 next if !grep { $_ eq $opt } @cloudinit_opts;
4928 $conf->{$opt} = delete $conf->{pending}->{$opt};
4929 }
4930
e6ec384f
AD
4931 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4932 foreach my $opt (sort keys %$pending_delete_hash) {
4933 next if !grep { $_ eq $opt } @cloudinit_opts;
4934 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4935 delete $conf->{$opt};
4936 }
4937
9ed7a77c
WB
4938 my $new_conf = { %$conf };
4939 $new_conf->{$key} = $value;
4940 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4941 };
4942
3d7389fe 4943 foreach my $opt (keys %{$conf->{pending}}) {
3a11fadb 4944 next if $selection && !$selection->{$opt};
3d7389fe 4945 my $value = $conf->{pending}->{$opt};
3a11fadb 4946 eval {
51a6f637
AD
4947 if ($opt eq 'hotplug') {
4948 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4949 } elsif ($opt eq 'tablet') {
b3c2bdd1 4950 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4951 if ($value == 1) {
d559309f
WB
4952 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4953 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4954 if $arch eq 'aarch64';
3a11fadb 4955 } elsif ($value == 0) {
d559309f
WB
4956 vm_deviceunplug($vmid, $conf, 'tablet');
4957 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4958 }
4eb68604 4959 } elsif ($opt =~ m/^usb\d+$/) {
f745762b 4960 die "skip\n";
50bbe377
TL
4961 # since we cannot reliably hot unplug usb devices we disable it for now
4962 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4963 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4964 #die "skip\n" if !$d;
4965 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
8edc9c08 4966 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4967 die "skip\n" if !$hotplug_features->{cpu};
3a11fadb
DM
4968 qemu_cpu_hotplug($vmid, $conf, $value);
4969 } elsif ($opt eq 'balloon') {
81d95ae1 4970 # enable/disable balloning device is not hotpluggable
8fe689e7 4971 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
a1b7d579 4972 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
81d95ae1
DM
4973 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4974
3a11fadb 4975 # allow manual ballooning if shares is set to zero
4cc1efa6 4976 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
9c2f7069 4977 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
0a13e08e 4978 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
9c2f7069 4979 }
a1b7d579 4980 } elsif ($opt =~ m/^net(\d+)$/) {
3eec5767 4981 # some changes can be done without hotplug
a1b7d579 4982 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
d559309f 4983 $vmid, $opt, $value, $arch, $machine_type);
74479ee9 4984 } elsif (is_valid_drivename($opt)) {
f9dde219 4985 die "skip\n" if $opt eq 'efidisk0' || $opt eq 'tpmstate0';
a05cff86 4986 # some changes can be done without hotplug
9ed7a77c
WB
4987 my $drive = parse_drive($opt, $value);
4988 if (drive_is_cloudinit($drive)) {
4989 &$apply_pending_cloudinit($opt, $value);
4990 }
b3c2bdd1 4991 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
9e7bce2c 4992 $vmid, $opt, $value, $arch, $machine_type);
4d3f29ed
AD
4993 } elsif ($opt =~ m/^memory$/) { #dimms
4994 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4995 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
c8effec3 4996 } elsif ($opt eq 'cpuunits') {
64cc310f
TL
4997 my $new_cpuunits = get_cpuunits({ $opt => $conf->{pending}->{$opt} }); # to clamp
4998 $cgroup->change_cpu_shares($new_cpuunits, 1024);
58be00f1 4999 } elsif ($opt eq 'cpulimit') {
c6f773b8 5000 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
5b65b00d 5001 $cgroup->change_cpu_quota($cpulimit, 100000);
74ea2c65
AD
5002 } elsif ($opt eq 'agent') {
5003 vmconfig_update_agent($conf, $opt, $value);
3a11fadb 5004 } else {
e56beeda 5005 die "skip\n"; # skip non-hot-pluggable options
3d7389fe 5006 }
3a11fadb
DM
5007 };
5008 if (my $err = $@) {
e56beeda
DM
5009 &$add_error($opt, $err) if $err ne "skip\n";
5010 } else {
3a11fadb
DM
5011 $conf->{$opt} = $value;
5012 delete $conf->{pending}->{$opt};
3d7389fe 5013 }
3d7389fe 5014 }
4df15a03
OB
5015
5016 PVE::QemuConfig->write_config($vmid, $conf);
c427973b 5017}
055d554d 5018
3dc38fbb
WB
5019sub try_deallocate_drive {
5020 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
5021
5022 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
5023 my $volid = $drive->{file};
5024 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
5025 my $sid = PVE::Storage::parse_volume_id($volid);
5026 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
cee01bcb
WB
5027
5028 # check if the disk is really unused
cee01bcb 5029 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
e0fd2b2f 5030 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
cee01bcb 5031 PVE::Storage::vdisk_free($storecfg, $volid);
3dc38fbb 5032 return 1;
40b977f3
WL
5033 } else {
5034 # If vm is not owner of this disk remove from config
5035 return 1;
3dc38fbb
WB
5036 }
5037 }
5038
d1c1af4b 5039 return;
3dc38fbb
WB
5040}
5041
5042sub vmconfig_delete_or_detach_drive {
5043 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
5044
5045 my $drive = parse_drive($opt, $conf->{$opt});
5046
5047 my $rpcenv = PVE::RPCEnvironment::get();
5048 my $authuser = $rpcenv->get_user();
5049
5050 if ($force) {
5051 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
5052 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
5053 } else {
5054 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
5055 }
5056}
5057
98bc3aeb
OB
5058
5059
055d554d 5060sub vmconfig_apply_pending {
eb5e482d
OB
5061 my ($vmid, $conf, $storecfg, $errors) = @_;
5062
a644de29
OB
5063 return if !scalar(keys %{$conf->{pending}});
5064
eb5e482d
OB
5065 my $add_apply_error = sub {
5066 my ($opt, $msg) = @_;
5067 my $err_msg = "unable to apply pending change $opt : $msg";
5068 $errors->{$opt} = $err_msg;
5069 warn $err_msg;
5070 };
c427973b
DM
5071
5072 # cold plug
055d554d 5073
98bc3aeb 5074 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 5075 foreach my $opt (sort keys %$pending_delete_hash) {
fb4d1ba2 5076 my $force = $pending_delete_hash->{$opt}->{force};
eb5e482d 5077 eval {
3d48b95a
OB
5078 if ($opt =~ m/^unused/) {
5079 die "internal error";
5080 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 5081 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
eb5e482d
OB
5082 }
5083 };
5084 if (my $err = $@) {
5085 $add_apply_error->($opt, $err);
055d554d 5086 } else {
98bc3aeb 5087 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
055d554d 5088 delete $conf->{$opt};
055d554d
DM
5089 }
5090 }
5091
3d48b95a 5092 PVE::QemuConfig->cleanup_pending($conf);
055d554d
DM
5093
5094 foreach my $opt (keys %{$conf->{pending}}) { # add/change
3d48b95a 5095 next if $opt eq 'delete'; # just to be sure
eb5e482d 5096 eval {
3d48b95a 5097 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 5098 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
eb5e482d
OB
5099 }
5100 };
5101 if (my $err = $@) {
5102 $add_apply_error->($opt, $err);
055d554d 5103 } else {
eb5e482d 5104 $conf->{$opt} = delete $conf->{pending}->{$opt};
055d554d 5105 }
055d554d 5106 }
3d48b95a
OB
5107
5108 # write all changes at once to avoid unnecessary i/o
5109 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
5110}
5111
3eec5767 5112sub vmconfig_update_net {
d559309f 5113 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
3eec5767
DM
5114
5115 my $newnet = parse_net($value);
5116
5117 if ($conf->{$opt}) {
5118 my $oldnet = parse_net($conf->{$opt});
5119
0f1af9e7
OB
5120 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5121 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5122 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
3eec5767
DM
5123 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5124
5125 # for non online change, we try to hot-unplug
7196b757 5126 die "skip\n" if !$hotplug;
3eec5767
DM
5127 vm_deviceunplug($vmid, $conf, $opt);
5128 } else {
5129
5130 die "internal error" if $opt !~ m/net(\d+)/;
5131 my $iface = "tap${vmid}i$1";
a1b7d579 5132
0f1af9e7
OB
5133 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5134 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
5135 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
5136 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
3eec5767 5137 PVE::Network::tap_unplug($iface);
28e129cc
AD
5138
5139 if ($have_sdn) {
5140 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5141 } else {
5142 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5143 }
0f1af9e7 5144 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4f4fbeb0
WB
5145 # Rate can be applied on its own but any change above needs to
5146 # include the rate in tap_plug since OVS resets everything.
5147 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
3eec5767 5148 }
38c590d9 5149
0f1af9e7 5150 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
25088687
DM
5151 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5152 }
5153
38c590d9 5154 return 1;
3eec5767
DM
5155 }
5156 }
a1b7d579 5157
7196b757 5158 if ($hotplug) {
d559309f 5159 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
38c590d9
DM
5160 } else {
5161 die "skip\n";
5162 }
3eec5767
DM
5163}
5164
74ea2c65
AD
5165sub vmconfig_update_agent {
5166 my ($conf, $opt, $value) = @_;
5167
5168 die "skip\n" if !$conf->{$opt};
5169
5170 my $hotplug_options = { fstrim_cloned_disks => 1 };
5171
5172 my $old_agent = parse_guest_agent($conf);
5173 my $agent = parse_guest_agent({$opt => $value});
5174
33f8b887 5175 for my $option (keys %$agent) { # added/changed options
74ea2c65
AD
5176 next if defined($hotplug_options->{$option});
5177 die "skip\n" if safe_string_ne($agent->{$option}, $old_agent->{$option});
5178 }
5179
33f8b887 5180 for my $option (keys %$old_agent) { # removed options
74ea2c65
AD
5181 next if defined($hotplug_options->{$option});
5182 die "skip\n" if safe_string_ne($old_agent->{$option}, $agent->{$option});
5183 }
33f8b887
TL
5184
5185 return; # either no actual change (e.g., format string reordered) or just hotpluggable changes
74ea2c65
AD
5186}
5187
a05cff86 5188sub vmconfig_update_disk {
9e7bce2c 5189 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
a05cff86
DM
5190
5191 my $drive = parse_drive($opt, $value);
5192
4df98f2f
TL
5193 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
5194 my $media = $drive->{media} || 'disk';
5195 my $oldmedia = $old_drive->{media} || 'disk';
5196 die "unable to change media type\n" if $media ne $oldmedia;
a05cff86 5197
4df98f2f 5198 if (!drive_is_cdrom($old_drive)) {
a05cff86 5199
4df98f2f 5200 if ($drive->{file} ne $old_drive->{file}) {
a05cff86 5201
4df98f2f 5202 die "skip\n" if !$hotplug;
a05cff86 5203
4df98f2f
TL
5204 # unplug and register as unused
5205 vm_deviceunplug($vmid, $conf, $opt);
5206 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
a1b7d579 5207
4df98f2f
TL
5208 } else {
5209 # update existing disk
5210
5211 # skip non hotpluggable value
5212 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5213 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5214 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5215 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
5216 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
5217 die "skip\n";
5218 }
a05cff86 5219
4df98f2f
TL
5220 # apply throttle
5221 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5222 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5223 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5224 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5225 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5226 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5227 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5228 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5229 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5230 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5231 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5232 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5233 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5234 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5235 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5236 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5237 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5238 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5239
5240 qemu_block_set_io_throttle(
5241 $vmid,"drive-$opt",
5242 ($drive->{mbps} || 0)*1024*1024,
5243 ($drive->{mbps_rd} || 0)*1024*1024,
5244 ($drive->{mbps_wr} || 0)*1024*1024,
5245 $drive->{iops} || 0,
5246 $drive->{iops_rd} || 0,
5247 $drive->{iops_wr} || 0,
5248 ($drive->{mbps_max} || 0)*1024*1024,
5249 ($drive->{mbps_rd_max} || 0)*1024*1024,
5250 ($drive->{mbps_wr_max} || 0)*1024*1024,
5251 $drive->{iops_max} || 0,
5252 $drive->{iops_rd_max} || 0,
5253 $drive->{iops_wr_max} || 0,
5254 $drive->{bps_max_length} || 1,
5255 $drive->{bps_rd_max_length} || 1,
5256 $drive->{bps_wr_max_length} || 1,
5257 $drive->{iops_max_length} || 1,
5258 $drive->{iops_rd_max_length} || 1,
5259 $drive->{iops_wr_max_length} || 1,
5260 );
a05cff86 5261
4df98f2f 5262 }
a1b7d579 5263
4df98f2f
TL
5264 return 1;
5265 }
4de1bb25 5266
4df98f2f 5267 } else { # cdrom
a1b7d579 5268
4df98f2f
TL
5269 if ($drive->{file} eq 'none') {
5270 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5271 if (drive_is_cloudinit($old_drive)) {
5272 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5273 }
5274 } else {
5275 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
ce9fce79 5276
4df98f2f
TL
5277 # force eject if locked
5278 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
ce9fce79 5279
4df98f2f
TL
5280 if ($path) {
5281 mon_cmd($vmid, "blockdev-change-medium",
5282 id => "$opt", filename => "$path");
4de1bb25 5283 }
a05cff86 5284 }
4df98f2f
TL
5285
5286 return 1;
a05cff86
DM
5287 }
5288 }
5289
a1b7d579 5290 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4de1bb25 5291 # hotplug new disks
f7b4356f 5292 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
d559309f 5293 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
a05cff86
DM
5294}
5295
13cfe3b7 5296# called in locked context by incoming migration
ba5396b5
FG
5297sub vm_migrate_get_nbd_disks {
5298 my ($storecfg, $conf, $replicated_volumes) = @_;
13cfe3b7
FG
5299
5300 my $local_volumes = {};
912792e2 5301 PVE::QemuConfig->foreach_volume($conf, sub {
13cfe3b7
FG
5302 my ($ds, $drive) = @_;
5303
5304 return if drive_is_cdrom($drive);
41c8671e 5305 return if $ds eq 'tpmstate0';
13cfe3b7
FG
5306
5307 my $volid = $drive->{file};
5308
5309 return if !$volid;
5310
5311 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5312
5313 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5314 return if $scfg->{shared};
ba5396b5
FG
5315
5316 # replicated disks re-use existing state via bitmap
5317 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
5318 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
13cfe3b7 5319 });
ba5396b5
FG
5320 return $local_volumes;
5321}
5322
5323# called in locked context by incoming migration
5324sub vm_migrate_alloc_nbd_disks {
5325 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
13cfe3b7 5326
13cfe3b7 5327 my $nbd = {};
ba5396b5 5328 foreach my $opt (sort keys %$source_volumes) {
5668463b 5329 my ($volid, $storeid, $volname, $drive, $use_existing, $format) = @{$source_volumes->{$opt}};
ba5396b5
FG
5330
5331 if ($use_existing) {
5332 $nbd->{$opt}->{drivestr} = print_drive($drive);
5333 $nbd->{$opt}->{volid} = $volid;
5334 $nbd->{$opt}->{replicated} = 1;
13cfe3b7
FG
5335 next;
5336 }
13cfe3b7 5337
5668463b
FG
5338 # storage mapping + volname = regular migration
5339 # storage mapping + format = remote migration
5340 # order of precedence, filtered by whether storage supports it:
5341 # 1. explicit requested format
5342 # 2. format of current volume
5343 # 3. default format of storage
bf8fc5a3 5344 if (!$storagemap->{identity}) {
82a03671 5345 $storeid = PVE::JSONSchema::map_id($storagemap, $storeid);
13cfe3b7 5346 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5668463b
FG
5347 if (!$format || !grep { $format eq $_ } @$validFormats) {
5348 if ($volname) {
5349 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5350 my $fileFormat = qemu_img_format($scfg, $volname);
5351 $format = $fileFormat
5352 if grep { $fileFormat eq $_ } @$validFormats;
5353 }
5354 $format //= $defFormat;
5355 }
13cfe3b7 5356 } else {
5668463b 5357 # can't happen for remote migration, so $volname is always defined
13cfe3b7
FG
5358 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5359 $format = qemu_img_format($scfg, $volname);
5360 }
5361
4df98f2f
TL
5362 my $size = $drive->{size} / 1024;
5363 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
13cfe3b7
FG
5364 my $newdrive = $drive;
5365 $newdrive->{format} = $format;
5366 $newdrive->{file} = $newvolid;
5367 my $drivestr = print_drive($newdrive);
ba5396b5
FG
5368 $nbd->{$opt}->{drivestr} = $drivestr;
5369 $nbd->{$opt}->{volid} = $newvolid;
13cfe3b7
FG
5370 }
5371
5372 return $nbd;
5373}
5374
5375# see vm_start_nolock for parameters, additionally:
5376# migrate_opts:
bf8fc5a3 5377# storagemap = parsed storage map for allocating NBD disks
3898a563
FG
5378sub vm_start {
5379 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5380
84da8217 5381 return PVE::QemuConfig->lock_config($vmid, sub {
3898a563
FG
5382 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
5383
4ef13a7f
FG
5384 die "you can't start a vm if it's a template\n"
5385 if !$params->{skiptemplate} && PVE::QemuConfig->is_template($conf);
3898a563 5386
d544e0e0 5387 my $has_suspended_lock = PVE::QemuConfig->has_lock($conf, 'suspended');
8e0c97bb
SR
5388 my $has_backup_lock = PVE::QemuConfig->has_lock($conf, 'backup');
5389
5390 my $running = check_running($vmid, undef, $migrate_opts->{migratedfrom});
5391
5392 if ($has_backup_lock && $running) {
5393 # a backup is currently running, attempt to start the guest in the
5394 # existing QEMU instance
5395 return vm_resume($vmid);
5396 }
3898a563
FG
5397
5398 PVE::QemuConfig->check_lock($conf)
d544e0e0
FE
5399 if !($params->{skiplock} || $has_suspended_lock);
5400
5401 $params->{resume} = $has_suspended_lock || defined($conf->{vmstate});
3898a563 5402
8e0c97bb 5403 die "VM $vmid already running\n" if $running;
3898a563 5404
ba5396b5
FG
5405 if (my $storagemap = $migrate_opts->{storagemap}) {
5406 my $replicated = $migrate_opts->{replicated_volumes};
5407 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
5408 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
5409
5410 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
5411 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
5412 }
5413 }
13cfe3b7 5414
84da8217 5415 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
3898a563
FG
5416 });
5417}
5418
5419
0c498cca
FG
5420# params:
5421# statefile => 'tcp', 'unix' for migration or path/volid for RAM state
5422# skiplock => 0/1, skip checking for config lock
4ef13a7f 5423# skiptemplate => 0/1, skip checking whether VM is template
0c498cca 5424# forcemachine => to force Qemu machine (rollback/migration)
58c64ad5 5425# forcecpu => a QEMU '-cpu' argument string to override get_cpu_options
0c498cca
FG
5426# timeout => in seconds
5427# paused => start VM in paused state (backup)
3898a563 5428# resume => resume from hibernation
5921764c
SR
5429# pbs-backing => {
5430# sata0 => {
5431# repository
5432# snapshot
5433# keyfile
5434# archive
5435# },
5436# virtio2 => ...
5437# }
0c498cca 5438# migrate_opts:
ba5396b5 5439# nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
0c498cca
FG
5440# migratedfrom => source node
5441# spice_ticket => used for spice migration, passed via tunnel/stdin
5442# network => CIDR of migration network
5443# type => secure/insecure - tunnel over encrypted connection or plain-text
0c498cca 5444# nbd_proto_version => int, 0 for TCP, 1 for UNIX
fd95d780 5445# replicated_volumes => which volids should be re-used with bitmaps for nbd migration
13d121d7
FE
5446# offline_volumes => new volids of offline migrated disks like tpmstate and cloudinit, not yet
5447# contained in config
3898a563
FG
5448sub vm_start_nolock {
5449 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
1e3baf05 5450
3898a563
FG
5451 my $statefile = $params->{statefile};
5452 my $resume = $params->{resume};
3dcb98d5 5453
3898a563
FG
5454 my $migratedfrom = $migrate_opts->{migratedfrom};
5455 my $migration_type = $migrate_opts->{type};
7ceade4c 5456
84da8217
FG
5457 my $res = {};
5458
3898a563
FG
5459 # clean up leftover reboot request files
5460 eval { clear_reboot_request($vmid); };
5461 warn $@ if $@;
1e3baf05 5462
3898a563
FG
5463 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5464 vmconfig_apply_pending($vmid, $conf, $storecfg);
5465 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5466 }
64457ed4 5467
104f47a9
ML
5468 # don't regenerate the ISO if the VM is started as part of a live migration
5469 # this way we can reuse the old ISO with the correct config
5470 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid) if !$migratedfrom;
055d554d 5471
13d121d7
FE
5472 # override offline migrated volumes, conf is out of date still
5473 if (my $offline_volumes = $migrate_opts->{offline_volumes}) {
5474 for my $key (sort keys $offline_volumes->%*) {
5475 my $parsed = parse_drive($key, $conf->{$key});
5476 $parsed->{file} = $offline_volumes->{$key};
5477 $conf->{$key} = print_drive($parsed);
5478 }
fd95d780
FG
5479 }
5480
3898a563 5481 my $defaults = load_defaults();
0c9a7596 5482
3898a563
FG
5483 # set environment variable useful inside network script
5484 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
6c47d546 5485
3898a563 5486 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
9e784b11 5487
3898a563 5488 my $forcemachine = $params->{forcemachine};
ea1c2110 5489 my $forcecpu = $params->{forcecpu};
3898a563 5490 if ($resume) {
ea1c2110 5491 # enforce machine and CPU type on suspended vm to ensure HW compatibility
3898a563 5492 $forcemachine = $conf->{runningmachine};
ea1c2110 5493 $forcecpu = $conf->{runningcpu};
3898a563
FG
5494 print "Resuming suspended VM\n";
5495 }
7ceade4c 5496
5921764c
SR
5497 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid,
5498 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
6c47d546 5499
3898a563
FG
5500 my $migration_ip;
5501 my $get_migration_ip = sub {
5502 my ($nodename) = @_;
b24e1ac2 5503
3898a563 5504 return $migration_ip if defined($migration_ip);
b24e1ac2 5505
3898a563 5506 my $cidr = $migrate_opts->{network};
0c498cca 5507
3898a563
FG
5508 if (!defined($cidr)) {
5509 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
5510 $cidr = $dc_conf->{migration}->{network};
5511 }
b24e1ac2 5512
3898a563
FG
5513 if (defined($cidr)) {
5514 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
b24e1ac2 5515
3898a563
FG
5516 die "could not get IP: no address configured on local " .
5517 "node for network '$cidr'\n" if scalar(@$ips) == 0;
b24e1ac2 5518
3898a563
FG
5519 die "could not get IP: multiple addresses configured on local " .
5520 "node for network '$cidr'\n" if scalar(@$ips) > 1;
b24e1ac2 5521
3898a563
FG
5522 $migration_ip = @$ips[0];
5523 }
b24e1ac2 5524
3898a563
FG
5525 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
5526 if !defined($migration_ip);
b24e1ac2 5527
3898a563
FG
5528 return $migration_ip;
5529 };
b24e1ac2 5530
3898a563
FG
5531 my $migrate_uri;
5532 if ($statefile) {
5533 if ($statefile eq 'tcp') {
5534 my $localip = "localhost";
5535 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
5536 my $nodename = nodename();
2de2d6f7 5537
3898a563
FG
5538 if (!defined($migration_type)) {
5539 if (defined($datacenterconf->{migration}->{type})) {
5540 $migration_type = $datacenterconf->{migration}->{type};
5541 } else {
5542 $migration_type = 'secure';
b7a5a225 5543 }
3898a563 5544 }
b7a5a225 5545
3898a563
FG
5546 if ($migration_type eq 'insecure') {
5547 $localip = $get_migration_ip->($nodename);
5548 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5549 }
2de2d6f7 5550
3898a563
FG
5551 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5552 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5553 $migrate_uri = "tcp:${localip}:${migrate_port}";
5554 push @$cmd, '-incoming', $migrate_uri;
5555 push @$cmd, '-S';
1c9d54bf 5556
3898a563
FG
5557 } elsif ($statefile eq 'unix') {
5558 # should be default for secure migrations as a ssh TCP forward
5559 # tunnel is not deterministic reliable ready and fails regurarly
5560 # to set up in time, so use UNIX socket forwards
5561 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5562 unlink $socket_addr;
54323eed 5563
3898a563 5564 $migrate_uri = "unix:$socket_addr";
1c9d54bf 5565
3898a563
FG
5566 push @$cmd, '-incoming', $migrate_uri;
5567 push @$cmd, '-S';
1c9d54bf 5568
3898a563
FG
5569 } elsif (-e $statefile) {
5570 push @$cmd, '-loadstate', $statefile;
5571 } else {
5572 my $statepath = PVE::Storage::path($storecfg, $statefile);
5573 push @$vollist, $statefile;
5574 push @$cmd, '-loadstate', $statepath;
5575 }
5576 } elsif ($params->{paused}) {
5577 push @$cmd, '-S';
5578 }
5579
1fb1822e
DC
5580 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
5581
5582 my $pci_devices = {}; # host pci devices
74c17b7a 5583 for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++) {
1fb1822e
DC
5584 my $dev = $conf->{"hostpci$i"} or next;
5585 $pci_devices->{$i} = parse_hostpci($dev);
5586 }
5587
9c85548f
DC
5588 # do not reserve pciid for mediated devices, sysfs will error out for duplicate assignment
5589 my $real_pci_devices = [ grep { !(defined($_->{mdev}) && scalar($_->{pciid}->@*) == 1) } values $pci_devices->%* ];
5590
5591 # map to a flat list of pci ids
5592 my $pci_id_list = [ map { $_->{id} } map { $_->{pciid}->@* } $real_pci_devices->@* ];
5593
1fb1822e
DC
5594 # reserve all PCI IDs before actually doing anything with them
5595 PVE::QemuServer::PCI::reserve_pci_usage($pci_id_list, $vmid, $start_timeout);
5596
5597 eval {
bbf96e0f 5598 my $uuid;
1fb1822e
DC
5599 for my $id (sort keys %$pci_devices) {
5600 my $d = $pci_devices->{$id};
5601 for my $dev ($d->{pciid}->@*) {
bbf96e0f
DC
5602 my $info = PVE::QemuServer::PCI::prepare_pci_device($vmid, $dev->{id}, $id, $d->{mdev});
5603
5604 # nvidia grid needs the uuid of the mdev as qemu parameter
5605 if ($d->{mdev} && !defined($uuid) && $info->{vendor} eq '10de') {
5606 $uuid = PVE::QemuServer::PCI::generate_mdev_uuid($vmid, $id);
5607 }
1fb1822e
DC
5608 }
5609 }
bbf96e0f 5610 push @$cmd, '-uuid', $uuid if defined($uuid);
1fb1822e
DC
5611 };
5612 if (my $err = $@) {
b4415a52 5613 eval { PVE::QemuServer::PCI::remove_pci_reservation($pci_id_list) };
1fb1822e
DC
5614 warn $@ if $@;
5615 die $err;
3898a563 5616 }
1e3baf05 5617
3898a563 5618 PVE::Storage::activate_volumes($storecfg, $vollist);
1e3baf05 5619
3898a563 5620 eval {
6bbcd71f 5621 run_command(['/bin/systemctl', 'stop', "$vmid.scope"], outfunc => sub{}, errfunc => sub{});
3898a563
FG
5622 };
5623 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5624 # timeout should be more than enough here...
39abafc8 5625 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 20);
3898a563 5626
d3f9db4d 5627 my $cpuunits = get_cpuunits($conf);
3898a563 5628
3898a563
FG
5629 my %run_params = (
5630 timeout => $statefile ? undef : $start_timeout,
5631 umask => 0077,
5632 noerr => 1,
5633 );
1e3baf05 5634
3898a563
FG
5635 # when migrating, prefix QEMU output so other side can pick up any
5636 # errors that might occur and show the user
5637 if ($migratedfrom) {
5638 $run_params{quiet} = 1;
5639 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
5640 }
8bf30c2a 5641
212220a4 5642 my %systemd_properties = (
3898a563 5643 Slice => 'qemu.slice',
354e61aa
SR
5644 KillMode => 'process',
5645 SendSIGKILL => 0,
5646 TimeoutStopUSec => ULONG_MAX, # infinity
3898a563 5647 );
7023f3ea 5648
6cbd3eb8 5649 if (PVE::CGroup::cgroup_mode() == 2) {
212220a4 5650 $systemd_properties{CPUWeight} = $cpuunits;
6cbd3eb8 5651 } else {
212220a4 5652 $systemd_properties{CPUShares} = $cpuunits;
6cbd3eb8
AD
5653 }
5654
3898a563 5655 if (my $cpulimit = $conf->{cpulimit}) {
212220a4 5656 $systemd_properties{CPUQuota} = int($cpulimit * 100);
3898a563 5657 }
212220a4 5658 $systemd_properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
7023f3ea 5659
3898a563
FG
5660 my $run_qemu = sub {
5661 PVE::Tools::run_fork sub {
212220a4 5662 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %systemd_properties);
6e0216d8 5663
f9dde219
SR
5664 my $tpmpid;
5665 if (my $tpm = $conf->{tpmstate0}) {
5666 # start the TPM emulator so QEMU can connect on start
5667 $tpmpid = start_swtpm($storecfg, $vmid, $tpm, $migratedfrom);
5668 }
5669
3898a563 5670 my $exitcode = run_command($cmd, %run_params);
f9dde219 5671 if ($exitcode) {
23bee97d
FE
5672 if ($tpmpid) {
5673 warn "stopping swtpm instance (pid $tpmpid) due to QEMU startup error\n";
5674 kill 'TERM', $tpmpid;
5675 }
f9dde219
SR
5676 die "QEMU exited with code $exitcode\n";
5677 }
503308ed 5678 };
3898a563 5679 };
503308ed 5680
3898a563 5681 if ($conf->{hugepages}) {
7023f3ea 5682
3898a563
FG
5683 my $code = sub {
5684 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5685 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
7023f3ea 5686
3898a563
FG
5687 PVE::QemuServer::Memory::hugepages_mount();
5688 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
7023f3ea 5689
503308ed 5690 eval { $run_qemu->() };
3898a563 5691 if (my $err = $@) {
f36e9894
SR
5692 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology)
5693 if !$conf->{keephugepages};
3898a563
FG
5694 die $err;
5695 }
77cde36b 5696
f36e9894
SR
5697 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology)
5698 if !$conf->{keephugepages};
3898a563
FG
5699 };
5700 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
1e3baf05 5701
3898a563
FG
5702 } else {
5703 eval { $run_qemu->() };
5704 }
afdb31d5 5705
3898a563
FG
5706 if (my $err = $@) {
5707 # deactivate volumes if start fails
5708 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
b4415a52 5709 eval { PVE::QemuServer::PCI::remove_pci_reservation($pci_id_list) };
1fb1822e 5710
3898a563
FG
5711 die "start failed: $err";
5712 }
62de2cbd 5713
1fb1822e
DC
5714 # re-reserve all PCI IDs now that we can know the actual VM PID
5715 my $pid = PVE::QemuServer::Helpers::vm_running_locally($vmid);
5716 eval { PVE::QemuServer::PCI::reserve_pci_usage($pci_id_list, $vmid, undef, $pid) };
5717 warn $@ if $@;
5718
3898a563 5719 print "migration listens on $migrate_uri\n" if $migrate_uri;
84da8217 5720 $res->{migrate_uri} = $migrate_uri;
eb8cddb5 5721
3898a563
FG
5722 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5723 eval { mon_cmd($vmid, "cont"); };
5724 warn $@ if $@;
5725 }
2189246c 5726
3898a563 5727 #start nbd server for storage migration
13cfe3b7 5728 if (my $nbd = $migrate_opts->{nbd}) {
3898a563 5729 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
2189246c 5730
3898a563
FG
5731 my $migrate_storage_uri;
5732 # nbd_protocol_version > 0 for unix socket support
5733 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5734 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5735 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix', data => { path => $socket_path } } );
5736 $migrate_storage_uri = "nbd:unix:$socket_path";
5737 } else {
5738 my $nodename = nodename();
5739 my $localip = $get_migration_ip->($nodename);
5740 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5741 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5742
4df98f2f
TL
5743 mon_cmd($vmid, "nbd-server-start", addr => {
5744 type => 'inet',
5745 data => {
5746 host => "${localip}",
5747 port => "${storage_migrate_port}",
5748 },
5749 });
3898a563
FG
5750 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5751 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
2189246c
AD
5752 }
5753
84da8217
FG
5754 $res->{migrate_storage_uri} = $migrate_storage_uri;
5755
13cfe3b7 5756 foreach my $opt (sort keys %$nbd) {
ba5396b5
FG
5757 my $drivestr = $nbd->{$opt}->{drivestr};
5758 my $volid = $nbd->{$opt}->{volid};
3898a563 5759 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
84da8217
FG
5760 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5761 print "storage migration listens on $nbd_uri volume:$drivestr\n";
ba5396b5
FG
5762 print "re-using replicated volume: $opt - $volid\n"
5763 if $nbd->{$opt}->{replicated};
84da8217
FG
5764
5765 $res->{drives}->{$opt} = $nbd->{$opt};
5766 $res->{drives}->{$opt}->{nbd_uri} = $nbd_uri;
3898a563
FG
5767 }
5768 }
a89fded1 5769
3898a563
FG
5770 if ($migratedfrom) {
5771 eval {
5772 set_migration_caps($vmid);
5773 };
5774 warn $@ if $@;
5775
5776 if ($spice_port) {
5777 print "spice listens on port $spice_port\n";
84da8217 5778 $res->{spice_port} = $spice_port;
3898a563 5779 if ($migrate_opts->{spice_ticket}) {
4df98f2f
TL
5780 mon_cmd($vmid, "set_password", protocol => 'spice', password =>
5781 $migrate_opts->{spice_ticket});
3898a563 5782 mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
95a4b4a9 5783 }
3898a563 5784 }
95a4b4a9 5785
3898a563
FG
5786 } else {
5787 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5788 if !$statefile && $conf->{balloon};
25088687 5789
3898a563
FG
5790 foreach my $opt (keys %$conf) {
5791 next if $opt !~ m/^net\d+$/;
5792 my $nicconf = parse_net($conf->{$opt});
5793 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
e18b0b99 5794 }
3898a563 5795 }
a1b7d579 5796
3898a563
FG
5797 mon_cmd($vmid, 'qom-set',
5798 path => "machine/peripheral/balloon0",
5799 property => "guest-stats-polling-interval",
5800 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
eb065317 5801
3898a563
FG
5802 if ($resume) {
5803 print "Resumed VM, removing state\n";
5804 if (my $vmstate = $conf->{vmstate}) {
5805 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5806 PVE::Storage::vdisk_free($storecfg, $vmstate);
7ceade4c 5807 }
ea1c2110 5808 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
3898a563
FG
5809 PVE::QemuConfig->write_config($vmid, $conf);
5810 }
7ceade4c 5811
3898a563 5812 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
84da8217
FG
5813
5814 return $res;
1e3baf05
DM
5815}
5816
1e3baf05 5817sub vm_commandline {
b14477e7 5818 my ($storecfg, $vmid, $snapname) = @_;
1e3baf05 5819
ffda963f 5820 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5821
e8a26810 5822 my ($forcemachine, $forcecpu);
b14477e7
RV
5823 if ($snapname) {
5824 my $snapshot = $conf->{snapshots}->{$snapname};
87d92707
TL
5825 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5826
ea1c2110
SR
5827 # check for machine or CPU overrides in snapshot
5828 $forcemachine = $snapshot->{runningmachine};
5829 $forcecpu = $snapshot->{runningcpu};
092868c4 5830
87d92707 5831 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
b14477e7 5832
b14477e7
RV
5833 $conf = $snapshot;
5834 }
5835
1e3baf05
DM
5836 my $defaults = load_defaults();
5837
e8a26810 5838 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu);
1e3baf05 5839
5930c1ff 5840 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5841}
5842
5843sub vm_reset {
5844 my ($vmid, $skiplock) = @_;
5845
ffda963f 5846 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5847
ffda963f 5848 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5849
ffda963f 5850 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5851
0a13e08e 5852 mon_cmd($vmid, "system_reset");
ff1a2432
DM
5853 });
5854}
5855
5856sub get_vm_volumes {
5857 my ($conf) = @_;
1e3baf05 5858
ff1a2432 5859 my $vollist = [];
d5769dc2 5860 foreach_volid($conf, sub {
392f8b5d 5861 my ($volid, $attr) = @_;
ff1a2432 5862
d5769dc2 5863 return if $volid =~ m|^/|;
ff1a2432 5864
d5769dc2
DM
5865 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5866 return if !$sid;
ff1a2432
DM
5867
5868 push @$vollist, $volid;
1e3baf05 5869 });
ff1a2432
DM
5870
5871 return $vollist;
5872}
5873
5874sub vm_stop_cleanup {
70b04821 5875 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5876
745fed70 5877 eval {
ff1a2432 5878
254575e9
DM
5879 if (!$keepActive) {
5880 my $vollist = get_vm_volumes($conf);
5881 PVE::Storage::deactivate_volumes($storecfg, $vollist);
f9dde219
SR
5882
5883 if (my $tpmdrive = $conf->{tpmstate0}) {
5884 my $tpm = parse_drive("tpmstate0", $tpmdrive);
5885 my ($storeid, $volname) = PVE::Storage::parse_volume_id($tpm->{file}, 1);
5886 if ($storeid) {
5887 PVE::Storage::unmap_volume($storecfg, $tpm->{file});
5888 }
5889 }
254575e9 5890 }
a1b7d579 5891
ab6a046f 5892 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5893 unlink "/var/run/qemu-server/${vmid}.$ext";
5894 }
a1b7d579 5895
6dbcb073 5896 if ($conf->{ivshmem}) {
4df98f2f 5897 my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
4c5a6a24
TL
5898 # just delete it for now, VMs which have this already open do not
5899 # are affected, but new VMs will get a separated one. If this
5900 # becomes an issue we either add some sort of ref-counting or just
5901 # add a "don't delete on stop" flag to the ivshmem format.
6dbcb073
DC
5902 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
5903 }
5904
b4415a52
TL
5905 my $ids = [];
5906 foreach my $key (keys %$conf) {
5907 next if $key !~ m/^hostpci(\d+)$/;
5908 my $hostpciindex = $1;
5909 my $d = parse_hostpci($conf->{$key});
5910 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5911
5912 foreach my $pci (@{$d->{pciid}}) {
5913 my $pciid = $pci->{id};
5914 push @$ids, $pci->{id};
5915 PVE::SysFSTools::pci_cleanup_mdev_device($pciid, $uuid);
5916 }
5917 }
5918 PVE::QemuServer::PCI::remove_pci_reservation($ids);
6ab45bd7 5919
70b04821 5920 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5921 };
5922 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5923}
5924
575d19da
DC
5925# call only in locked context
5926sub _do_vm_stop {
5927 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
9269013a 5928
575d19da
DC
5929 my $pid = check_running($vmid, $nocheck);
5930 return if !$pid;
1e3baf05 5931
575d19da
DC
5932 my $conf;
5933 if (!$nocheck) {
5934 $conf = PVE::QemuConfig->load_config($vmid);
5935 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5936 if (!defined($timeout) && $shutdown && $conf->{startup}) {
5937 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
5938 $timeout = $opts->{down} if $opts->{down};
e6c3b671 5939 }
575d19da
DC
5940 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
5941 }
19672434 5942
575d19da
DC
5943 eval {
5944 if ($shutdown) {
a2af1bbe 5945 if (defined($conf) && get_qga_key($conf, 'enabled')) {
0a13e08e 5946 mon_cmd($vmid, "guest-shutdown", timeout => $timeout);
9269013a 5947 } else {
0a13e08e 5948 mon_cmd($vmid, "system_powerdown");
1e3baf05
DM
5949 }
5950 } else {
0a13e08e 5951 mon_cmd($vmid, "quit");
1e3baf05 5952 }
575d19da
DC
5953 };
5954 my $err = $@;
1e3baf05 5955
575d19da
DC
5956 if (!$err) {
5957 $timeout = 60 if !defined($timeout);
1e3baf05
DM
5958
5959 my $count = 0;
e6c3b671 5960 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5961 $count++;
5962 sleep 1;
5963 }
5964
5965 if ($count >= $timeout) {
575d19da
DC
5966 if ($force) {
5967 warn "VM still running - terminating now with SIGTERM\n";
5968 kill 15, $pid;
5969 } else {
5970 die "VM quit/powerdown failed - got timeout\n";
5971 }
5972 } else {
5973 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5974 return;
1e3baf05 5975 }
575d19da 5976 } else {
d60cbb97
TL
5977 if (!check_running($vmid, $nocheck)) {
5978 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
5979 return;
5980 }
5981 if ($force) {
575d19da
DC
5982 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5983 kill 15, $pid;
5984 } else {
5985 die "VM quit/powerdown failed\n";
5986 }
5987 }
5988
5989 # wait again
5990 $timeout = 10;
5991
5992 my $count = 0;
5993 while (($count < $timeout) && check_running($vmid, $nocheck)) {
5994 $count++;
5995 sleep 1;
5996 }
5997
5998 if ($count >= $timeout) {
5999 warn "VM still running - terminating now with SIGKILL\n";
6000 kill 9, $pid;
6001 sleep 1;
6002 }
1e3baf05 6003
575d19da
DC
6004 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
6005}
6006
6007# Note: use $nocheck to skip tests if VM configuration file exists.
6008# We need that when migration VMs to other nodes (files already moved)
6009# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
6010sub vm_stop {
6011 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
6012
6013 $force = 1 if !defined($force) && !$shutdown;
6014
6015 if ($migratedfrom){
6016 my $pid = check_running($vmid, $nocheck, $migratedfrom);
6017 kill 15, $pid if $pid;
6018 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
6019 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
6020 return;
6021 }
6022
6023 PVE::QemuConfig->lock_config($vmid, sub {
6024 _do_vm_stop($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
ff1a2432 6025 });
1e3baf05
DM
6026}
6027
165411f0
DC
6028sub vm_reboot {
6029 my ($vmid, $timeout) = @_;
6030
6031 PVE::QemuConfig->lock_config($vmid, sub {
66026117 6032 eval {
165411f0 6033
66026117
OB
6034 # only reboot if running, as qmeventd starts it again on a stop event
6035 return if !check_running($vmid);
165411f0 6036
66026117 6037 create_reboot_request($vmid);
165411f0 6038
66026117
OB
6039 my $storecfg = PVE::Storage::config();
6040 _do_vm_stop($storecfg, $vmid, undef, undef, $timeout, 1);
165411f0 6041
66026117
OB
6042 };
6043 if (my $err = $@) {
3c1c3fe6 6044 # avoid that the next normal shutdown will be confused for a reboot
66026117
OB
6045 clear_reboot_request($vmid);
6046 die $err;
6047 }
165411f0
DC
6048 });
6049}
6050
75c24bba 6051# note: if using the statestorage parameter, the caller has to check privileges
1e3baf05 6052sub vm_suspend {
48b4cdc2 6053 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
6054
6055 my $conf;
6056 my $path;
6057 my $storecfg;
6058 my $vmstate;
1e3baf05 6059
ffda963f 6060 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 6061
159719e5 6062 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 6063
159719e5 6064 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 6065 PVE::QemuConfig->check_lock($conf)
159719e5
DC
6066 if !($skiplock || $is_backing_up);
6067
6068 die "cannot suspend to disk during backup\n"
6069 if $is_backing_up && $includestate;
bcb7c9cf 6070
159719e5
DC
6071 if ($includestate) {
6072 $conf->{lock} = 'suspending';
6073 my $date = strftime("%Y-%m-%d", localtime(time()));
6074 $storecfg = PVE::Storage::config();
75c24bba
DC
6075 if (!$statestorage) {
6076 $statestorage = find_vmstate_storage($conf, $storecfg);
6077 # check permissions for the storage
6078 my $rpcenv = PVE::RPCEnvironment::get();
6079 if ($rpcenv->{type} ne 'cli') {
6080 my $authuser = $rpcenv->get_user();
6081 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
6082 }
6083 }
6084
6085
4df98f2f
TL
6086 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate(
6087 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
6088 $path = PVE::Storage::path($storecfg, $vmstate);
6089 PVE::QemuConfig->write_config($vmid, $conf);
6090 } else {
0a13e08e 6091 mon_cmd($vmid, "stop");
159719e5 6092 }
1e3baf05 6093 });
159719e5
DC
6094
6095 if ($includestate) {
6096 # save vm state
6097 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
6098
6099 eval {
27a5be53 6100 set_migration_caps($vmid, 1);
0a13e08e 6101 mon_cmd($vmid, "savevm-start", statefile => $path);
159719e5 6102 for(;;) {
0a13e08e 6103 my $state = mon_cmd($vmid, "query-savevm");
159719e5
DC
6104 if (!$state->{status}) {
6105 die "savevm not active\n";
6106 } elsif ($state->{status} eq 'active') {
6107 sleep(1);
6108 next;
6109 } elsif ($state->{status} eq 'completed') {
b0a9a385 6110 print "State saved, quitting\n";
159719e5
DC
6111 last;
6112 } elsif ($state->{status} eq 'failed' && $state->{error}) {
6113 die "query-savevm failed with error '$state->{error}'\n"
6114 } else {
6115 die "query-savevm returned status '$state->{status}'\n";
6116 }
6117 }
6118 };
6119 my $err = $@;
6120
6121 PVE::QemuConfig->lock_config($vmid, sub {
6122 $conf = PVE::QemuConfig->load_config($vmid);
6123 if ($err) {
6124 # cleanup, but leave suspending lock, to indicate something went wrong
6125 eval {
0a13e08e 6126 mon_cmd($vmid, "savevm-end");
159719e5
DC
6127 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
6128 PVE::Storage::vdisk_free($storecfg, $vmstate);
ea1c2110 6129 delete $conf->@{qw(vmstate runningmachine runningcpu)};
159719e5
DC
6130 PVE::QemuConfig->write_config($vmid, $conf);
6131 };
6132 warn $@ if $@;
6133 die $err;
6134 }
6135
6136 die "lock changed unexpectedly\n"
6137 if !PVE::QemuConfig->has_lock($conf, 'suspending');
6138
0a13e08e 6139 mon_cmd($vmid, "quit");
159719e5
DC
6140 $conf->{lock} = 'suspended';
6141 PVE::QemuConfig->write_config($vmid, $conf);
6142 });
6143 }
1e3baf05
DM
6144}
6145
6146sub vm_resume {
289e0b85 6147 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 6148
ffda963f 6149 PVE::QemuConfig->lock_config($vmid, sub {
0a13e08e 6150 my $res = mon_cmd($vmid, 'query-status');
c2786bed 6151 my $resume_cmd = 'cont';
8e0c97bb 6152 my $reset = 0;
c2786bed 6153
8e0c97bb
SR
6154 if ($res->{status}) {
6155 return if $res->{status} eq 'running'; # job done, go home
6156 $resume_cmd = 'system_wakeup' if $res->{status} eq 'suspended';
6157 $reset = 1 if $res->{status} eq 'shutdown';
c2786bed
DC
6158 }
6159
289e0b85 6160 if (!$nocheck) {
1e3baf05 6161
ffda963f 6162 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 6163
e79706d4
FG
6164 PVE::QemuConfig->check_lock($conf)
6165 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 6166 }
3e24733b 6167
8e0c97bb
SR
6168 if ($reset) {
6169 # required if a VM shuts down during a backup and we get a resume
6170 # request before the backup finishes for example
6171 mon_cmd($vmid, "system_reset");
6172 }
0a13e08e 6173 mon_cmd($vmid, $resume_cmd);
1e3baf05
DM
6174 });
6175}
6176
5fdbe4f0
DM
6177sub vm_sendkey {
6178 my ($vmid, $skiplock, $key) = @_;
1e3baf05 6179
ffda963f 6180 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 6181
ffda963f 6182 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 6183
7b7c6d1b 6184 # there is no qmp command, so we use the human monitor command
0a13e08e 6185 my $res = PVE::QemuServer::Monitor::hmp_cmd($vmid, "sendkey $key");
d30820d6 6186 die $res if $res ne '';
1e3baf05
DM
6187 });
6188}
6189
3e16d5fc
DM
6190# vzdump restore implementaion
6191
ed221350 6192sub tar_archive_read_firstfile {
3e16d5fc 6193 my $archive = shift;
afdb31d5 6194
3e16d5fc
DM
6195 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
6196
6197 # try to detect archive type first
387ba257 6198 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 6199 die "unable to open file '$archive'\n";
387ba257 6200 my $firstfile = <$fh>;
3e16d5fc 6201 kill 15, $pid;
387ba257 6202 close $fh;
3e16d5fc
DM
6203
6204 die "ERROR: archive contaions no data\n" if !$firstfile;
6205 chomp $firstfile;
6206
6207 return $firstfile;
6208}
6209
ed221350
DM
6210sub tar_restore_cleanup {
6211 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
6212
6213 print STDERR "starting cleanup\n";
6214
6215 if (my $fd = IO::File->new($statfile, "r")) {
6216 while (defined(my $line = <$fd>)) {
6217 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6218 my $volid = $2;
6219 eval {
6220 if ($volid =~ m|^/|) {
6221 unlink $volid || die 'unlink failed\n';
6222 } else {
ed221350 6223 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 6224 }
afdb31d5 6225 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
6226 };
6227 print STDERR "unable to cleanup '$volid' - $@" if $@;
6228 } else {
6229 print STDERR "unable to parse line in statfile - $line";
afdb31d5 6230 }
3e16d5fc
DM
6231 }
6232 $fd->close();
6233 }
6234}
6235
d1e92cf6 6236sub restore_file_archive {
a0d1b1a2 6237 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 6238
a2ec5a67
FG
6239 return restore_vma_archive($archive, $vmid, $user, $opts)
6240 if $archive eq '-';
6241
c6d51783
AA
6242 my $info = PVE::Storage::archive_info($archive);
6243 my $format = $opts->{format} // $info->{format};
6244 my $comp = $info->{compression};
91bd6c90
DM
6245
6246 # try to detect archive format
6247 if ($format eq 'tar') {
6248 return restore_tar_archive($archive, $vmid, $user, $opts);
6249 } else {
6250 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
6251 }
6252}
6253
d1e92cf6
DM
6254# hepler to remove disks that will not be used after restore
6255my $restore_cleanup_oldconf = sub {
6256 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
6257
01a4377f
FE
6258 my $kept_disks = {};
6259
912792e2 6260 PVE::QemuConfig->foreach_volume($oldconf, sub {
d1e92cf6
DM
6261 my ($ds, $drive) = @_;
6262
6263 return if drive_is_cdrom($drive, 1);
6264
6265 my $volid = $drive->{file};
6266 return if !$volid || $volid =~ m|^/|;
6267
6268 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
6269 return if !$path || !$owner || ($owner != $vmid);
6270
6271 # Note: only delete disk we want to restore
6272 # other volumes will become unused
6273 if ($virtdev_hash->{$ds}) {
6274 eval { PVE::Storage::vdisk_free($storecfg, $volid); };
6275 if (my $err = $@) {
6276 warn $err;
6277 }
01a4377f
FE
6278 } else {
6279 $kept_disks->{$volid} = 1;
d1e92cf6
DM
6280 }
6281 });
6282
01a4377f
FE
6283 # after the restore we have no snapshots anymore
6284 for my $snapname (keys $oldconf->{snapshots}->%*) {
d1e92cf6
DM
6285 my $snap = $oldconf->{snapshots}->{$snapname};
6286 if ($snap->{vmstate}) {
6287 eval { PVE::Storage::vdisk_free($storecfg, $snap->{vmstate}); };
6288 if (my $err = $@) {
6289 warn $err;
6290 }
6291 }
01a4377f
FE
6292
6293 for my $volid (keys $kept_disks->%*) {
6294 eval { PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snapname); };
6295 warn $@ if $@;
6296 }
d1e92cf6
DM
6297 }
6298};
6299
9f3d73bc
DM
6300# Helper to parse vzdump backup device hints
6301#
6302# $rpcenv: Environment, used to ckeck storage permissions
6303# $user: User ID, to check storage permissions
6304# $storecfg: Storage configuration
6305# $fh: the file handle for reading the configuration
6306# $devinfo: should contain device sizes for all backu-up'ed devices
6307# $options: backup options (pool, default storage)
6308#
6309# Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
6310my $parse_backup_hints = sub {
6311 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
d1e92cf6 6312
36d4bdcb
TL
6313 my $check_storage = sub { # assert if an image can be allocate
6314 my ($storeid, $scfg) = @_;
6315 die "Content type 'images' is not available on storage '$storeid'\n"
6316 if !$scfg->{content}->{images};
6317 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace'])
6318 if $user ne 'root@pam';
6319 };
d1e92cf6 6320
36d4bdcb 6321 my $virtdev_hash = {};
9f3d73bc
DM
6322 while (defined(my $line = <$fh>)) {
6323 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6324 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6325 die "archive does not contain data for drive '$virtdev'\n"
6326 if !$devinfo->{$devname};
6327
6328 if (defined($options->{storage})) {
6329 $storeid = $options->{storage} || 'local';
6330 } elsif (!$storeid) {
6331 $storeid = 'local';
d1e92cf6 6332 }
9f3d73bc
DM
6333 $format = 'raw' if !$format;
6334 $devinfo->{$devname}->{devname} = $devname;
6335 $devinfo->{$devname}->{virtdev} = $virtdev;
6336 $devinfo->{$devname}->{format} = $format;
6337 $devinfo->{$devname}->{storeid} = $storeid;
6338
62af60cd 6339 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
36d4bdcb 6340 $check_storage->($storeid, $scfg); # permission and content type check
d1e92cf6 6341
9f3d73bc
DM
6342 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6343 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6344 my $virtdev = $1;
6345 my $drive = parse_drive($virtdev, $2);
36d4bdcb 6346
9f3d73bc
DM
6347 if (drive_is_cloudinit($drive)) {
6348 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
5364990d
TL
6349 $storeid = $options->{storage} if defined ($options->{storage});
6350 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
9f3d73bc 6351 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
d1e92cf6 6352
36d4bdcb 6353 $check_storage->($storeid, $scfg); # permission and content type check
9f8ba326 6354
9f3d73bc
DM
6355 $virtdev_hash->{$virtdev} = {
6356 format => $format,
5364990d 6357 storeid => $storeid,
9f3d73bc
DM
6358 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
6359 is_cloudinit => 1,
6360 };
d1e92cf6 6361 }
9f3d73bc
DM
6362 }
6363 }
d1e92cf6 6364
9f3d73bc
DM
6365 return $virtdev_hash;
6366};
d1e92cf6 6367
9f3d73bc
DM
6368# Helper to allocate and activate all volumes required for a restore
6369#
6370# $storecfg: Storage configuration
6371# $virtdev_hash: as returned by parse_backup_hints()
6372#
6373# Returns: { $virtdev => $volid }
6374my $restore_allocate_devices = sub {
6375 my ($storecfg, $virtdev_hash, $vmid) = @_;
d1e92cf6 6376
9f3d73bc
DM
6377 my $map = {};
6378 foreach my $virtdev (sort keys %$virtdev_hash) {
6379 my $d = $virtdev_hash->{$virtdev};
6380 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
6381 my $storeid = $d->{storeid};
6382 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
d1e92cf6 6383
9f3d73bc
DM
6384 # test if requested format is supported
6385 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
6386 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6387 $d->{format} = $defFormat if !$supported;
d1e92cf6 6388
9f3d73bc
DM
6389 my $name;
6390 if ($d->{is_cloudinit}) {
6391 $name = "vm-$vmid-cloudinit";
c997e24a
ML
6392 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6393 if ($scfg->{path}) {
6394 $name .= ".$d->{format}";
6395 }
d1e92cf6
DM
6396 }
6397
4df98f2f
TL
6398 my $volid = PVE::Storage::vdisk_alloc(
6399 $storecfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
d1e92cf6 6400
9f3d73bc
DM
6401 print STDERR "new volume ID is '$volid'\n";
6402 $d->{volid} = $volid;
d1e92cf6 6403
9f3d73bc 6404 PVE::Storage::activate_volumes($storecfg, [$volid]);
d1e92cf6 6405
9f3d73bc 6406 $map->{$virtdev} = $volid;
d1e92cf6
DM
6407 }
6408
9f3d73bc
DM
6409 return $map;
6410};
d1e92cf6 6411
c62d7cf5 6412sub restore_update_config_line {
eabac302 6413 my ($cookie, $map, $line, $unique) = @_;
91bd6c90 6414
98a4b3fb
FE
6415 return '' if $line =~ m/^\#qmdump\#/;
6416 return '' if $line =~ m/^\#vzdump\#/;
6417 return '' if $line =~ m/^lock:/;
6418 return '' if $line =~ m/^unused\d+:/;
6419 return '' if $line =~ m/^parent:/;
6420
6421 my $res = '';
91bd6c90 6422
b5b99790 6423 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
6424 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6425 # try to convert old 1.X settings
6426 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6427 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
6428 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 6429 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
6430 my $net = {
6431 model => $model,
6432 bridge => "vmbr$ind",
6433 macaddr => $macaddr,
6434 };
6435 my $netstr = print_net($net);
6436
98a4b3fb 6437 $res .= "net$cookie->{netcount}: $netstr\n";
91bd6c90
DM
6438 $cookie->{netcount}++;
6439 }
6440 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6441 my ($id, $netstr) = ($1, $2);
6442 my $net = parse_net($netstr);
b5b99790 6443 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90 6444 $netstr = print_net($net);
98a4b3fb 6445 $res .= "$id: $netstr\n";
f9dde219 6446 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk|tpmstate)\d+):\s*(\S+)\s*$/) {
91bd6c90 6447 my $virtdev = $1;
907ea891 6448 my $value = $3;
d9faf790
WB
6449 my $di = parse_drive($virtdev, $value);
6450 if (defined($di->{backup}) && !$di->{backup}) {
98a4b3fb 6451 $res .= "#$line";
c0f7406e 6452 } elsif ($map->{$virtdev}) {
8fd57431 6453 delete $di->{format}; # format can change on restore
91bd6c90 6454 $di->{file} = $map->{$virtdev};
71c58bb7 6455 $value = print_drive($di);
98a4b3fb 6456 $res .= "$virtdev: $value\n";
91bd6c90 6457 } else {
98a4b3fb 6458 $res .= $line;
91bd6c90 6459 }
1a0c2f03 6460 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 6461 my $vmgenid = $1;
6ee499ff 6462 if ($vmgenid ne '0') {
1a0c2f03 6463 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
6464 $vmgenid = generate_uuid();
6465 }
98a4b3fb 6466 $res .= "vmgenid: $vmgenid\n";
19a5dd55
WL
6467 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6468 my ($uuid, $uuid_str);
6469 UUID::generate($uuid);
6470 UUID::unparse($uuid, $uuid_str);
6471 my $smbios1 = parse_smbios1($2);
6472 $smbios1->{uuid} = $uuid_str;
98a4b3fb 6473 $res .= $1.print_smbios1($smbios1)."\n";
91bd6c90 6474 } else {
98a4b3fb 6475 $res .= $line;
91bd6c90 6476 }
98a4b3fb
FE
6477
6478 return $res;
c62d7cf5 6479}
9f3d73bc
DM
6480
6481my $restore_deactivate_volumes = sub {
e8b07b29 6482 my ($storecfg, $virtdev_hash) = @_;
9f3d73bc
DM
6483
6484 my $vollist = [];
e8b07b29
FE
6485 for my $dev (values $virtdev_hash->%*) {
6486 push $vollist->@*, $dev->{volid} if $dev->{volid};
9f3d73bc
DM
6487 }
6488
ff86112c
FE
6489 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
6490 print STDERR $@ if $@;
9f3d73bc
DM
6491};
6492
6493my $restore_destroy_volumes = sub {
e8b07b29 6494 my ($storecfg, $virtdev_hash) = @_;
9f3d73bc 6495
e8b07b29
FE
6496 for my $dev (values $virtdev_hash->%*) {
6497 my $volid = $dev->{volid} or next;
9f3d73bc 6498 eval {
e60afe82 6499 PVE::Storage::vdisk_free($storecfg, $volid);
9f3d73bc
DM
6500 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6501 };
6502 print STDERR "unable to cleanup '$volid' - $@" if $@;
6503 }
6504};
91bd6c90 6505
202a2a0b
FE
6506my $restore_merge_config = sub {
6507 my ($filename, $backup_conf_raw, $override_conf) = @_;
6508
6509 my $backup_conf = parse_vm_config($filename, $backup_conf_raw);
6510 for my $key (keys $override_conf->%*) {
6511 $backup_conf->{$key} = $override_conf->{$key};
6512 }
6513
6514 return $backup_conf;
6515};
6516
91bd6c90 6517sub scan_volids {
9a8ba127 6518 my ($cfg, $vmid) = @_;
91bd6c90 6519
9a8ba127 6520 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid, undef, 'images');
91bd6c90
DM
6521
6522 my $volid_hash = {};
6523 foreach my $storeid (keys %$info) {
6524 foreach my $item (@{$info->{$storeid}}) {
6525 next if !($item->{volid} && $item->{size});
5996a936 6526 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
6527 $volid_hash->{$item->{volid}} = $item;
6528 }
6529 }
6530
6531 return $volid_hash;
6532}
6533
68b108ee 6534sub update_disk_config {
91bd6c90 6535 my ($vmid, $conf, $volid_hash) = @_;
be190583 6536
91bd6c90 6537 my $changes;
9b29cbd0 6538 my $prefix = "VM $vmid";
91bd6c90 6539
c449137a
DC
6540 # used and unused disks
6541 my $referenced = {};
91bd6c90 6542
5996a936
DM
6543 # Note: it is allowed to define multiple storages with same path (alias), so
6544 # we need to check both 'volid' and real 'path' (two different volid can point
6545 # to the same path).
6546
c449137a 6547 my $referencedpath = {};
be190583 6548
91bd6c90 6549 # update size info
0c4fef3f 6550 PVE::QemuConfig->foreach_volume($conf, sub {
ca04977c 6551 my ($opt, $drive) = @_;
91bd6c90 6552
ca04977c
FE
6553 my $volid = $drive->{file};
6554 return if !$volid;
4df98f2f 6555 my $volume = $volid_hash->{$volid};
91bd6c90 6556
ca04977c
FE
6557 # mark volid as "in-use" for next step
6558 $referenced->{$volid} = 1;
4df98f2f 6559 if ($volume && (my $path = $volume->{path})) {
ca04977c 6560 $referencedpath->{$path} = 1;
91bd6c90 6561 }
ca04977c
FE
6562
6563 return if drive_is_cdrom($drive);
4df98f2f 6564 return if !$volume;
ca04977c 6565
4df98f2f 6566 my ($updated, $msg) = PVE::QemuServer::Drive::update_disksize($drive, $volume->{size});
ca04977c
FE
6567 if (defined($updated)) {
6568 $changes = 1;
6569 $conf->{$opt} = print_drive($updated);
9b29cbd0 6570 print "$prefix ($opt): $msg\n";
ca04977c
FE
6571 }
6572 });
91bd6c90 6573
5996a936 6574 # remove 'unusedX' entry if volume is used
ca04977c
FE
6575 PVE::QemuConfig->foreach_unused_volume($conf, sub {
6576 my ($opt, $drive) = @_;
6577
6578 my $volid = $drive->{file};
6579 return if !$volid;
6580
f7d1505b
TL
6581 my $path;
6582 $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 6583 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
68b108ee 6584 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5996a936
DM
6585 $changes = 1;
6586 delete $conf->{$opt};
6587 }
c449137a
DC
6588
6589 $referenced->{$volid} = 1;
6590 $referencedpath->{$path} = 1 if $path;
ca04977c 6591 });
5996a936 6592
91bd6c90
DM
6593 foreach my $volid (sort keys %$volid_hash) {
6594 next if $volid =~ m/vm-$vmid-state-/;
c449137a 6595 next if $referenced->{$volid};
5996a936
DM
6596 my $path = $volid_hash->{$volid}->{path};
6597 next if !$path; # just to be sure
c449137a 6598 next if $referencedpath->{$path};
91bd6c90 6599 $changes = 1;
53b81297 6600 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
68b108ee 6601 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
c449137a 6602 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
6603 }
6604
6605 return $changes;
6606}
6607
6608sub rescan {
9224dcee 6609 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 6610
20519efc 6611 my $cfg = PVE::Storage::config();
91bd6c90 6612
53b81297 6613 print "rescan volumes...\n";
9a8ba127 6614 my $volid_hash = scan_volids($cfg, $vmid);
91bd6c90
DM
6615
6616 my $updatefn = sub {
6617 my ($vmid) = @_;
6618
ffda963f 6619 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 6620
ffda963f 6621 PVE::QemuConfig->check_lock($conf);
91bd6c90 6622
03da3f0d
DM
6623 my $vm_volids = {};
6624 foreach my $volid (keys %$volid_hash) {
6625 my $info = $volid_hash->{$volid};
6626 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
6627 }
6628
68b108ee 6629 my $changes = update_disk_config($vmid, $conf, $vm_volids);
91bd6c90 6630
9224dcee 6631 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
6632 };
6633
6634 if (defined($vmid)) {
6635 if ($nolock) {
6636 &$updatefn($vmid);
6637 } else {
ffda963f 6638 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
6639 }
6640 } else {
6641 my $vmlist = config_list();
6642 foreach my $vmid (keys %$vmlist) {
6643 if ($nolock) {
6644 &$updatefn($vmid);
6645 } else {
ffda963f 6646 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 6647 }
91bd6c90
DM
6648 }
6649 }
6650}
6651
9f3d73bc
DM
6652sub restore_proxmox_backup_archive {
6653 my ($archive, $vmid, $user, $options) = @_;
6654
6655 my $storecfg = PVE::Storage::config();
6656
6657 my ($storeid, $volname) = PVE::Storage::parse_volume_id($archive);
6658 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6659
9f3d73bc 6660 my $fingerprint = $scfg->{fingerprint};
503e96f8 6661 my $keyfile = PVE::Storage::PBSPlugin::pbs_encryption_key_file_name($storecfg, $storeid);
9f3d73bc 6662
fbec3f89 6663 my $repo = PVE::PBSClient::get_repository($scfg);
2dda626d 6664 my $namespace = $scfg->{namespace};
dea4b04c 6665
26731a3c 6666 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
9f3d73bc
DM
6667 my $password = PVE::Storage::PBSPlugin::pbs_get_password($scfg, $storeid);
6668 local $ENV{PBS_PASSWORD} = $password;
6669 local $ENV{PBS_FINGERPRINT} = $fingerprint if defined($fingerprint);
6670
6671 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6672 PVE::Storage::parse_volname($storecfg, $archive);
6673
6674 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6675
6676 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6677
6678 my $tmpdir = "/var/tmp/vzdumptmp$$";
6679 rmtree $tmpdir;
6680 mkpath $tmpdir;
6681
6682 my $conffile = PVE::QemuConfig->config_file($vmid);
9f3d73bc
DM
6683 # disable interrupts (always do cleanups)
6684 local $SIG{INT} =
6685 local $SIG{TERM} =
6686 local $SIG{QUIT} =
6687 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
6688
6689 # Note: $oldconf is undef if VM does not exists
6690 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6691 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
98a4b3fb 6692 my $new_conf_raw = '';
9f3d73bc
DM
6693
6694 my $rpcenv = PVE::RPCEnvironment::get();
e8b07b29
FE
6695 my $devinfo = {}; # info about drives included in backup
6696 my $virtdev_hash = {}; # info about allocated drives
9f3d73bc
DM
6697
6698 eval {
6699 # enable interrupts
6700 local $SIG{INT} =
6701 local $SIG{TERM} =
6702 local $SIG{QUIT} =
6703 local $SIG{HUP} =
6704 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
6705
6706 my $cfgfn = "$tmpdir/qemu-server.conf";
6707 my $firewall_config_fn = "$tmpdir/fw.conf";
6708 my $index_fn = "$tmpdir/index.json";
6709
6710 my $cmd = "restore";
6711
6712 my $param = [$pbs_backup_name, "index.json", $index_fn];
6713 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6714 my $index = PVE::Tools::file_get_contents($index_fn);
6715 $index = decode_json($index);
6716
9f3d73bc
DM
6717 foreach my $info (@{$index->{files}}) {
6718 if ($info->{filename} =~ m/^(drive-\S+).img.fidx$/) {
6719 my $devname = $1;
6720 if ($info->{size} =~ m/^(\d+)$/) { # untaint size
6721 $devinfo->{$devname}->{size} = $1;
6722 } else {
6723 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6724 }
6725 }
6726 }
6727
4df98f2f
TL
6728 my $is_qemu_server_backup = scalar(
6729 grep { $_->{filename} eq 'qemu-server.conf.blob' } @{$index->{files}}
6730 );
9f3d73bc
DM
6731 if (!$is_qemu_server_backup) {
6732 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6733 }
6734 my $has_firewall_config = scalar(grep { $_->{filename} eq 'fw.conf.blob' } @{$index->{files}});
6735
6736 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6737 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6738
6739 if ($has_firewall_config) {
6740 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6741 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6742
6743 my $pve_firewall_dir = '/etc/pve/firewall';
6744 mkdir $pve_firewall_dir; # make sure the dir exists
6745 PVE::Tools::file_copy($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6746 }
6747
6748 my $fh = IO::File->new($cfgfn, "r") ||
a1cbe55c 6749 die "unable to read qemu-server.conf - $!\n";
9f3d73bc 6750
e8b07b29 6751 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
9f3d73bc
DM
6752
6753 # fixme: rate limit?
6754
6755 # create empty/temp config
6756 PVE::Tools::file_set_contents($conffile, "memory: 128\nlock: create");
6757
6758 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6759
6760 # allocate volumes
6761 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6762
6f94e162
SR
6763 foreach my $virtdev (sort keys %$virtdev_hash) {
6764 my $d = $virtdev_hash->{$virtdev};
6765 next if $d->{is_cloudinit}; # no need to restore cloudinit
9f3d73bc 6766
55c7f9cf 6767 # this fails if storage is unavailable
6f94e162 6768 my $volid = $d->{volid};
6f94e162 6769 my $path = PVE::Storage::path($storecfg, $volid);
9f3d73bc 6770
f9dde219
SR
6771 # for live-restore we only want to preload the efidisk and TPM state
6772 next if $options->{live} && $virtdev ne 'efidisk0' && $virtdev ne 'tpmstate0';
55c7f9cf 6773
21a9ec2a
WB
6774 my @ns_arg;
6775 if (defined(my $ns = $scfg->{namespace})) {
6776 @ns_arg = ('--ns', $ns);
6777 }
6778
6f94e162
SR
6779 my $pbs_restore_cmd = [
6780 '/usr/bin/pbs-restore',
6781 '--repository', $repo,
21a9ec2a 6782 @ns_arg,
6f94e162
SR
6783 $pbs_backup_name,
6784 "$d->{devname}.img.fidx",
6785 $path,
6786 '--verbose',
6787 ];
55fb78aa 6788
6f94e162
SR
6789 push @$pbs_restore_cmd, '--format', $d->{format} if $d->{format};
6790 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e $keyfile;
9f3d73bc 6791
6f94e162
SR
6792 if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $volid)) {
6793 push @$pbs_restore_cmd, '--skip-zero';
26731a3c 6794 }
6f94e162
SR
6795
6796 my $dbg_cmdstring = PVE::Tools::cmd2string($pbs_restore_cmd);
6797 print "restore proxmox backup image: $dbg_cmdstring\n";
6798 run_command($pbs_restore_cmd);
9f3d73bc
DM
6799 }
6800
6801 $fh->seek(0, 0) || die "seek failed - $!\n";
6802
9f3d73bc
DM
6803 my $cookie = { netcount => 0 };
6804 while (defined(my $line = <$fh>)) {
c62d7cf5 6805 $new_conf_raw .= restore_update_config_line(
98a4b3fb 6806 $cookie,
98a4b3fb
FE
6807 $map,
6808 $line,
6809 $options->{unique},
6810 );
9f3d73bc
DM
6811 }
6812
6813 $fh->close();
9f3d73bc
DM
6814 };
6815 my $err = $@;
6816
26731a3c 6817 if ($err || !$options->{live}) {
e8b07b29 6818 $restore_deactivate_volumes->($storecfg, $virtdev_hash);
26731a3c 6819 }
9f3d73bc
DM
6820
6821 rmtree $tmpdir;
6822
6823 if ($err) {
e8b07b29 6824 $restore_destroy_volumes->($storecfg, $virtdev_hash);
9f3d73bc
DM
6825 die $err;
6826 }
6827
f7551170
SR
6828 if ($options->{live}) {
6829 # keep lock during live-restore
6830 $new_conf_raw .= "\nlock: create";
6831 }
6832
202a2a0b
FE
6833 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $options->{override_conf});
6834 PVE::QemuConfig->write_config($vmid, $new_conf);
9f3d73bc
DM
6835
6836 eval { rescan($vmid, 1); };
6837 warn $@ if $@;
26731a3c
SR
6838
6839 PVE::AccessControl::add_vm_to_pool($vmid, $options->{pool}) if $options->{pool};
6840
6841 if ($options->{live}) {
fefd65a1
SR
6842 # enable interrupts
6843 local $SIG{INT} =
6844 local $SIG{TERM} =
6845 local $SIG{QUIT} =
6846 local $SIG{HUP} =
6847 local $SIG{PIPE} = sub { die "got signal ($!) - abort\n"; };
26731a3c 6848
fefd65a1
SR
6849 my $conf = PVE::QemuConfig->load_config($vmid);
6850 die "cannot do live-restore for template\n" if PVE::QemuConfig->is_template($conf);
26731a3c 6851
f9dde219
SR
6852 # these special drives are already restored before start
6853 delete $devinfo->{'drive-efidisk0'};
6854 delete $devinfo->{'drive-tpmstate0-backup'};
2dda626d
DC
6855
6856 my $pbs_opts = {
6857 repo => $repo,
6858 keyfile => $keyfile,
6859 snapshot => $pbs_backup_name,
6860 namespace => $namespace,
6861 };
6862 pbs_live_restore($vmid, $conf, $storecfg, $devinfo, $pbs_opts);
f7551170
SR
6863
6864 PVE::QemuConfig->remove_lock($vmid, "create");
26731a3c
SR
6865 }
6866}
6867
6868sub pbs_live_restore {
2dda626d 6869 my ($vmid, $conf, $storecfg, $restored_disks, $opts) = @_;
26731a3c 6870
88cabb62 6871 print "starting VM for live-restore\n";
2dda626d 6872 print "repository: '$opts->{repo}', snapshot: '$opts->{snapshot}'\n";
26731a3c
SR
6873
6874 my $pbs_backing = {};
8986e36e 6875 for my $ds (keys %$restored_disks) {
26731a3c 6876 $ds =~ m/^drive-(.*)$/;
88cabb62
SR
6877 my $confname = $1;
6878 $pbs_backing->{$confname} = {
2dda626d
DC
6879 repository => $opts->{repo},
6880 snapshot => $opts->{snapshot},
26731a3c
SR
6881 archive => "$ds.img.fidx",
6882 };
2dda626d
DC
6883 $pbs_backing->{$confname}->{keyfile} = $opts->{keyfile} if -e $opts->{keyfile};
6884 $pbs_backing->{$confname}->{namespace} = $opts->{namespace} if defined($opts->{namespace});
88cabb62
SR
6885
6886 my $drive = parse_drive($confname, $conf->{$confname});
6887 print "restoring '$ds' to '$drive->{file}'\n";
26731a3c
SR
6888 }
6889
fd70c843 6890 my $drives_streamed = 0;
26731a3c
SR
6891 eval {
6892 # make sure HA doesn't interrupt our restore by stopping the VM
6893 if (PVE::HA::Config::vm_is_ha_managed($vmid)) {
fd70c843 6894 run_command(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
26731a3c
SR
6895 }
6896
fd70c843
TL
6897 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6898 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
bfb12678 6899 vm_start_nolock($storecfg, $vmid, $conf, {paused => 1, 'pbs-backing' => $pbs_backing}, {});
26731a3c 6900
26697640
SR
6901 my $qmeventd_fd = register_qmeventd_handle($vmid);
6902
26731a3c
SR
6903 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6904 # this will effectively collapse the backing image chain consisting of
6905 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6906 # removes itself once all backing images vanish with 'auto-remove=on')
6907 my $jobs = {};
8986e36e 6908 for my $ds (sort keys %$restored_disks) {
26731a3c
SR
6909 my $job_id = "restore-$ds";
6910 mon_cmd($vmid, 'block-stream',
6911 'job-id' => $job_id,
6912 device => "$ds",
6913 );
6914 $jobs->{$job_id} = {};
6915 }
6916
6917 mon_cmd($vmid, 'cont');
6918 qemu_drive_mirror_monitor($vmid, undef, $jobs, 'auto', 0, 'stream');
6919
a09b39f1
TL
6920 print "restore-drive jobs finished successfully, removing all tracking block devices"
6921 ." to disconnect from Proxmox Backup Server\n";
6922
8986e36e 6923 for my $ds (sort keys %$restored_disks) {
26731a3c
SR
6924 mon_cmd($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6925 }
26697640
SR
6926
6927 close($qmeventd_fd);
26731a3c
SR
6928 };
6929
6930 my $err = $@;
6931
6932 if ($err) {
8b8893c3 6933 warn "An error occurred during live-restore: $err\n";
26731a3c
SR
6934 _do_vm_stop($storecfg, $vmid, 1, 1, 10, 0, 1);
6935 die "live-restore failed\n";
6936 }
9f3d73bc
DM
6937}
6938
91bd6c90
DM
6939sub restore_vma_archive {
6940 my ($archive, $vmid, $user, $opts, $comp) = @_;
6941
91bd6c90
DM
6942 my $readfrom = $archive;
6943
7c536e11
WB
6944 my $cfg = PVE::Storage::config();
6945 my $commands = [];
6946 my $bwlimit = $opts->{bwlimit};
6947
6948 my $dbg_cmdstring = '';
6949 my $add_pipe = sub {
6950 my ($cmd) = @_;
6951 push @$commands, $cmd;
6952 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6953 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 6954 $readfrom = '-';
7c536e11
WB
6955 };
6956
6957 my $input = undef;
6958 if ($archive eq '-') {
6959 $input = '<&STDIN';
6960 } else {
6961 # If we use a backup from a PVE defined storage we also consider that
6962 # storage's rate limit:
6963 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
6964 if (defined($volid)) {
6965 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
6966 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
6967 if ($readlimit) {
6968 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 6969 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
6970 $add_pipe->($cstream);
6971 }
6972 }
6973 }
6974
6975 if ($comp) {
c6d51783
AA
6976 my $info = PVE::Storage::decompressor_info('vma', $comp);
6977 my $cmd = $info->{decompressor};
6978 push @$cmd, $readfrom;
7c536e11 6979 $add_pipe->($cmd);
91bd6c90
DM
6980 }
6981
6982 my $tmpdir = "/var/tmp/vzdumptmp$$";
6983 rmtree $tmpdir;
6984
6985 # disable interrupts (always do cleanups)
5b97ef24
TL
6986 local $SIG{INT} =
6987 local $SIG{TERM} =
6988 local $SIG{QUIT} =
6989 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
6990
6991 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6992 POSIX::mkfifo($mapfifo, 0600);
6993 my $fifofh;
808a65b5 6994 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
91bd6c90 6995
7c536e11 6996 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
6997
6998 my $oldtimeout;
6999 my $timeout = 5;
7000
e8b07b29
FE
7001 my $devinfo = {}; # info about drives included in backup
7002 my $virtdev_hash = {}; # info about allocated drives
91bd6c90
DM
7003
7004 my $rpcenv = PVE::RPCEnvironment::get();
7005
ffda963f 7006 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90 7007
ae200950 7008 # Note: $oldconf is undef if VM does not exist
ffda963f
FG
7009 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
7010 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
98a4b3fb 7011 my $new_conf_raw = '';
ed221350 7012
7c536e11
WB
7013 my %storage_limits;
7014
91bd6c90 7015 my $print_devmap = sub {
91bd6c90
DM
7016 my $cfgfn = "$tmpdir/qemu-server.conf";
7017
7018 # we can read the config - that is already extracted
7019 my $fh = IO::File->new($cfgfn, "r") ||
a1cbe55c 7020 die "unable to read qemu-server.conf - $!\n";
91bd6c90 7021
6738ab9c 7022 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
7023 if (-f $fwcfgfn) {
7024 my $pve_firewall_dir = '/etc/pve/firewall';
7025 mkdir $pve_firewall_dir; # make sure the dir exists
7026 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
7027 }
6738ab9c 7028
e8b07b29 7029 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
91bd6c90 7030
c8964278
FE
7031 foreach my $info (values %{$virtdev_hash}) {
7032 my $storeid = $info->{storeid};
7033 next if defined($storage_limits{$storeid});
7034
7035 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$storeid], $bwlimit) // 0;
7036 print STDERR "rate limit for storage $storeid: $limit KiB/s\n" if $limit;
7037 $storage_limits{$storeid} = $limit * 1024;
7c536e11
WB
7038 }
7039
91bd6c90 7040 foreach my $devname (keys %$devinfo) {
be190583
DM
7041 die "found no device mapping information for device '$devname'\n"
7042 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
7043 }
7044
ed221350 7045 # create empty/temp config
be190583 7046 if ($oldconf) {
ed221350 7047 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
d1e92cf6 7048 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
ed221350
DM
7049 }
7050
9f3d73bc
DM
7051 # allocate volumes
7052 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
7053
7054 # print restore information to $fifofh
91bd6c90
DM
7055 foreach my $virtdev (sort keys %$virtdev_hash) {
7056 my $d = $virtdev_hash->{$virtdev};
9f3d73bc
DM
7057 next if $d->{is_cloudinit}; # no need to restore cloudinit
7058
7c536e11 7059 my $storeid = $d->{storeid};
9f3d73bc 7060 my $volid = $d->{volid};
7c536e11
WB
7061
7062 my $map_opts = '';
7063 if (my $limit = $storage_limits{$storeid}) {
7064 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
7065 }
8fd57431 7066
91bd6c90 7067 my $write_zeros = 1;
88240a83 7068 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
7069 $write_zeros = 0;
7070 }
7071
9f3d73bc 7072 my $path = PVE::Storage::path($cfg, $volid);
87056e18 7073
9f3d73bc 7074 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 7075
9f3d73bc 7076 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
91bd6c90
DM
7077 }
7078
7079 $fh->seek(0, 0) || die "seek failed - $!\n";
7080
91bd6c90
DM
7081 my $cookie = { netcount => 0 };
7082 while (defined(my $line = <$fh>)) {
c62d7cf5 7083 $new_conf_raw .= restore_update_config_line(
98a4b3fb 7084 $cookie,
98a4b3fb
FE
7085 $map,
7086 $line,
7087 $opts->{unique},
7088 );
91bd6c90
DM
7089 }
7090
7091 $fh->close();
91bd6c90
DM
7092 };
7093
7094 eval {
7095 # enable interrupts
6cb0144a
EK
7096 local $SIG{INT} =
7097 local $SIG{TERM} =
7098 local $SIG{QUIT} =
7099 local $SIG{HUP} =
7100 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
7101 local $SIG{ALRM} = sub { die "got timeout\n"; };
7102
7103 $oldtimeout = alarm($timeout);
7104
7105 my $parser = sub {
7106 my $line = shift;
7107
7108 print "$line\n";
7109
7110 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
7111 my ($dev_id, $size, $devname) = ($1, $2, $3);
7112 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
7113 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 7114 # we correctly received the vma config, so we can disable
3cf90d7a
DM
7115 # the timeout now for disk allocation (set to 10 minutes, so
7116 # that we always timeout if something goes wrong)
7117 alarm(600);
91bd6c90
DM
7118 &$print_devmap();
7119 print $fifofh "done\n";
7120 my $tmp = $oldtimeout || 0;
7121 $oldtimeout = undef;
7122 alarm($tmp);
7123 close($fifofh);
808a65b5 7124 $fifofh = undef;
91bd6c90
DM
7125 }
7126 };
be190583 7127
7c536e11
WB
7128 print "restore vma archive: $dbg_cmdstring\n";
7129 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
7130 };
7131 my $err = $@;
7132
7133 alarm($oldtimeout) if $oldtimeout;
7134
e8b07b29 7135 $restore_deactivate_volumes->($cfg, $virtdev_hash);
5f96f4df 7136
808a65b5 7137 close($fifofh) if $fifofh;
91bd6c90 7138 unlink $mapfifo;
9f3d73bc 7139 rmtree $tmpdir;
91bd6c90
DM
7140
7141 if ($err) {
e8b07b29 7142 $restore_destroy_volumes->($cfg, $virtdev_hash);
91bd6c90
DM
7143 die $err;
7144 }
7145
202a2a0b
FE
7146 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $opts->{override_conf});
7147 PVE::QemuConfig->write_config($vmid, $new_conf);
ed221350 7148
91bd6c90
DM
7149 eval { rescan($vmid, 1); };
7150 warn $@ if $@;
26731a3c
SR
7151
7152 PVE::AccessControl::add_vm_to_pool($vmid, $opts->{pool}) if $opts->{pool};
91bd6c90
DM
7153}
7154
7155sub restore_tar_archive {
7156 my ($archive, $vmid, $user, $opts) = @_;
7157
202a2a0b
FE
7158 if (scalar(keys $opts->{override_conf}->%*) > 0) {
7159 my $keystring = join(' ', keys $opts->{override_conf}->%*);
7160 die "cannot pass along options ($keystring) when restoring from tar archive\n";
7161 }
7162
9c502e26 7163 if ($archive ne '-') {
ed221350 7164 my $firstfile = tar_archive_read_firstfile($archive);
32e54050 7165 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
9c502e26
DM
7166 if $firstfile ne 'qemu-server.conf';
7167 }
3e16d5fc 7168
20519efc 7169 my $storecfg = PVE::Storage::config();
ebb55558 7170
4b026937
TL
7171 # avoid zombie disks when restoring over an existing VM -> cleanup first
7172 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
7173 # skiplock=1 because qmrestore has set the 'create' lock itself already
ffda963f 7174 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
b04ea584 7175 destroy_vm($storecfg, $vmid, 1, { lock => 'restore' }) if -f $vmcfgfn;
ed221350 7176
3e16d5fc
DM
7177 my $tocmd = "/usr/lib/qemu-server/qmextract";
7178
2415a446 7179 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 7180 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
7181 $tocmd .= ' --prealloc' if $opts->{prealloc};
7182 $tocmd .= ' --info' if $opts->{info};
7183
a0d1b1a2 7184 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 7185 # so we pipe to zcat
2415a446
DM
7186 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
7187 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
7188
7189 my $tmpdir = "/var/tmp/vzdumptmp$$";
7190 mkpath $tmpdir;
7191
7192 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
7193 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 7194 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 7195
ffda963f 7196 my $conffile = PVE::QemuConfig->config_file($vmid);
98a4b3fb 7197 my $new_conf_raw = '';
3e16d5fc
DM
7198
7199 # disable interrupts (always do cleanups)
6cb0144a
EK
7200 local $SIG{INT} =
7201 local $SIG{TERM} =
7202 local $SIG{QUIT} =
7203 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 7204
afdb31d5 7205 eval {
3e16d5fc 7206 # enable interrupts
6cb0144a
EK
7207 local $SIG{INT} =
7208 local $SIG{TERM} =
7209 local $SIG{QUIT} =
7210 local $SIG{HUP} =
7211 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 7212
9c502e26
DM
7213 if ($archive eq '-') {
7214 print "extracting archive from STDIN\n";
7215 run_command($cmd, input => "<&STDIN");
7216 } else {
7217 print "extracting archive '$archive'\n";
7218 run_command($cmd);
7219 }
3e16d5fc
DM
7220
7221 return if $opts->{info};
7222
7223 # read new mapping
7224 my $map = {};
7225 my $statfile = "$tmpdir/qmrestore.stat";
7226 if (my $fd = IO::File->new($statfile, "r")) {
7227 while (defined (my $line = <$fd>)) {
7228 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
7229 $map->{$1} = $2 if $1;
7230 } else {
7231 print STDERR "unable to parse line in statfile - $line\n";
7232 }
7233 }
7234 $fd->close();
7235 }
7236
7237 my $confsrc = "$tmpdir/qemu-server.conf";
7238
f7d1505b 7239 my $srcfd = IO::File->new($confsrc, "r") || die "unable to open file '$confsrc'\n";
3e16d5fc 7240
91bd6c90 7241 my $cookie = { netcount => 0 };
3e16d5fc 7242 while (defined (my $line = <$srcfd>)) {
c62d7cf5 7243 $new_conf_raw .= restore_update_config_line(
98a4b3fb 7244 $cookie,
98a4b3fb
FE
7245 $map,
7246 $line,
7247 $opts->{unique},
7248 );
3e16d5fc
DM
7249 }
7250
7251 $srcfd->close();
3e16d5fc 7252 };
7dc7f315 7253 if (my $err = $@) {
ed221350 7254 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
3e16d5fc 7255 die $err;
afdb31d5 7256 }
3e16d5fc
DM
7257
7258 rmtree $tmpdir;
7259
98a4b3fb 7260 PVE::Tools::file_set_contents($conffile, $new_conf_raw);
91bd6c90 7261
ed221350
DM
7262 PVE::Cluster::cfs_update(); # make sure we read new file
7263
91bd6c90
DM
7264 eval { rescan($vmid, 1); };
7265 warn $@ if $@;
3e16d5fc
DM
7266};
7267
65a5ce88 7268sub foreach_storage_used_by_vm {
18bfb361
DM
7269 my ($conf, $func) = @_;
7270
7271 my $sidhash = {};
7272
912792e2 7273 PVE::QemuConfig->foreach_volume($conf, sub {
8ddbcf8b
FG
7274 my ($ds, $drive) = @_;
7275 return if drive_is_cdrom($drive);
18bfb361
DM
7276
7277 my $volid = $drive->{file};
7278
7279 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 7280 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 7281 });
18bfb361
DM
7282
7283 foreach my $sid (sort keys %$sidhash) {
7284 &$func($sid);
7285 }
7286}
7287
6c9f59c1
TL
7288my $qemu_snap_storage = {
7289 rbd => 1,
7290};
e5eaa028 7291sub do_snapshots_with_qemu {
9d83932d
SR
7292 my ($storecfg, $volid, $deviceid) = @_;
7293
7294 return if $deviceid =~ m/tpmstate0/;
e5eaa028
WL
7295
7296 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 7297 my $scfg = $storecfg->{ids}->{$storage_name};
f7d1505b 7298 die "could not find storage '$storage_name'\n" if !defined($scfg);
e5eaa028 7299
8aa2ed7c 7300 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
7301 return 1;
7302 }
7303
7304 if ($volid =~ m/\.(qcow2|qed)$/){
7305 return 1;
7306 }
7307
d1c1af4b 7308 return;
e5eaa028
WL
7309}
7310
4dcc780c 7311sub qga_check_running {
a4938c72 7312 my ($vmid, $nowarn) = @_;
4dcc780c 7313
0a13e08e 7314 eval { mon_cmd($vmid, "guest-ping", timeout => 3); };
4dcc780c 7315 if ($@) {
a4938c72 7316 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
7317 return 0;
7318 }
7319 return 1;
7320}
7321
04a69bb4
AD
7322sub template_create {
7323 my ($vmid, $conf, $disk) = @_;
7324
04a69bb4 7325 my $storecfg = PVE::Storage::config();
04a69bb4 7326
912792e2 7327 PVE::QemuConfig->foreach_volume($conf, sub {
9cd07842
DM
7328 my ($ds, $drive) = @_;
7329
7330 return if drive_is_cdrom($drive);
7331 return if $disk && $ds ne $disk;
7332
7333 my $volid = $drive->{file};
bbd56097 7334 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 7335
04a69bb4
AD
7336 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
7337 $drive->{file} = $voliddst;
71c58bb7 7338 $conf->{$ds} = print_drive($drive);
ffda963f 7339 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 7340 });
04a69bb4
AD
7341}
7342
92bdc3f0
DC
7343sub convert_iscsi_path {
7344 my ($path) = @_;
7345
7346 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
7347 my $portal = $1;
7348 my $target = $2;
7349 my $lun = $3;
7350
7351 my $initiator_name = get_initiator_name();
7352
7353 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
7354 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
7355 }
7356
7357 die "cannot convert iscsi path '$path', unkown format\n";
7358}
7359
5133de42 7360sub qemu_img_convert {
988e2714 7361 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
7362
7363 my $storecfg = PVE::Storage::config();
7364 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
7365 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
7366
af1f1ec0 7367 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6bb91c17 7368
af1f1ec0
DC
7369 my $cachemode;
7370 my $src_path;
7371 my $src_is_iscsi = 0;
bdd1feef 7372 my $src_format;
6bb91c17 7373
af1f1ec0
DC
7374 if ($src_storeid) {
7375 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
5133de42 7376 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
af1f1ec0
DC
7377 $src_format = qemu_img_format($src_scfg, $src_volname);
7378 $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
7379 $src_is_iscsi = ($src_path =~ m|^iscsi://|);
7380 $cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
a23d57d5 7381 } elsif (-f $src_volid || -b $src_volid) {
af1f1ec0 7382 $src_path = $src_volid;
e0fd2b2f 7383 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
af1f1ec0
DC
7384 $src_format = $1;
7385 }
7386 }
5133de42 7387
af1f1ec0 7388 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
5133de42 7389
af1f1ec0
DC
7390 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
7391 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
7392 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
7393 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
5133de42 7394
af1f1ec0
DC
7395 my $cmd = [];
7396 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
bdd1feef
TL
7397 push @$cmd, '-l', "snapshot.name=$snapname"
7398 if $snapname && $src_format && $src_format eq "qcow2";
af1f1ec0
DC
7399 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
7400 push @$cmd, '-T', $cachemode if defined($cachemode);
7401
7402 if ($src_is_iscsi) {
7403 push @$cmd, '--image-opts';
7404 $src_path = convert_iscsi_path($src_path);
bdd1feef 7405 } elsif ($src_format) {
af1f1ec0
DC
7406 push @$cmd, '-f', $src_format;
7407 }
92bdc3f0 7408
af1f1ec0
DC
7409 if ($dst_is_iscsi) {
7410 push @$cmd, '--target-image-opts';
7411 $dst_path = convert_iscsi_path($dst_path);
7412 } else {
7413 push @$cmd, '-O', $dst_format;
7414 }
92bdc3f0 7415
af1f1ec0 7416 push @$cmd, $src_path;
92bdc3f0 7417
af1f1ec0
DC
7418 if (!$dst_is_iscsi && $is_zero_initialized) {
7419 push @$cmd, "zeroinit:$dst_path";
7420 } else {
7421 push @$cmd, $dst_path;
7422 }
92bdc3f0 7423
af1f1ec0
DC
7424 my $parser = sub {
7425 my $line = shift;
7426 if($line =~ m/\((\S+)\/100\%\)/){
7427 my $percent = $1;
7428 my $transferred = int($size * $percent / 100);
b5e9d97b
TL
7429 my $total_h = render_bytes($size, 1);
7430 my $transferred_h = render_bytes($transferred, 1);
92bdc3f0 7431
6629f976 7432 print "transferred $transferred_h of $total_h ($percent%)\n";
988e2714 7433 }
5133de42 7434
af1f1ec0 7435 };
5133de42 7436
af1f1ec0
DC
7437 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
7438 my $err = $@;
7439 die "copy failed: $err" if $err;
5133de42
AD
7440}
7441
7442sub qemu_img_format {
7443 my ($scfg, $volname) = @_;
7444
e0fd2b2f 7445 if ($scfg->{path} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
5133de42 7446 return $1;
be190583 7447 } else {
5133de42 7448 return "raw";
5133de42
AD
7449 }
7450}
7451
cfad42af 7452sub qemu_drive_mirror {
bc6c8231 7453 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
cfad42af 7454
5a345967
AD
7455 $jobs = {} if !$jobs;
7456
7457 my $qemu_target;
7458 my $format;
35e4ab04 7459 $jobs->{"drive-$drive"} = {};
152fe752 7460
1e5143de 7461 if ($dst_volid =~ /^nbd:/) {
87955688 7462 $qemu_target = $dst_volid;
5a345967 7463 $format = "nbd";
5a345967 7464 } else {
5a345967
AD
7465 my $storecfg = PVE::Storage::config();
7466 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
7467
7468 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 7469
5a345967 7470 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 7471
5a345967 7472 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 7473
5a345967
AD
7474 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
7475 }
988e2714
WB
7476
7477 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
7478 $opts->{format} = $format if $format;
7479
bc6c8231
FG
7480 if (defined($src_bitmap)) {
7481 $opts->{sync} = 'incremental';
7482 $opts->{bitmap} = $src_bitmap;
7483 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7484 }
7485
9fa05d31 7486 if (defined($bwlimit)) {
f6409f61
TL
7487 $opts->{speed} = $bwlimit * 1024;
7488 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
7489 } else {
7490 print "drive mirror is starting for drive-$drive\n";
7491 }
21ccdb50 7492
6dde5ea2 7493 # if a job already runs for this device we get an error, catch it for cleanup
0a13e08e 7494 eval { mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
7495 if (my $err = $@) {
7496 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
7497 warn "$@\n" if $@;
7498 die "mirroring error: $err\n";
5a345967
AD
7499 }
7500
e02fb126 7501 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga);
5a345967
AD
7502}
7503
db1f8b39
FG
7504# $completion can be either
7505# 'complete': wait until all jobs are ready, block-job-complete them (default)
7506# 'cancel': wait until all jobs are ready, block-job-cancel them
7507# 'skip': wait until all jobs are ready, return with block jobs in ready state
9e671722 7508# 'auto': wait until all jobs disappear, only use for jobs which complete automatically
5a345967 7509sub qemu_drive_mirror_monitor {
9e671722 7510 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
e02fb126 7511
db1f8b39 7512 $completion //= 'complete';
9e671722 7513 $op //= "mirror";
2e953867 7514
08ac653f 7515 eval {
5a345967
AD
7516 my $err_complete = 0;
7517
3b56383b 7518 my $starttime = time ();
08ac653f 7519 while (1) {
9e671722 7520 die "block job ('$op') timed out\n" if $err_complete > 300;
5a345967 7521
0a13e08e 7522 my $stats = mon_cmd($vmid, "query-block-jobs");
3b56383b 7523 my $ctime = time();
08ac653f 7524
9e671722 7525 my $running_jobs = {};
0ea24bf0 7526 for my $stat (@$stats) {
9e671722
SR
7527 next if $stat->{type} ne $op;
7528 $running_jobs->{$stat->{device}} = $stat;
5a345967 7529 }
08ac653f 7530
5a345967 7531 my $readycounter = 0;
67fb9de6 7532
0ea24bf0 7533 for my $job_id (sort keys %$jobs) {
1057fc74 7534 my $job = $running_jobs->{$job_id};
5a345967 7535
1057fc74 7536 my $vanished = !defined($job);
0ea24bf0 7537 my $complete = defined($jobs->{$job_id}->{complete}) && $vanished;
9e671722 7538 if($complete || ($vanished && $completion eq 'auto')) {
3b56383b 7539 print "$job_id: $op-job finished\n";
0ea24bf0 7540 delete $jobs->{$job_id};
5a345967
AD
7541 next;
7542 }
7543
1057fc74 7544 die "$job_id: '$op' has been cancelled\n" if !defined($job);
f34ebd52 7545
1057fc74
TL
7546 my $busy = $job->{busy};
7547 my $ready = $job->{ready};
7548 if (my $total = $job->{len}) {
7549 my $transferred = $job->{offset} || 0;
5a345967
AD
7550 my $remaining = $total - $transferred;
7551 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 7552
3b56383b
TL
7553 my $duration = $ctime - $starttime;
7554 my $total_h = render_bytes($total, 1);
7555 my $transferred_h = render_bytes($transferred, 1);
7556
7557 my $status = sprintf(
7558 "transferred $transferred_h of $total_h ($percent%%) in %s",
7559 render_duration($duration),
7560 );
7561
7562 if ($ready) {
7563 if ($busy) {
7564 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7565 } else {
7566 $status .= ", ready";
7567 }
7568 }
67daf692
TL
7569 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready};
7570 $jobs->{$job_id}->{ready} = $ready;
5a345967 7571 }
f34ebd52 7572
1057fc74 7573 $readycounter++ if $job->{ready};
5a345967 7574 }
b467f79a 7575
5a345967
AD
7576 last if scalar(keys %$jobs) == 0;
7577
7578 if ($readycounter == scalar(keys %$jobs)) {
9e671722
SR
7579 print "all '$op' jobs are ready\n";
7580
7581 # do the complete later (or has already been done)
7582 last if $completion eq 'skip' || $completion eq 'auto';
5a345967
AD
7583
7584 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
7585 my $agent_running = $qga && qga_check_running($vmid);
7586 if ($agent_running) {
5619e74a 7587 print "freeze filesystem\n";
0a13e08e 7588 eval { mon_cmd($vmid, "guest-fsfreeze-freeze"); };
d6cdfae4 7589 warn $@ if $@;
5619e74a
AD
7590 } else {
7591 print "suspend vm\n";
7592 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
d6cdfae4 7593 warn $@ if $@;
5619e74a
AD
7594 }
7595
5a345967
AD
7596 # if we clone a disk for a new target vm, we don't switch the disk
7597 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 7598
1a988fd2 7599 if ($agent_running) {
5619e74a 7600 print "unfreeze filesystem\n";
0a13e08e 7601 eval { mon_cmd($vmid, "guest-fsfreeze-thaw"); };
d6cdfae4 7602 warn $@ if $@;
5619e74a
AD
7603 } else {
7604 print "resume vm\n";
d6cdfae4
FE
7605 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
7606 warn $@ if $@;
5619e74a
AD
7607 }
7608
2e953867 7609 last;
5a345967
AD
7610 } else {
7611
0ea24bf0 7612 for my $job_id (sort keys %$jobs) {
5a345967 7613 # try to switch the disk if source and destination are on the same guest
0ea24bf0 7614 print "$job_id: Completing block job_id...\n";
5a345967 7615
e02fb126 7616 my $op;
db1f8b39 7617 if ($completion eq 'complete') {
e02fb126 7618 $op = 'block-job-complete';
db1f8b39 7619 } elsif ($completion eq 'cancel') {
e02fb126
ML
7620 $op = 'block-job-cancel';
7621 } else {
7622 die "invalid completion value: $completion\n";
7623 }
0ea24bf0 7624 eval { mon_cmd($vmid, $op, device => $job_id) };
5a345967 7625 if ($@ =~ m/cannot be completed/) {
3b56383b 7626 print "$job_id: block job cannot be completed, trying again.\n";
5a345967
AD
7627 $err_complete++;
7628 }else {
0ea24bf0
TL
7629 print "$job_id: Completed successfully.\n";
7630 $jobs->{$job_id}->{complete} = 1;
5a345967
AD
7631 }
7632 }
2e953867 7633 }
08ac653f 7634 }
08ac653f 7635 sleep 1;
cfad42af 7636 }
08ac653f 7637 };
88383920 7638 my $err = $@;
08ac653f 7639
88383920 7640 if ($err) {
5a345967 7641 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
3b56383b 7642 die "block job ($op) error: $err";
88383920 7643 }
5a345967
AD
7644}
7645
7646sub qemu_blockjobs_cancel {
7647 my ($vmid, $jobs) = @_;
7648
7649 foreach my $job (keys %$jobs) {
bd2d5fe6 7650 print "$job: Cancelling block job\n";
0a13e08e 7651 eval { mon_cmd($vmid, "block-job-cancel", device => $job); };
5a345967
AD
7652 $jobs->{$job}->{cancel} = 1;
7653 }
7654
7655 while (1) {
0a13e08e 7656 my $stats = mon_cmd($vmid, "query-block-jobs");
5a345967
AD
7657
7658 my $running_jobs = {};
7659 foreach my $stat (@$stats) {
7660 $running_jobs->{$stat->{device}} = $stat;
7661 }
7662
7663 foreach my $job (keys %$jobs) {
7664
bd2d5fe6
WB
7665 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
7666 print "$job: Done.\n";
5a345967
AD
7667 delete $jobs->{$job};
7668 }
7669 }
7670
7671 last if scalar(keys %$jobs) == 0;
7672
7673 sleep 1;
cfad42af
AD
7674 }
7675}
7676
152fe752 7677sub clone_disk {
1196086f
FE
7678 my ($storecfg, $source, $dest, $full, $newvollist, $jobs, $completion, $qga, $bwlimit) = @_;
7679
7680 my ($vmid, $running) = $source->@{qw(vmid running)};
25166060 7681 my ($src_drivename, $drive, $snapname) = $source->@{qw(drivename drive snapname)};
1196086f 7682
25166060 7683 my ($newvmid, $dst_drivename, $efisize) = $dest->@{qw(vmid drivename efisize)};
1196086f 7684 my ($storage, $format) = $dest->@{qw(storage format)};
152fe752 7685
5f957592
FE
7686 my $use_drive_mirror = $full && $running && $src_drivename && !$snapname;
7687
25166060
FE
7688 if ($src_drivename && $dst_drivename && $src_drivename ne $dst_drivename) {
7689 die "cloning from/to EFI disk requires EFI disk\n"
7690 if $src_drivename eq 'efidisk0' || $dst_drivename eq 'efidisk0';
7691 die "cloning from/to TPM state requires TPM state\n"
7692 if $src_drivename eq 'tpmstate0' || $dst_drivename eq 'tpmstate0';
5f957592
FE
7693
7694 # This would lead to two device nodes in QEMU pointing to the same backing image!
7695 die "cannot change drive name when cloning disk from/to the same VM\n"
7696 if $use_drive_mirror && $vmid == $newvmid;
25166060
FE
7697 }
7698
1d1f8f9a
FE
7699 die "cannot move TPM state while VM is running\n"
7700 if $use_drive_mirror && $src_drivename eq 'tpmstate0';
7701
152fe752
DM
7702 my $newvolid;
7703
25166060
FE
7704 print "create " . ($full ? 'full' : 'linked') . " clone of drive ";
7705 print "$src_drivename " if $src_drivename;
7706 print "($drive->{file})\n";
7707
152fe752 7708 if (!$full) {
258e646c 7709 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
7710 push @$newvollist, $newvolid;
7711 } else {
5a345967 7712
152fe752
DM
7713 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
7714 $storeid = $storage if $storage;
7715
44549149 7716 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752 7717
931432bd 7718 my $name = undef;
d0abc774 7719 my $size = undef;
7fe8b44c
TL
7720 if (drive_is_cloudinit($drive)) {
7721 $name = "vm-$newvmid-cloudinit";
c997e24a
ML
7722 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7723 if ($scfg->{path}) {
7724 $name .= ".$dst_format";
7725 }
7fe8b44c
TL
7726 $snapname = undef;
7727 $size = PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE;
25166060 7728 } elsif ($dst_drivename eq 'efidisk0') {
7344af7b 7729 $size = $efisize or die "internal error - need to specify EFI disk size\n";
25166060 7730 } elsif ($dst_drivename eq 'tpmstate0') {
5f5aba25 7731 $dst_format = 'raw';
f9dde219 7732 $size = PVE::QemuServer::Drive::TPMSTATE_DISK_SIZE;
d0abc774 7733 } else {
3bae384f 7734 ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 10);
7fe8b44c 7735 }
b5688f69
FE
7736 $newvolid = PVE::Storage::vdisk_alloc(
7737 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7738 );
152fe752
DM
7739 push @$newvollist, $newvolid;
7740
3999f370 7741 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 7742
7fe8b44c 7743 if (drive_is_cloudinit($drive)) {
1b485263
ML
7744 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7745 # if this is the case, we have to complete any block-jobs still there from
7746 # previous drive-mirrors
7747 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7748 qemu_drive_mirror_monitor($vmid, $newvmid, $jobs, $completion, $qga);
7749 }
7fe8b44c
TL
7750 goto no_data_clone;
7751 }
7752
988e2714 7753 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
5f957592 7754 if ($use_drive_mirror) {
5f957592
FE
7755 qemu_drive_mirror($vmid, $src_drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7756 $completion, $qga, $bwlimit);
7757 } else {
d189e590 7758 # TODO: handle bwlimits
25166060 7759 if ($dst_drivename eq 'efidisk0') {
818ce80e
DC
7760 # the relevant data on the efidisk may be smaller than the source
7761 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7762 # that is given by the OVMF_VARS.fd
62375438 7763 my $src_path = PVE::Storage::path($storecfg, $drive->{file}, $snapname);
818ce80e 7764 my $dst_path = PVE::Storage::path($storecfg, $newvolid);
fdfdc80e 7765
62375438
FE
7766 my $src_format = (PVE::Storage::parse_volname($storecfg, $drive->{file}))[6];
7767
fdfdc80e
FE
7768 # better for Ceph if block size is not too small, see bug #3324
7769 my $bs = 1024*1024;
7770
62375438 7771 my $cmd = ['qemu-img', 'dd', '-n', '-O', $dst_format];
a9c45bd4
FE
7772
7773 if ($src_format eq 'qcow2' && $snapname) {
7774 die "cannot clone qcow2 EFI disk snapshot - requires QEMU >= 6.2\n"
7775 if !min_version(kvm_user_version(), 6, 2);
7776 push $cmd->@*, '-l', $snapname;
7777 }
62375438
FE
7778 push $cmd->@*, "bs=$bs", "osize=$size", "if=$src_path", "of=$dst_path";
7779 run_command($cmd);
818ce80e
DC
7780 } else {
7781 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
7782 }
be190583 7783 }
152fe752
DM
7784 }
7785
7fe8b44c 7786no_data_clone:
3bae384f 7787 my ($size) = eval { PVE::Storage::volume_size_info($storecfg, $newvolid, 10) };
152fe752 7788
3b53c471
FE
7789 my $disk = dclone($drive);
7790 delete $disk->{format};
152fe752 7791 $disk->{file} = $newvolid;
3bae384f 7792 $disk->{size} = $size if defined($size);
152fe752
DM
7793
7794 return $disk;
7795}
7796
98cfd8b6
AD
7797sub get_running_qemu_version {
7798 my ($vmid) = @_;
0a13e08e 7799 my $res = mon_cmd($vmid, "query-version");
98cfd8b6
AD
7800 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7801}
7802
249c4a6c
AD
7803sub qemu_use_old_bios_files {
7804 my ($machine_type) = @_;
7805
7806 return if !$machine_type;
7807
7808 my $use_old_bios_files = undef;
7809
7810 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7811 $machine_type = $1;
7812 $use_old_bios_files = 1;
7813 } else {
4df98f2f 7814 my $version = extract_version($machine_type, kvm_user_version());
249c4a6c
AD
7815 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7816 # load new efi bios files on migration. So this hack is required to allow
7817 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7818 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
2ea5fb7e 7819 $use_old_bios_files = !min_version($version, 2, 4);
249c4a6c
AD
7820 }
7821
7822 return ($use_old_bios_files, $machine_type);
7823}
7824
818ce80e 7825sub get_efivars_size {
ff84f0e3
FE
7826 my ($conf, $efidisk) = @_;
7827
818ce80e 7828 my $arch = get_vm_arch($conf);
ff84f0e3 7829 $efidisk //= $conf->{efidisk0} ? parse_drive('efidisk0', $conf->{efidisk0}) : undef;
90b20b15
DC
7830 my $smm = PVE::QemuServer::Machine::machine_type_is_q35($conf);
7831 my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk, $smm);
818ce80e
DC
7832 die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
7833 return -s $ovmf_vars;
7834}
7835
7836sub update_efidisk_size {
7837 my ($conf) = @_;
7838
7839 return if !defined($conf->{efidisk0});
7840
7841 my $disk = PVE::QemuServer::parse_drive('efidisk0', $conf->{efidisk0});
7842 $disk->{size} = get_efivars_size($conf);
7843 $conf->{efidisk0} = print_drive($disk);
7844
7845 return;
7846}
7847
f9dde219
SR
7848sub update_tpmstate_size {
7849 my ($conf) = @_;
7850
7851 my $disk = PVE::QemuServer::parse_drive('tpmstate0', $conf->{tpmstate0});
7852 $disk->{size} = PVE::QemuServer::Drive::TPMSTATE_DISK_SIZE;
7853 $conf->{tpmstate0} = print_drive($disk);
7854}
7855
90b20b15
DC
7856sub create_efidisk($$$$$$$) {
7857 my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk, $smm) = @_;
3e1f1122 7858
90b20b15 7859 my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk, $smm);
96ed3574 7860 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 7861
af1f1ec0
DC
7862 my $vars_size_b = -s $ovmf_vars;
7863 my $vars_size = PVE::Tools::convert_size($vars_size_b, 'b' => 'kb');
3e1f1122
TL
7864 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7865 PVE::Storage::activate_volumes($storecfg, [$volid]);
7866
af1f1ec0 7867 qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0);
340dbcf7 7868 my ($size) = PVE::Storage::volume_size_info($storecfg, $volid, 3);
3e1f1122 7869
340dbcf7 7870 return ($volid, $size/1024);
3e1f1122
TL
7871}
7872
22de899a
AD
7873sub vm_iothreads_list {
7874 my ($vmid) = @_;
7875
0a13e08e 7876 my $res = mon_cmd($vmid, 'query-iothreads');
22de899a
AD
7877
7878 my $iothreads = {};
7879 foreach my $iothread (@$res) {
7880 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
7881 }
7882
7883 return $iothreads;
7884}
7885
ee034f5c
AD
7886sub scsihw_infos {
7887 my ($conf, $drive) = @_;
7888
7889 my $maxdev = 0;
7890
7fe1b688 7891 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 7892 $maxdev = 7;
a1511b3c 7893 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
7894 $maxdev = 1;
7895 } else {
7896 $maxdev = 256;
7897 }
7898
7899 my $controller = int($drive->{index} / $maxdev);
4df98f2f
TL
7900 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single')
7901 ? "virtioscsi"
7902 : "scsihw";
ee034f5c
AD
7903
7904 return ($maxdev, $controller, $controller_prefix);
7905}
a1511b3c 7906
4317f69f
AD
7907sub windows_version {
7908 my ($ostype) = @_;
7909
7910 return 0 if !$ostype;
7911
7912 my $winversion = 0;
7913
7914 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7915 $winversion = 5;
7916 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7917 $winversion = 6;
7918 } elsif ($ostype =~ m/^win(\d+)$/) {
7919 $winversion = $1;
7920 }
7921
7922 return $winversion;
7923}
7924
44549149
EK
7925sub resolve_dst_disk_format {
7926 my ($storecfg, $storeid, $src_volname, $format) = @_;
7927 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7928
7929 if (!$format) {
7930 # if no target format is specified, use the source disk format as hint
7931 if ($src_volname) {
7932 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7933 $format = qemu_img_format($scfg, $src_volname);
7934 } else {
7935 return $defFormat;
7936 }
7937 }
7938
7939 # test if requested format is supported - else use default
7940 my $supported = grep { $_ eq $format } @$validFormats;
7941 $format = $defFormat if !$supported;
7942 return $format;
7943}
7944
66cebc46
DC
7945# NOTE: if this logic changes, please update docs & possibly gui logic
7946sub find_vmstate_storage {
7947 my ($conf, $storecfg) = @_;
7948
7949 # first, return storage from conf if set
7950 return $conf->{vmstatestorage} if $conf->{vmstatestorage};
7951
7952 my ($target, $shared, $local);
7953
7954 foreach_storage_used_by_vm($conf, sub {
7955 my ($sid) = @_;
7956 my $scfg = PVE::Storage::storage_config($storecfg, $sid);
7957 my $dst = $scfg->{shared} ? \$shared : \$local;
7958 $$dst = $sid if !$$dst || $scfg->{path}; # prefer file based storage
7959 });
7960
7961 # second, use shared storage where VM has at least one disk
7962 # third, use local storage where VM has at least one disk
7963 # fall back to local storage
7964 $target = $shared // $local // 'local';
7965
7966 return $target;
7967}
7968
6ee499ff 7969sub generate_uuid {
ae2fcb3b
EK
7970 my ($uuid, $uuid_str);
7971 UUID::generate($uuid);
7972 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
7973 return $uuid_str;
7974}
7975
7976sub generate_smbios1_uuid {
7977 return "uuid=".generate_uuid();
ae2fcb3b
EK
7978}
7979
9c152e87
TL
7980sub nbd_stop {
7981 my ($vmid) = @_;
7982
0a13e08e 7983 mon_cmd($vmid, 'nbd-server-stop');
9c152e87
TL
7984}
7985
dae98db9
DC
7986sub create_reboot_request {
7987 my ($vmid) = @_;
7988 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7989 or die "failed to create reboot trigger file: $!\n";
7990 close($fh);
7991}
7992
7993sub clear_reboot_request {
7994 my ($vmid) = @_;
7995 my $path = "/run/qemu-server/$vmid.reboot";
7996 my $res = 0;
7997
7998 $res = unlink($path);
7999 die "could not remove reboot request for $vmid: $!"
8000 if !$res && $! != POSIX::ENOENT;
8001
8002 return $res;
8003}
8004
5cfa9f5f
SR
8005sub bootorder_from_legacy {
8006 my ($conf, $bootcfg) = @_;
8007
8008 my $boot = $bootcfg->{legacy} || $boot_fmt->{legacy}->{default};
8009 my $bootindex_hash = {};
8010 my $i = 1;
8011 foreach my $o (split(//, $boot)) {
8012 $bootindex_hash->{$o} = $i*100;
8013 $i++;
8014 }
8015
8016 my $bootorder = {};
8017
8018 PVE::QemuConfig->foreach_volume($conf, sub {
8019 my ($ds, $drive) = @_;
8020
8021 if (drive_is_cdrom ($drive, 1)) {
8022 if ($bootindex_hash->{d}) {
8023 $bootorder->{$ds} = $bootindex_hash->{d};
8024 $bootindex_hash->{d} += 1;
8025 }
8026 } elsif ($bootindex_hash->{c}) {
8027 $bootorder->{$ds} = $bootindex_hash->{c}
8028 if $conf->{bootdisk} && $conf->{bootdisk} eq $ds;
8029 $bootindex_hash->{c} += 1;
8030 }
8031 });
8032
8033 if ($bootindex_hash->{n}) {
8034 for (my $i = 0; $i < $MAX_NETS; $i++) {
8035 my $netname = "net$i";
8036 next if !$conf->{$netname};
8037 $bootorder->{$netname} = $bootindex_hash->{n};
8038 $bootindex_hash->{n} += 1;
8039 }
8040 }
8041
8042 return $bootorder;
8043}
8044
8045# Generate default device list for 'boot: order=' property. Matches legacy
8046# default boot order, but with explicit device names. This is important, since
8047# the fallback for when neither 'order' nor the old format is specified relies
8048# on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
8049sub get_default_bootdevices {
8050 my ($conf) = @_;
8051
8052 my @ret = ();
8053
8054 # harddisk
8055 my $first = PVE::QemuServer::Drive::resolve_first_disk($conf, 0);
8056 push @ret, $first if $first;
8057
8058 # cdrom
8059 $first = PVE::QemuServer::Drive::resolve_first_disk($conf, 1);
8060 push @ret, $first if $first;
8061
8062 # network
8063 for (my $i = 0; $i < $MAX_NETS; $i++) {
8064 my $netname = "net$i";
8065 next if !$conf->{$netname};
8066 push @ret, $netname;
8067 last;
8068 }
8069
8070 return \@ret;
8071}
8072
e5d611c3
TL
8073sub device_bootorder {
8074 my ($conf) = @_;
8075
8076 return bootorder_from_legacy($conf) if !defined($conf->{boot});
8077
8078 my $boot = parse_property_string($boot_fmt, $conf->{boot});
8079
8080 my $bootorder = {};
8081 if (!defined($boot) || $boot->{legacy}) {
8082 $bootorder = bootorder_from_legacy($conf, $boot);
8083 } elsif ($boot->{order}) {
8084 my $i = 100; # start at 100 to allow user to insert devices before us with -args
8085 for my $dev (PVE::Tools::split_list($boot->{order})) {
8086 $bootorder->{$dev} = $i++;
8087 }
8088 }
8089
8090 return $bootorder;
8091}
8092
65911545
SR
8093sub register_qmeventd_handle {
8094 my ($vmid) = @_;
8095
8096 my $fh;
8097 my $peer = "/var/run/qmeventd.sock";
8098 my $count = 0;
8099
8100 for (;;) {
8101 $count++;
8102 $fh = IO::Socket::UNIX->new(Peer => $peer, Blocking => 0, Timeout => 1);
8103 last if $fh;
8104 if ($! != EINTR && $! != EAGAIN) {
8105 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
8106 }
8107 if ($count > 4) {
8108 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
8109 . "after $count retries\n";
8110 }
8111 usleep(25000);
8112 }
8113
8114 # send handshake to mark VM as backing up
8115 print $fh to_json({vzdump => {vmid => "$vmid"}});
8116
8117 # return handle to be closed later when inhibit is no longer required
8118 return $fh;
8119}
8120
65e866e5
DM
8121# bash completion helper
8122
8123sub complete_backup_archives {
8124 my ($cmdname, $pname, $cvalue) = @_;
8125
8126 my $cfg = PVE::Storage::config();
8127
8128 my $storeid;
8129
8130 if ($cvalue =~ m/^([^:]+):/) {
8131 $storeid = $1;
8132 }
8133
8134 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
8135
8136 my $res = [];
8137 foreach my $id (keys %$data) {
8138 foreach my $item (@{$data->{$id}}) {
f43a4f12 8139 next if $item->{format} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
65e866e5
DM
8140 push @$res, $item->{volid} if defined($item->{volid});
8141 }
8142 }
8143
8144 return $res;
8145}
8146
8147my $complete_vmid_full = sub {
8148 my ($running) = @_;
8149
8150 my $idlist = vmstatus();
8151
8152 my $res = [];
8153
8154 foreach my $id (keys %$idlist) {
8155 my $d = $idlist->{$id};
8156 if (defined($running)) {
8157 next if $d->{template};
8158 next if $running && $d->{status} ne 'running';
8159 next if !$running && $d->{status} eq 'running';
8160 }
8161 push @$res, $id;
8162
8163 }
8164 return $res;
8165};
8166
8167sub complete_vmid {
8168 return &$complete_vmid_full();
8169}
8170
8171sub complete_vmid_stopped {
8172 return &$complete_vmid_full(0);
8173}
8174
8175sub complete_vmid_running {
8176 return &$complete_vmid_full(1);
8177}
8178
335af808
DM
8179sub complete_storage {
8180
8181 my $cfg = PVE::Storage::config();
8182 my $ids = $cfg->{ids};
8183
8184 my $res = [];
8185 foreach my $sid (keys %$ids) {
8186 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 8187 next if !$ids->{$sid}->{content}->{images};
335af808
DM
8188 push @$res, $sid;
8189 }
8190
8191 return $res;
8192}
8193
255e9c54
AL
8194sub complete_migration_storage {
8195 my ($cmd, $param, $current_value, $all_args) = @_;
8196
8197 my $targetnode = @$all_args[1];
8198
8199 my $cfg = PVE::Storage::config();
8200 my $ids = $cfg->{ids};
8201
8202 my $res = [];
8203 foreach my $sid (keys %$ids) {
8204 next if !PVE::Storage::storage_check_enabled($cfg, $sid, $targetnode, 1);
8205 next if !$ids->{$sid}->{content}->{images};
8206 push @$res, $sid;
8207 }
8208
8209 return $res;
8210}
8211
b08c37c3
DC
8212sub vm_is_paused {
8213 my ($vmid) = @_;
8214 my $qmpstatus = eval {
8215 PVE::QemuConfig::assert_config_exists_on_node($vmid);
8216 mon_cmd($vmid, "query-status");
8217 };
8218 warn "$@\n" if $@;
8219 return $qmpstatus && $qmpstatus->{status} eq "paused";
8220}
8221
3f11f0d7
LS
8222sub check_volume_storage_type {
8223 my ($storecfg, $vol) = @_;
8224
8225 my ($storeid, $volname) = PVE::Storage::parse_volume_id($vol);
8226 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
8227 my ($vtype) = PVE::Storage::parse_volname($storecfg, $vol);
8228
8229 die "storage '$storeid' does not support content-type '$vtype'\n"
8230 if !$scfg->{content}->{$vtype};
8231
8232 return 1;
8233}
8234
1e3baf05 82351;