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