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