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