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