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