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