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