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