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