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