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