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