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