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