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