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