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