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