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