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