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