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