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