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