]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
vm_start: split NBD disk allocation further
[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}
107 if defined($map->{entries}) && $map->{entries}->{$source};
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 {
67812f9c 2936 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
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
2ea5fb7e 3342 push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
519ed28c 3343
0567a4d5 3344 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
370b05e7 3345
1e3baf05
DM
3346 push @$cmd, '-S' if $conf->{freeze};
3347
b20df606 3348 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
1e3baf05 3349
48657158
MD
3350 my $guest_agent = parse_guest_agent($conf);
3351
3352 if ($guest_agent->{enabled}) {
d036e418 3353 my $qgasocket = PVE::QemuServer::Helpers::qmp_socket($vmid, 1);
ab6a046f 3354 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
48657158 3355
60f03a11 3356 if (!$guest_agent->{type} || $guest_agent->{type} eq 'virtio') {
48657158
MD
3357 my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $machine_type);
3358 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3359 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3360 } elsif ($guest_agent->{type} eq 'isa') {
3361 push @$devices, '-device', "isa-serial,chardev=qga0";
3362 }
ab6a046f
AD
3363 }
3364
2cf61f33
SR
3365 my $rng = parse_rng($conf->{rng0}) if $conf->{rng0};
3366 if ($rng && &$version_guard(4, 1, 2)) {
3367 my $max_bytes = $rng->{max_bytes} // $rng_fmt->{max_bytes}->{default};
3368 my $period = $rng->{period} // $rng_fmt->{period}->{default};
3369
3370 my $limiter_str = "";
3371 if ($max_bytes) {
3372 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3373 }
3374
3375 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3376 die "cannot create VirtIO RNG device: source file '$rng->{source}' doesn't exist\n"
3377 if ! -e $rng->{source};
3378
3379 my $rng_addr = print_pci_addr("rng0", $bridges, $arch, $machine_type);
3380
3381 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3382 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3383 }
3384
1d794448 3385 my $spice_port;
2fa3151e 3386
590e698c
DM
3387 if ($qxlnum) {
3388 if ($qxlnum > 1) {
ac087616 3389 if ($winversion){
590e698c 3390 for(my $i = 1; $i < $qxlnum; $i++){
2ea5fb7e 3391 push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
590e698c
DM
3392 }
3393 } else {
3394 # assume other OS works like Linux
55655ebc
DC
3395 my ($ram, $vram) = ("134217728", "67108864");
3396 if ($vga->{memory}) {
3397 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
3398 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
3399 }
3400 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3401 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
2fa3151e
AD
3402 }
3403 }
3404
d559309f 3405 my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type);
95a4b4a9 3406
af0eba7e 3407 my $pfamily = PVE::Tools::get_host_address_family($nodename);
91152441
WB
3408 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
3409 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
4d316a63
AL
3410
3411 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3412 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3413 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3414
91152441
WB
3415 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
3416 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
943340a6 3417
caab114a
TL
3418 my $spice_enhancement = PVE::JSONSchema::parse_property_string($spice_enhancements_fmt, $conf->{spice_enhancements} // '');
3419 if ($spice_enhancement->{foldersharing}) {
3420 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3421 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3422 }
c4df18db 3423
caab114a
TL
3424 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3425 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming};
3426 push @$devices, '-spice', "$spice_opts";
1011b570
DM
3427 }
3428
8d9ae0d2
DM
3429 # enable balloon by default, unless explicitly disabled
3430 if (!defined($conf->{balloon}) || $conf->{balloon}) {
d559309f 3431 $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
8d9ae0d2
DM
3432 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3433 }
1e3baf05 3434
0ea9541d
DM
3435 if ($conf->{watchdog}) {
3436 my $wdopts = parse_watchdog($conf->{watchdog});
d559309f 3437 $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
0a40e8ea 3438 my $watchdog = $wdopts->{model} || 'i6300esb';
5bdcf937
AD
3439 push @$devices, '-device', "$watchdog$pciaddr";
3440 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
0ea9541d
DM
3441 }
3442
1e3baf05 3443 my $vollist = [];
941e0c42 3444 my $scsicontroller = {};
26ee04b6 3445 my $ahcicontroller = {};
cdd20088 3446 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
1e3baf05 3447
5881b913
DM
3448 # Add iscsi initiator name if available
3449 if (my $initiator = get_initiator_name()) {
3450 push @$devices, '-iscsi', "initiator-name=$initiator";
3451 }
3452
1e3baf05
DM
3453 foreach_drive($conf, sub {
3454 my ($ds, $drive) = @_;
3455
ff1a2432 3456 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
1e3baf05 3457 push @$vollist, $drive->{file};
ff1a2432 3458 }
afdb31d5 3459
4dcce9ee
TL
3460 # ignore efidisk here, already added in bios/fw handling code above
3461 return if $drive->{interface} eq 'efidisk';
3462
1e3baf05 3463 $use_virtio = 1 if $ds =~ m/^virtio/;
3b408e82
DM
3464
3465 if (drive_is_cdrom ($drive)) {
3466 if ($bootindex_hash->{d}) {
3467 $drive->{bootindex} = $bootindex_hash->{d};
3468 $bootindex_hash->{d} += 1;
3469 }
3470 } else {
3471 if ($bootindex_hash->{c}) {
3472 $drive->{bootindex} = $bootindex_hash->{c} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
3473 $bootindex_hash->{c} += 1;
3474 }
3475 }
3476
51f492cd
AD
3477 if($drive->{interface} eq 'virtio'){
3478 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
3479 }
3480
941e0c42 3481 if ($drive->{interface} eq 'scsi') {
cdd20088 3482
ee034f5c 3483 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
6731a4cf 3484
b8fb1c03
SR
3485 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3486 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3487
d559309f 3488 $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
a1b7d579 3489 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
fc8b40fd
AD
3490
3491 my $iothread = '';
3492 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
3493 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3494 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
e7a5104d
DC
3495 } elsif ($drive->{iothread}) {
3496 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
fc8b40fd
AD
3497 }
3498
6e11f143
AD
3499 my $queues = '';
3500 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
3501 $queues = ",num_queues=$drive->{queues}";
370b05e7 3502 }
6e11f143
AD
3503
3504 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
cdd20088 3505 $scsicontroller->{$controller}=1;
941e0c42 3506 }
3b408e82 3507
26ee04b6 3508 if ($drive->{interface} eq 'sata') {
e0fd2b2f 3509 my $controller = int($drive->{index} / $PVE::QemuServer::Drive::MAX_SATA_DISKS);
d559309f 3510 $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
5bdcf937 3511 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
26ee04b6
DA
3512 $ahcicontroller->{$controller}=1;
3513 }
46f58b5f 3514
776c5f50 3515 my $drive_cmd = print_drive_commandline_full($storecfg, $vmid, $drive);
15b21acc 3516 push @$devices, '-drive',$drive_cmd;
d559309f 3517 push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
1e3baf05
DM
3518 });
3519
cc4d6182 3520 for (my $i = 0; $i < $MAX_NETS; $i++) {
5f0c4c32 3521 next if !$conf->{"net$i"};
cc4d6182
DA
3522 my $d = parse_net($conf->{"net$i"});
3523 next if !$d;
1e3baf05 3524
cc4d6182 3525 $use_virtio = 1 if $d->{model} eq 'virtio';
1e3baf05 3526
cc4d6182
DA
3527 if ($bootindex_hash->{n}) {
3528 $d->{bootindex} = $bootindex_hash->{n};
3529 $bootindex_hash->{n} += 1;
3530 }
1e3baf05 3531
d559309f 3532 my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, "net$i");
5bdcf937
AD
3533 push @$devices, '-netdev', $netdevfull;
3534
d559309f 3535 my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
5bdcf937
AD
3536 push @$devices, '-device', $netdevicefull;
3537 }
1e3baf05 3538
6dbcb073
DC
3539 if ($conf->{ivshmem}) {
3540 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
e3c27a6a 3541
6dbcb073
DC
3542 my $bus;
3543 if ($q35) {
3544 $bus = print_pcie_addr("ivshmem");
3545 } else {
3546 $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
3547 }
e3c27a6a
TL
3548
3549 my $ivshmem_name = $ivshmem->{name} // $vmid;
3550 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3551
6dbcb073
DC
3552 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3553 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
3554 }
3555
2513b862
DC
3556 # pci.4 is nested in pci.1
3557 $bridges->{1} = 1 if $bridges->{4};
3558
db656e5f
DM
3559 if (!$q35) {
3560 # add pci bridges
2ea5fb7e 3561 if (min_version($machine_version, 2, 3)) {
fc79e813
AD
3562 $bridges->{1} = 1;
3563 $bridges->{2} = 1;
3564 }
3565
6731a4cf
AD
3566 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3567
2513b862
DC
3568 }
3569
3570 for my $k (sort {$b cmp $a} keys %$bridges) {
3571 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3572 $pciaddr = print_pci_addr("pci.$k", undef, $arch, $machine_type);
3573 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3574 if ($q35) {
3575 # add after -readconfig pve-q35.cfg
3576 splice @$devices, 2, 0, '-device', $devstr;
3577 } else {
3578 unshift @$devices, '-device', $devstr if $k > 0;
f8e83f05 3579 }
19672434
DM
3580 }
3581
ac0077cc
SR
3582 if (!$kvm) {
3583 push @$machineFlags, 'accel=tcg';
3584 }
3585
3586 my $machine_type_min = $machine_type;
3587 if ($add_pve_version) {
3588 $machine_type_min =~ s/\+pve\d+$//;
3589 $machine_type_min .= "+pve$required_pve_version";
3590 }
3591 push @$machineFlags, "type=${machine_type_min}";
3592
5bdcf937 3593 push @$cmd, @$devices;
be190583 3594 push @$cmd, '-rtc', join(',', @$rtcFlags)
8c559505 3595 if scalar(@$rtcFlags);
be190583 3596 push @$cmd, '-machine', join(',', @$machineFlags)
8c559505
DM
3597 if scalar(@$machineFlags);
3598 push @$cmd, '-global', join(',', @$globalFlags)
3599 if scalar(@$globalFlags);
3600
7ceade4c
DC
3601 if (my $vmstate = $conf->{vmstate}) {
3602 my $statepath = PVE::Storage::path($storecfg, $vmstate);
24d1f93a 3603 push @$vollist, $vmstate;
7ceade4c 3604 push @$cmd, '-loadstate', $statepath;
b85666cf 3605 print "activating and using '$vmstate' as vmstate\n";
7ceade4c
DC
3606 }
3607
76350670
DC
3608 # add custom args
3609 if ($conf->{args}) {
3610 my $aa = PVE::Tools::split_args($conf->{args});
3611 push @$cmd, @$aa;
3612 }
3613
1d794448 3614 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
1e3baf05 3615}
19672434 3616
943340a6 3617sub spice_port {
1011b570 3618 my ($vmid) = @_;
943340a6 3619
0a13e08e 3620 my $res = mon_cmd($vmid, 'query-spice');
943340a6
DM
3621
3622 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
1011b570
DM
3623}
3624
86fdcfb2
DA
3625sub vm_devices_list {
3626 my ($vmid) = @_;
3627
0a13e08e 3628 my $res = mon_cmd($vmid, 'query-pci');
f721624b 3629 my $devices_to_check = [];
ceea9078
DM
3630 my $devices = {};
3631 foreach my $pcibus (@$res) {
f721624b
DC
3632 push @$devices_to_check, @{$pcibus->{devices}},
3633 }
3634
3635 while (@$devices_to_check) {
3636 my $to_check = [];
3637 for my $d (@$devices_to_check) {
3638 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3639 next if !$d->{'pci_bridge'};
3640
3641 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
3642 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
f78cc802 3643 }
f721624b 3644 $devices_to_check = $to_check;
f78cc802
AD
3645 }
3646
0a13e08e 3647 my $resblock = mon_cmd($vmid, 'query-block');
f78cc802
AD
3648 foreach my $block (@$resblock) {
3649 if($block->{device} =~ m/^drive-(\S+)/){
3650 $devices->{$1} = 1;
1dc4f496
DM
3651 }
3652 }
86fdcfb2 3653
0a13e08e 3654 my $resmice = mon_cmd($vmid, 'query-mice');
3d7389fe
DM
3655 foreach my $mice (@$resmice) {
3656 if ($mice->{name} eq 'QEMU HID Tablet') {
3657 $devices->{tablet} = 1;
3658 last;
3659 }
3660 }
3661
deb091c5
DC
3662 # for usb devices there is no query-usb
3663 # but we can iterate over the entries in
3664 # qom-list path=/machine/peripheral
0a13e08e 3665 my $resperipheral = mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
deb091c5
DC
3666 foreach my $per (@$resperipheral) {
3667 if ($per->{name} =~ m/^usb\d+$/) {
3668 $devices->{$per->{name}} = 1;
3669 }
3670 }
3671
1dc4f496 3672 return $devices;
86fdcfb2
DA
3673}
3674
ec21aa11 3675sub vm_deviceplug {
d559309f 3676 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
ae57f6b3 3677
3392d6ca 3678 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f 3679
95d6343b
DA
3680 my $devices_list = vm_devices_list($vmid);
3681 return 1 if defined($devices_list->{$deviceid});
3682
d559309f 3683 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
fee46675 3684
3d7389fe 3685 if ($deviceid eq 'tablet') {
fee46675 3686
d559309f
WB
3687 qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
3688
3689 } elsif ($deviceid eq 'keyboard') {
3690
3691 qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
3d7389fe 3692
4eb68604
DC
3693 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3694
f745762b
DC
3695 die "usb hotplug currently not reliable\n";
3696 # since we can't reliably hot unplug all added usb devices
3697 # and usb passthrough disables live migration
3698 # we disable usb hotplugging for now
4eb68604
DC
3699 qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
3700
fee46675 3701 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
40f28a9f 3702
22de899a
AD
3703 qemu_iothread_add($vmid, $deviceid, $device);
3704
fee46675 3705 qemu_driveadd($storecfg, $vmid, $device);
d559309f 3706 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675 3707
5e5dcb73 3708 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
3709 eval { qemu_deviceaddverify($vmid, $deviceid); };
3710 if (my $err = $@) {
63c2da2f
DM
3711 eval { qemu_drivedel($vmid, $deviceid); };
3712 warn $@ if $@;
fee46675 3713 die $err;
5e5dcb73 3714 }
cfc817c7 3715
2733141c 3716 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
fee46675 3717
fc8b40fd 3718
cdd20088 3719 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
d559309f 3720 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
a1b7d579 3721 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
2733141c
AD
3722
3723 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
fee46675 3724
fc8b40fd
AD
3725 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
3726 qemu_iothread_add($vmid, $deviceid, $device);
3727 $devicefull .= ",iothread=iothread-$deviceid";
3728 }
3729
6e11f143
AD
3730 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
3731 $devicefull .= ",num_queues=$device->{queues}";
3732 }
3733
cfc817c7 3734 qemu_deviceadd($vmid, $devicefull);
fee46675 3735 qemu_deviceaddverify($vmid, $deviceid);
cfc817c7 3736
fee46675
DM
3737 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3738
d559309f 3739 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
fee46675 3740 qemu_driveadd($storecfg, $vmid, $device);
a1b7d579 3741
d559309f 3742 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675
DM
3743 eval { qemu_deviceadd($vmid, $devicefull); };
3744 if (my $err = $@) {
63c2da2f
DM
3745 eval { qemu_drivedel($vmid, $deviceid); };
3746 warn $@ if $@;
fee46675 3747 die $err;
a4f091a0 3748 }
a4f091a0 3749
fee46675
DM
3750 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3751
95d3be58 3752 return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
8718099c 3753
3392d6ca 3754 my $machine_type = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
95d3be58
DC
3755 my $use_old_bios_files = undef;
3756 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
8718099c 3757
95d3be58
DC
3758 my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
3759 qemu_deviceadd($vmid, $netdevicefull);
79046fd1
DC
3760 eval {
3761 qemu_deviceaddverify($vmid, $deviceid);
3762 qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
3763 };
fee46675
DM
3764 if (my $err = $@) {
3765 eval { qemu_netdevdel($vmid, $deviceid); };
3766 warn $@ if $@;
3767 die $err;
95d3be58 3768 }
2630d2a9 3769
fee46675 3770 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
b467f79a 3771
40f28a9f 3772 my $bridgeid = $2;
d559309f 3773 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
40f28a9f 3774 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
a1b7d579 3775
40f28a9f 3776 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
3777 qemu_deviceaddverify($vmid, $deviceid);
3778
3779 } else {
a1b7d579 3780 die "can't hotplug device '$deviceid'\n";
40f28a9f
AD
3781 }
3782
5e5dcb73 3783 return 1;
a4dea331
DA
3784}
3785
3eec5767 3786# fixme: this should raise exceptions on error!
ec21aa11 3787sub vm_deviceunplug {
f19d1c47 3788 my ($vmid, $conf, $deviceid) = @_;
873c2d69 3789
95d6343b
DA
3790 my $devices_list = vm_devices_list($vmid);
3791 return 1 if !defined($devices_list->{$deviceid});
3792
63c2da2f
DM
3793 die "can't unplug bootdisk" if $conf->{bootdisk} && $conf->{bootdisk} eq $deviceid;
3794
d559309f 3795 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
63c2da2f 3796
3d7389fe 3797 qemu_devicedel($vmid, $deviceid);
3d7389fe 3798
4eb68604
DC
3799 } elsif ($deviceid =~ m/^usb\d+$/) {
3800
f745762b
DC
3801 die "usb hotplug currently not reliable\n";
3802 # when unplugging usb devices this way,
3803 # there may be remaining usb controllers/hubs
3804 # so we disable it for now
4eb68604
DC
3805 qemu_devicedel($vmid, $deviceid);
3806 qemu_devicedelverify($vmid, $deviceid);
3807
63c2da2f 3808 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
f19d1c47 3809
5e5dcb73 3810 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
3811 qemu_devicedelverify($vmid, $deviceid);
3812 qemu_drivedel($vmid, $deviceid);
22de899a
AD
3813 qemu_iothread_del($conf, $vmid, $deviceid);
3814
2733141c 3815 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
a1b7d579 3816
63c2da2f 3817 qemu_devicedel($vmid, $deviceid);
8ce30dde 3818 qemu_devicedelverify($vmid, $deviceid);
fc8b40fd 3819 qemu_iothread_del($conf, $vmid, $deviceid);
a1b7d579 3820
63c2da2f 3821 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
cfc817c7 3822
63c2da2f
DM
3823 qemu_devicedel($vmid, $deviceid);
3824 qemu_drivedel($vmid, $deviceid);
a1b7d579 3825 qemu_deletescsihw($conf, $vmid, $deviceid);
8ce30dde 3826
63c2da2f 3827 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
a4f091a0 3828
2630d2a9 3829 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
3830 qemu_devicedelverify($vmid, $deviceid);
3831 qemu_netdevdel($vmid, $deviceid);
3832
3833 } else {
3834 die "can't unplug device '$deviceid'\n";
2630d2a9
DA
3835 }
3836
5e5dcb73
DA
3837 return 1;
3838}
3839
3840sub qemu_deviceadd {
3841 my ($vmid, $devicefull) = @_;
873c2d69 3842
d695b5b7
AD
3843 $devicefull = "driver=".$devicefull;
3844 my %options = split(/[=,]/, $devicefull);
f19d1c47 3845
0a13e08e 3846 mon_cmd($vmid, "device_add" , %options);
5e5dcb73 3847}
afdb31d5 3848
5e5dcb73 3849sub qemu_devicedel {
fee46675 3850 my ($vmid, $deviceid) = @_;
63c2da2f 3851
0a13e08e 3852 my $ret = mon_cmd($vmid, "device_del", id => $deviceid);
5e5dcb73
DA
3853}
3854
22de899a
AD
3855sub qemu_iothread_add {
3856 my($vmid, $deviceid, $device) = @_;
3857
3858 if ($device->{iothread}) {
3859 my $iothreads = vm_iothreads_list($vmid);
3860 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3861 }
3862}
3863
3864sub qemu_iothread_del {
3865 my($conf, $vmid, $deviceid) = @_;
3866
7820eae4
DC
3867 my $confid = $deviceid;
3868 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
3869 $confid = 'scsi' . $1;
3870 }
3871 my $device = parse_drive($confid, $conf->{$confid});
22de899a
AD
3872 if ($device->{iothread}) {
3873 my $iothreads = vm_iothreads_list($vmid);
3874 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3875 }
3876}
3877
4d3f29ed
AD
3878sub qemu_objectadd {
3879 my($vmid, $objectid, $qomtype) = @_;
3880
0a13e08e 3881 mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4d3f29ed
AD
3882
3883 return 1;
3884}
3885
3886sub qemu_objectdel {
3887 my($vmid, $objectid) = @_;
3888
0a13e08e 3889 mon_cmd($vmid, "object-del", id => $objectid);
4d3f29ed
AD
3890
3891 return 1;
3892}
3893
5e5dcb73 3894sub qemu_driveadd {
fee46675 3895 my ($storecfg, $vmid, $device) = @_;
5e5dcb73 3896
776c5f50 3897 my $drive = print_drive_commandline_full($storecfg, $vmid, $device);
7a69fc3c 3898 $drive =~ s/\\/\\\\/g;
0a13e08e 3899 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_add auto \"$drive\"");
fee46675 3900
5e5dcb73 3901 # If the command succeeds qemu prints: "OK"
fee46675
DM
3902 return 1 if $ret =~ m/OK/s;
3903
3904 die "adding drive failed: $ret\n";
5e5dcb73 3905}
afdb31d5 3906
5e5dcb73
DA
3907sub qemu_drivedel {
3908 my($vmid, $deviceid) = @_;
873c2d69 3909
0a13e08e 3910 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-$deviceid");
5e5dcb73 3911 $ret =~ s/^\s+//;
a1b7d579 3912
63c2da2f 3913 return 1 if $ret eq "";
a1b7d579 3914
63c2da2f 3915 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
a1b7d579
DM
3916 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3917
63c2da2f 3918 die "deleting drive $deviceid failed : $ret\n";
5e5dcb73 3919}
f19d1c47 3920
5e5dcb73 3921sub qemu_deviceaddverify {
fee46675 3922 my ($vmid, $deviceid) = @_;
873c2d69 3923
5e5dcb73
DA
3924 for (my $i = 0; $i <= 5; $i++) {
3925 my $devices_list = vm_devices_list($vmid);
3926 return 1 if defined($devices_list->{$deviceid});
3927 sleep 1;
afdb31d5 3928 }
fee46675
DM
3929
3930 die "error on hotplug device '$deviceid'\n";
5e5dcb73 3931}
afdb31d5 3932
5e5dcb73
DA
3933
3934sub qemu_devicedelverify {
63c2da2f
DM
3935 my ($vmid, $deviceid) = @_;
3936
a1b7d579 3937 # need to verify that the device is correctly removed as device_del
63c2da2f 3938 # is async and empty return is not reliable
5e5dcb73 3939
5e5dcb73
DA
3940 for (my $i = 0; $i <= 5; $i++) {
3941 my $devices_list = vm_devices_list($vmid);
3942 return 1 if !defined($devices_list->{$deviceid});
3943 sleep 1;
afdb31d5 3944 }
63c2da2f
DM
3945
3946 die "error on hot-unplugging device '$deviceid'\n";
873c2d69
DA
3947}
3948
cdd20088 3949sub qemu_findorcreatescsihw {
d559309f 3950 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
cfc817c7 3951
ee034f5c 3952 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
2733141c
AD
3953
3954 my $scsihwid="$controller_prefix$controller";
cfc817c7
DA
3955 my $devices_list = vm_devices_list($vmid);
3956
cdd20088 3957 if(!defined($devices_list->{$scsihwid})) {
d559309f 3958 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
cfc817c7 3959 }
fee46675 3960
cfc817c7
DA
3961 return 1;
3962}
3963
8ce30dde
AD
3964sub qemu_deletescsihw {
3965 my ($conf, $vmid, $opt) = @_;
3966
3967 my $device = parse_drive($opt, $conf->{$opt});
3968
a1511b3c 3969 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
2733141c
AD
3970 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
3971 return 1;
3972 }
3973
ee034f5c 3974 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
8ce30dde
AD
3975
3976 my $devices_list = vm_devices_list($vmid);
3977 foreach my $opt (keys %{$devices_list}) {
e0fd2b2f
FE
3978 if (is_valid_drivename($opt)) {
3979 my $drive = parse_drive($opt, $conf->{$opt});
8ce30dde
AD
3980 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3981 return 1;
3982 }
3983 }
3984 }
3985
3986 my $scsihwid="scsihw$controller";
3987
3988 vm_deviceunplug($vmid, $conf, $scsihwid);
3989
3990 return 1;
3991}
3992
281fedb3 3993sub qemu_add_pci_bridge {
d559309f 3994 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
40f28a9f
AD
3995
3996 my $bridges = {};
281fedb3
DM
3997
3998 my $bridgeid;
3999
d559309f 4000 print_pci_addr($device, $bridges, $arch, $machine_type);
40f28a9f
AD
4001
4002 while (my ($k, $v) = each %$bridges) {
4003 $bridgeid = $k;
4004 }
fee46675 4005 return 1 if !defined($bridgeid) || $bridgeid < 1;
281fedb3 4006
40f28a9f
AD
4007 my $bridge = "pci.$bridgeid";
4008 my $devices_list = vm_devices_list($vmid);
4009
281fedb3 4010 if (!defined($devices_list->{$bridge})) {
d559309f 4011 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
40f28a9f 4012 }
281fedb3 4013
40f28a9f
AD
4014 return 1;
4015}
4016
25088687
DM
4017sub qemu_set_link_status {
4018 my ($vmid, $device, $up) = @_;
4019
0a13e08e 4020 mon_cmd($vmid, "set_link", name => $device,
25088687
DM
4021 up => $up ? JSON::true : JSON::false);
4022}
4023
2630d2a9 4024sub qemu_netdevadd {
d559309f 4025 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
2630d2a9 4026
d559309f 4027 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
73aa03b8 4028 my %options = split(/[=,]/, $netdev);
2630d2a9 4029
0a13e08e 4030 mon_cmd($vmid, "netdev_add", %options);
73aa03b8 4031 return 1;
2630d2a9
DA
4032}
4033
4034sub qemu_netdevdel {
4035 my ($vmid, $deviceid) = @_;
4036
0a13e08e 4037 mon_cmd($vmid, "netdev_del", id => $deviceid);
2630d2a9
DA
4038}
4039
16521d63 4040sub qemu_usb_hotplug {
d559309f 4041 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
16521d63
DC
4042
4043 return if !$device;
4044
4045 # remove the old one first
4046 vm_deviceunplug($vmid, $conf, $deviceid);
4047
4048 # check if xhci controller is necessary and available
4049 if ($device->{usb3}) {
4050
4051 my $devicelist = vm_devices_list($vmid);
4052
4053 if (!$devicelist->{xhci}) {
d559309f 4054 my $pciaddr = print_pci_addr("xhci", undef, $arch, $machine_type);
16521d63
DC
4055 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4056 }
4057 }
4058 my $d = parse_usb_device($device->{host});
4059 $d->{usb3} = $device->{usb3};
4060
4061 # add the new one
d559309f 4062 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
16521d63
DC
4063}
4064
838776ab 4065sub qemu_cpu_hotplug {
8edc9c08 4066 my ($vmid, $conf, $vcpus) = @_;
838776ab 4067
3392d6ca 4068 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
1e881b75 4069
8edc9c08
AD
4070 my $sockets = 1;
4071 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4072 $sockets = $conf->{sockets} if $conf->{sockets};
4073 my $cores = $conf->{cores} || 1;
4074 my $maxcpus = $sockets * $cores;
838776ab 4075
8edc9c08 4076 $vcpus = $maxcpus if !$vcpus;
3a11fadb 4077
8edc9c08
AD
4078 die "you can't add more vcpus than maxcpus\n"
4079 if $vcpus > $maxcpus;
3a11fadb 4080
8edc9c08 4081 my $currentvcpus = $conf->{vcpus} || $maxcpus;
1e881b75 4082
eba3e64d 4083 if ($vcpus < $currentvcpus) {
1e881b75 4084
2ea5fb7e 4085 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
1e881b75
AD
4086
4087 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4088 qemu_devicedel($vmid, "cpu$i");
4089 my $retry = 0;
4090 my $currentrunningvcpus = undef;
4091 while (1) {
65af8c31 4092 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
1e881b75 4093 last if scalar(@{$currentrunningvcpus}) == $i-1;
961af8a3 4094 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
1e881b75
AD
4095 $retry++;
4096 sleep 1;
4097 }
4098 #update conf after each succesfull cpu unplug
4099 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4100 PVE::QemuConfig->write_config($vmid, $conf);
4101 }
4102 } else {
961af8a3 4103 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
1e881b75
AD
4104 }
4105
4106 return;
4107 }
838776ab 4108
65af8c31 4109 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
961af8a3 4110 die "vcpus in running vm does not match its configuration\n"
8edc9c08 4111 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
838776ab 4112
2ea5fb7e 4113 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
eba3e64d
AD
4114
4115 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4116 my $cpustr = print_cpu_device($conf, $i);
4117 qemu_deviceadd($vmid, $cpustr);
4118
4119 my $retry = 0;
4120 my $currentrunningvcpus = undef;
4121 while (1) {
65af8c31 4122 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
eba3e64d 4123 last if scalar(@{$currentrunningvcpus}) == $i;
961af8a3 4124 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
eba3e64d
AD
4125 sleep 1;
4126 $retry++;
4127 }
4128 #update conf after each succesfull cpu hotplug
4129 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4130 PVE::QemuConfig->write_config($vmid, $conf);
4131 }
4132 } else {
4133
4134 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
0a13e08e 4135 mon_cmd($vmid, "cpu-add", id => int($i));
eba3e64d 4136 }
838776ab
AD
4137 }
4138}
4139
affd2f88 4140sub qemu_block_set_io_throttle {
277ca170
WB
4141 my ($vmid, $deviceid,
4142 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
9196a8ec
WB
4143 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4144 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4145 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
affd2f88 4146
f3f323a3
AD
4147 return if !check_running($vmid) ;
4148
0a13e08e 4149 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
277ca170
WB
4150 bps => int($bps),
4151 bps_rd => int($bps_rd),
4152 bps_wr => int($bps_wr),
4153 iops => int($iops),
4154 iops_rd => int($iops_rd),
4155 iops_wr => int($iops_wr),
4156 bps_max => int($bps_max),
4157 bps_rd_max => int($bps_rd_max),
4158 bps_wr_max => int($bps_wr_max),
4159 iops_max => int($iops_max),
4160 iops_rd_max => int($iops_rd_max),
9196a8ec
WB
4161 iops_wr_max => int($iops_wr_max),
4162 bps_max_length => int($bps_max_length),
4163 bps_rd_max_length => int($bps_rd_max_length),
4164 bps_wr_max_length => int($bps_wr_max_length),
4165 iops_max_length => int($iops_max_length),
4166 iops_rd_max_length => int($iops_rd_max_length),
4167 iops_wr_max_length => int($iops_wr_max_length),
277ca170 4168 );
f3f323a3 4169
affd2f88
AD
4170}
4171
f5eb281a 4172# old code, only used to shutdown old VM after update
dab36e1e
DM
4173sub __read_avail {
4174 my ($fh, $timeout) = @_;
4175
4176 my $sel = new IO::Select;
4177 $sel->add($fh);
4178
4179 my $res = '';
4180 my $buf;
4181
4182 my @ready;
4183 while (scalar (@ready = $sel->can_read($timeout))) {
4184 my $count;
4185 if ($count = $fh->sysread($buf, 8192)) {
4186 if ($buf =~ /^(.*)\(qemu\) $/s) {
4187 $res .= $1;
4188 last;
4189 } else {
4190 $res .= $buf;
4191 }
4192 } else {
4193 if (!defined($count)) {
4194 die "$!\n";
4195 }
4196 last;
4197 }
4198 }
4199
4200 die "monitor read timeout\n" if !scalar(@ready);
f5eb281a 4201
dab36e1e
DM
4202 return $res;
4203}
4204
c1175c92
AD
4205sub qemu_block_resize {
4206 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4207
ed221350 4208 my $running = check_running($vmid);
c1175c92 4209
7246e8f9 4210 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
c1175c92
AD
4211
4212 return if !$running;
4213
375db731
FE
4214 my $padding = (1024 - $size % 1024) % 1024;
4215 $size = $size + $padding;
4216
0a13e08e 4217 mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
c1175c92
AD
4218
4219}
4220
1ab0057c
AD
4221sub qemu_volume_snapshot {
4222 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4223
ed221350 4224 my $running = check_running($vmid);
1ab0057c 4225
e5eaa028 4226 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
0a13e08e 4227 mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
e5eaa028
WL
4228 } else {
4229 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4230 }
1ab0057c
AD
4231}
4232
fc46aff9
AD
4233sub qemu_volume_snapshot_delete {
4234 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4235
ed221350 4236 my $running = check_running($vmid);
fc46aff9 4237
a2f1554b
AD
4238 if($running) {
4239
4240 $running = undef;
4241 my $conf = PVE::QemuConfig->load_config($vmid);
4242 foreach_drive($conf, sub {
4243 my ($ds, $drive) = @_;
4244 $running = 1 if $drive->{file} eq $volid;
4245 });
4246 }
4247
1ef7592f 4248 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
0a13e08e 4249 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
1ef7592f
AD
4250 } else {
4251 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4252 }
fc46aff9
AD
4253}
4254
264e519f
DM
4255sub set_migration_caps {
4256 my ($vmid) = @_;
a89fded1 4257
8b8345f3 4258 my $cap_ref = [];
a89fded1
AD
4259
4260 my $enabled_cap = {
8b8345f3 4261 "auto-converge" => 1,
0b0a47e8 4262 "xbzrle" => 1,
8b8345f3
DM
4263 "x-rdma-pin-all" => 0,
4264 "zero-blocks" => 0,
b62532e4 4265 "compress" => 0
a89fded1
AD
4266 };
4267
0a13e08e 4268 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
a89fded1 4269
8b8345f3 4270 for my $supported_capability (@$supported_capabilities) {
b463a3ce
SP
4271 push @$cap_ref, {
4272 capability => $supported_capability->{capability},
22430fa2
DM
4273 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4274 };
a89fded1
AD
4275 }
4276
0a13e08e 4277 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
8b8345f3 4278}
a89fded1 4279
81d95ae1 4280my $fast_plug_option = {
7498eb64 4281 'lock' => 1,
81d95ae1 4282 'name' => 1,
a1b7d579 4283 'onboot' => 1,
81d95ae1
DM
4284 'shares' => 1,
4285 'startup' => 1,
b0ec896e 4286 'description' => 1,
ec647db4 4287 'protection' => 1,
8cad5e9b 4288 'vmstatestorage' => 1,
9e784b11 4289 'hookscript' => 1,
b8e7068a 4290 'tags' => 1,
81d95ae1
DM
4291};
4292
3a11fadb
DM
4293# hotplug changes in [PENDING]
4294# $selection hash can be used to only apply specified options, for
4295# example: { cores => 1 } (only apply changed 'cores')
4296# $errors ref is used to return error messages
c427973b 4297sub vmconfig_hotplug_pending {
3a11fadb 4298 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
c427973b 4299
8e90138a 4300 my $defaults = load_defaults();
045749f2
TL
4301 my $arch = get_vm_arch($conf);
4302 my $machine_type = get_vm_machine($conf, undef, $arch);
c427973b
DM
4303
4304 # commit values which do not have any impact on running VM first
3a11fadb
DM
4305 # Note: those option cannot raise errors, we we do not care about
4306 # $selection and always apply them.
4307
4308 my $add_error = sub {
4309 my ($opt, $msg) = @_;
4310 $errors->{$opt} = "hotplug problem - $msg";
4311 };
c427973b
DM
4312
4313 my $changes = 0;
4314 foreach my $opt (keys %{$conf->{pending}}) { # add/change
81d95ae1 4315 if ($fast_plug_option->{$opt}) {
c427973b
DM
4316 $conf->{$opt} = $conf->{pending}->{$opt};
4317 delete $conf->{pending}->{$opt};
4318 $changes = 1;
4319 }
4320 }
4321
4322 if ($changes) {
ffda963f 4323 PVE::QemuConfig->write_config($vmid, $conf);
c427973b
DM
4324 }
4325
b3c2bdd1 4326 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
c427973b 4327
98bc3aeb 4328 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4329 foreach my $opt (sort keys %$pending_delete_hash) {
3a11fadb 4330 next if $selection && !$selection->{$opt};
d321c4a9 4331 my $force = $pending_delete_hash->{$opt}->{force};
3a11fadb 4332 eval {
51a6f637
AD
4333 if ($opt eq 'hotplug') {
4334 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4335 } elsif ($opt eq 'tablet') {
b3c2bdd1 4336 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4337 if ($defaults->{tablet}) {
d559309f
WB
4338 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4339 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4340 if $arch eq 'aarch64';
3a11fadb 4341 } else {
d559309f
WB
4342 vm_deviceunplug($vmid, $conf, 'tablet');
4343 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4344 }
4eb68604 4345 } elsif ($opt =~ m/^usb\d+/) {
f745762b
DC
4346 die "skip\n";
4347 # since we cannot reliably hot unplug usb devices
4348 # we are disabling it
4eb68604
DC
4349 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4350 vm_deviceunplug($vmid, $conf, $opt);
8edc9c08 4351 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4352 die "skip\n" if !$hotplug_features->{cpu};
8edc9c08 4353 qemu_cpu_hotplug($vmid, $conf, undef);
9c2f7069 4354 } elsif ($opt eq 'balloon') {
81d95ae1 4355 # enable balloon device is not hotpluggable
75b51053
DC
4356 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4357 # here we reset the ballooning value to memory
4358 my $balloon = $conf->{memory} || $defaults->{memory};
0a13e08e 4359 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
81d95ae1
DM
4360 } elsif ($fast_plug_option->{$opt}) {
4361 # do nothing
3eec5767 4362 } elsif ($opt =~ m/^net(\d+)$/) {
b3c2bdd1 4363 die "skip\n" if !$hotplug_features->{network};
3eec5767 4364 vm_deviceunplug($vmid, $conf, $opt);
74479ee9 4365 } elsif (is_valid_drivename($opt)) {
b3c2bdd1 4366 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
19120f99 4367 vm_deviceunplug($vmid, $conf, $opt);
3dc38fbb 4368 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4d3f29ed
AD
4369 } elsif ($opt =~ m/^memory$/) {
4370 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4371 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
c8effec3
AD
4372 } elsif ($opt eq 'cpuunits') {
4373 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
58be00f1
AD
4374 } elsif ($opt eq 'cpulimit') {
4375 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
3d7389fe 4376 } else {
e56beeda 4377 die "skip\n";
3d7389fe 4378 }
3a11fadb
DM
4379 };
4380 if (my $err = $@) {
e56beeda
DM
4381 &$add_error($opt, $err) if $err ne "skip\n";
4382 } else {
3a11fadb 4383 delete $conf->{$opt};
98bc3aeb 4384 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
3d7389fe 4385 }
3d7389fe
DM
4386 }
4387
e5a66e48 4388 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
9ed7a77c 4389 $apply_pending_cloudinit = sub {
e5a66e48
WB
4390 return if $apply_pending_cloudinit_done; # once is enough
4391 $apply_pending_cloudinit_done = 1; # once is enough
4392
9ed7a77c 4393 my ($key, $value) = @_;
9ed7a77c
WB
4394
4395 my @cloudinit_opts = keys %$confdesc_cloudinit;
4396 foreach my $opt (keys %{$conf->{pending}}) {
4397 next if !grep { $_ eq $opt } @cloudinit_opts;
4398 $conf->{$opt} = delete $conf->{pending}->{$opt};
4399 }
4400
4401 my $new_conf = { %$conf };
4402 $new_conf->{$key} = $value;
4403 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4404 };
4405
3d7389fe 4406 foreach my $opt (keys %{$conf->{pending}}) {
3a11fadb 4407 next if $selection && !$selection->{$opt};
3d7389fe 4408 my $value = $conf->{pending}->{$opt};
3a11fadb 4409 eval {
51a6f637
AD
4410 if ($opt eq 'hotplug') {
4411 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4412 } elsif ($opt eq 'tablet') {
b3c2bdd1 4413 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4414 if ($value == 1) {
d559309f
WB
4415 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4416 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4417 if $arch eq 'aarch64';
3a11fadb 4418 } elsif ($value == 0) {
d559309f
WB
4419 vm_deviceunplug($vmid, $conf, 'tablet');
4420 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4421 }
4eb68604 4422 } elsif ($opt =~ m/^usb\d+$/) {
f745762b
DC
4423 die "skip\n";
4424 # since we cannot reliably hot unplug usb devices
4425 # we are disabling it
4eb68604
DC
4426 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4427 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4428 die "skip\n" if !$d;
d559309f 4429 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
8edc9c08 4430 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4431 die "skip\n" if !$hotplug_features->{cpu};
3a11fadb
DM
4432 qemu_cpu_hotplug($vmid, $conf, $value);
4433 } elsif ($opt eq 'balloon') {
81d95ae1 4434 # enable/disable balloning device is not hotpluggable
8fe689e7 4435 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
a1b7d579 4436 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
81d95ae1
DM
4437 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4438
3a11fadb 4439 # allow manual ballooning if shares is set to zero
4cc1efa6 4440 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
9c2f7069 4441 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
0a13e08e 4442 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
9c2f7069 4443 }
a1b7d579 4444 } elsif ($opt =~ m/^net(\d+)$/) {
3eec5767 4445 # some changes can be done without hotplug
a1b7d579 4446 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
d559309f 4447 $vmid, $opt, $value, $arch, $machine_type);
74479ee9 4448 } elsif (is_valid_drivename($opt)) {
7a4bdb36 4449 die "skip\n" if $opt eq 'efidisk0';
a05cff86 4450 # some changes can be done without hotplug
9ed7a77c
WB
4451 my $drive = parse_drive($opt, $value);
4452 if (drive_is_cloudinit($drive)) {
4453 &$apply_pending_cloudinit($opt, $value);
4454 }
b3c2bdd1 4455 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
9e7bce2c 4456 $vmid, $opt, $value, $arch, $machine_type);
4d3f29ed
AD
4457 } elsif ($opt =~ m/^memory$/) { #dimms
4458 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4459 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
c8effec3
AD
4460 } elsif ($opt eq 'cpuunits') {
4461 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
58be00f1 4462 } elsif ($opt eq 'cpulimit') {
c6f773b8 4463 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
58be00f1 4464 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
3a11fadb 4465 } else {
e56beeda 4466 die "skip\n"; # skip non-hot-pluggable options
3d7389fe 4467 }
3a11fadb
DM
4468 };
4469 if (my $err = $@) {
e56beeda
DM
4470 &$add_error($opt, $err) if $err ne "skip\n";
4471 } else {
3a11fadb
DM
4472 $conf->{$opt} = $value;
4473 delete $conf->{pending}->{$opt};
3d7389fe 4474 }
3d7389fe 4475 }
4df15a03
OB
4476
4477 PVE::QemuConfig->write_config($vmid, $conf);
c427973b 4478}
055d554d 4479
3dc38fbb
WB
4480sub try_deallocate_drive {
4481 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4482
4483 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4484 my $volid = $drive->{file};
4485 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4486 my $sid = PVE::Storage::parse_volume_id($volid);
4487 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
cee01bcb
WB
4488
4489 # check if the disk is really unused
cee01bcb 4490 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
e0fd2b2f 4491 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
cee01bcb 4492 PVE::Storage::vdisk_free($storecfg, $volid);
3dc38fbb 4493 return 1;
40b977f3
WL
4494 } else {
4495 # If vm is not owner of this disk remove from config
4496 return 1;
3dc38fbb
WB
4497 }
4498 }
4499
4500 return undef;
4501}
4502
4503sub vmconfig_delete_or_detach_drive {
4504 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4505
4506 my $drive = parse_drive($opt, $conf->{$opt});
4507
4508 my $rpcenv = PVE::RPCEnvironment::get();
4509 my $authuser = $rpcenv->get_user();
4510
4511 if ($force) {
4512 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
4513 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4514 } else {
4515 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4516 }
4517}
4518
98bc3aeb
OB
4519
4520
055d554d 4521sub vmconfig_apply_pending {
eb5e482d
OB
4522 my ($vmid, $conf, $storecfg, $errors) = @_;
4523
4524 my $add_apply_error = sub {
4525 my ($opt, $msg) = @_;
4526 my $err_msg = "unable to apply pending change $opt : $msg";
4527 $errors->{$opt} = $err_msg;
4528 warn $err_msg;
4529 };
c427973b
DM
4530
4531 # cold plug
055d554d 4532
98bc3aeb 4533 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4534 foreach my $opt (sort keys %$pending_delete_hash) {
fb4d1ba2 4535 my $force = $pending_delete_hash->{$opt}->{force};
eb5e482d 4536 eval {
3d48b95a
OB
4537 if ($opt =~ m/^unused/) {
4538 die "internal error";
4539 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 4540 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
eb5e482d
OB
4541 }
4542 };
4543 if (my $err = $@) {
4544 $add_apply_error->($opt, $err);
055d554d 4545 } else {
98bc3aeb 4546 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
055d554d 4547 delete $conf->{$opt};
055d554d
DM
4548 }
4549 }
4550
3d48b95a 4551 PVE::QemuConfig->cleanup_pending($conf);
055d554d
DM
4552
4553 foreach my $opt (keys %{$conf->{pending}}) { # add/change
3d48b95a 4554 next if $opt eq 'delete'; # just to be sure
eb5e482d 4555 eval {
3d48b95a 4556 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 4557 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
eb5e482d
OB
4558 }
4559 };
4560 if (my $err = $@) {
4561 $add_apply_error->($opt, $err);
055d554d 4562 } else {
eb5e482d 4563 $conf->{$opt} = delete $conf->{pending}->{$opt};
055d554d 4564 }
055d554d 4565 }
3d48b95a
OB
4566
4567 # write all changes at once to avoid unnecessary i/o
4568 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
4569}
4570
3eec5767 4571sub vmconfig_update_net {
d559309f 4572 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
3eec5767
DM
4573
4574 my $newnet = parse_net($value);
4575
4576 if ($conf->{$opt}) {
4577 my $oldnet = parse_net($conf->{$opt});
4578
0f1af9e7
OB
4579 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4580 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4581 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
3eec5767
DM
4582 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4583
4584 # for non online change, we try to hot-unplug
7196b757 4585 die "skip\n" if !$hotplug;
3eec5767
DM
4586 vm_deviceunplug($vmid, $conf, $opt);
4587 } else {
4588
4589 die "internal error" if $opt !~ m/net(\d+)/;
4590 my $iface = "tap${vmid}i$1";
a1b7d579 4591
0f1af9e7
OB
4592 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4593 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4594 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4595 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
3eec5767 4596 PVE::Network::tap_unplug($iface);
28e129cc
AD
4597
4598 if ($have_sdn) {
4599 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4600 } else {
4601 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4602 }
0f1af9e7 4603 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4f4fbeb0
WB
4604 # Rate can be applied on its own but any change above needs to
4605 # include the rate in tap_plug since OVS resets everything.
4606 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
3eec5767 4607 }
38c590d9 4608
0f1af9e7 4609 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
25088687
DM
4610 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4611 }
4612
38c590d9 4613 return 1;
3eec5767
DM
4614 }
4615 }
a1b7d579 4616
7196b757 4617 if ($hotplug) {
d559309f 4618 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
38c590d9
DM
4619 } else {
4620 die "skip\n";
4621 }
3eec5767
DM
4622}
4623
a05cff86 4624sub vmconfig_update_disk {
9e7bce2c 4625 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
a05cff86
DM
4626
4627 my $drive = parse_drive($opt, $value);
4628
4629 if ($conf->{$opt}) {
4630
4631 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4632
4633 my $media = $drive->{media} || 'disk';
4634 my $oldmedia = $old_drive->{media} || 'disk';
4635 die "unable to change media type\n" if $media ne $oldmedia;
4636
4637 if (!drive_is_cdrom($old_drive)) {
4638
a1b7d579 4639 if ($drive->{file} ne $old_drive->{file}) {
a05cff86 4640
7196b757 4641 die "skip\n" if !$hotplug;
a05cff86
DM
4642
4643 # unplug and register as unused
4644 vm_deviceunplug($vmid, $conf, $opt);
4645 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
a1b7d579 4646
a05cff86
DM
4647 } else {
4648 # update existing disk
4649
4650 # skip non hotpluggable value
0f1af9e7
OB
4651 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4652 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4653 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4654 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
4655 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
a05cff86
DM
4656 die "skip\n";
4657 }
4658
4659 # apply throttle
0f1af9e7
OB
4660 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4661 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4662 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4663 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4664 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4665 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4666 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4667 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4668 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4669 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4670 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4671 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4672 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4673 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4674 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4675 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4676 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4677 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
a1b7d579 4678
a05cff86
DM
4679 qemu_block_set_io_throttle($vmid,"drive-$opt",
4680 ($drive->{mbps} || 0)*1024*1024,
4681 ($drive->{mbps_rd} || 0)*1024*1024,
4682 ($drive->{mbps_wr} || 0)*1024*1024,
4683 $drive->{iops} || 0,
4684 $drive->{iops_rd} || 0,
4685 $drive->{iops_wr} || 0,
4686 ($drive->{mbps_max} || 0)*1024*1024,
4687 ($drive->{mbps_rd_max} || 0)*1024*1024,
4688 ($drive->{mbps_wr_max} || 0)*1024*1024,
4689 $drive->{iops_max} || 0,
4690 $drive->{iops_rd_max} || 0,
9196a8ec
WB
4691 $drive->{iops_wr_max} || 0,
4692 $drive->{bps_max_length} || 1,
4693 $drive->{bps_rd_max_length} || 1,
4694 $drive->{bps_wr_max_length} || 1,
4695 $drive->{iops_max_length} || 1,
4696 $drive->{iops_rd_max_length} || 1,
4697 $drive->{iops_wr_max_length} || 1);
a05cff86
DM
4698
4699 }
a1b7d579 4700
a05cff86
DM
4701 return 1;
4702 }
4de1bb25
DM
4703
4704 } else { # cdrom
a1b7d579 4705
4de1bb25 4706 if ($drive->{file} eq 'none') {
922869f2 4707 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
2d9ddec5
WB
4708 if (drive_is_cloudinit($old_drive)) {
4709 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4710 }
4de1bb25
DM
4711 } else {
4712 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
ce9fce79
SR
4713
4714 # force eject if locked
922869f2 4715 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
ce9fce79
SR
4716
4717 if ($path) {
4718 mon_cmd($vmid, "blockdev-change-medium",
922869f2 4719 id => "$opt", filename => "$path");
ce9fce79 4720 }
4de1bb25 4721 }
a1b7d579 4722
34758d66 4723 return 1;
a05cff86
DM
4724 }
4725 }
4726 }
4727
a1b7d579 4728 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4de1bb25 4729 # hotplug new disks
f7b4356f 4730 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
d559309f 4731 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
a05cff86
DM
4732}
4733
13cfe3b7 4734# called in locked context by incoming migration
ba5396b5
FG
4735sub vm_migrate_get_nbd_disks {
4736 my ($storecfg, $conf, $replicated_volumes) = @_;
13cfe3b7
FG
4737
4738 my $local_volumes = {};
4739 foreach_drive($conf, sub {
4740 my ($ds, $drive) = @_;
4741
4742 return if drive_is_cdrom($drive);
4743
4744 my $volid = $drive->{file};
4745
4746 return if !$volid;
4747
4748 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4749
4750 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4751 return if $scfg->{shared};
ba5396b5
FG
4752
4753 # replicated disks re-use existing state via bitmap
4754 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
4755 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
13cfe3b7 4756 });
ba5396b5
FG
4757 return $local_volumes;
4758}
4759
4760# called in locked context by incoming migration
4761sub vm_migrate_alloc_nbd_disks {
4762 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
13cfe3b7
FG
4763
4764 my $format = undef;
4765
4766 my $nbd = {};
ba5396b5
FG
4767 foreach my $opt (sort keys %$source_volumes) {
4768 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
4769
4770 if ($use_existing) {
4771 $nbd->{$opt}->{drivestr} = print_drive($drive);
4772 $nbd->{$opt}->{volid} = $volid;
4773 $nbd->{$opt}->{replicated} = 1;
13cfe3b7
FG
4774 next;
4775 }
13cfe3b7
FG
4776
4777 # If a remote storage is specified and the format of the original
4778 # volume is not available there, fall back to the default format.
4779 # Otherwise use the same format as the original.
bf8fc5a3
FG
4780 if (!$storagemap->{identity}) {
4781 $storeid = map_storage($storagemap, $storeid);
13cfe3b7
FG
4782 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4783 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4784 my $fileFormat = qemu_img_format($scfg, $volname);
4785 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
4786 } else {
4787 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4788 $format = qemu_img_format($scfg, $volname);
4789 }
4790
4791 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4792 my $newdrive = $drive;
4793 $newdrive->{format} = $format;
4794 $newdrive->{file} = $newvolid;
4795 my $drivestr = print_drive($newdrive);
ba5396b5
FG
4796 $nbd->{$opt}->{drivestr} = $drivestr;
4797 $nbd->{$opt}->{volid} = $newvolid;
13cfe3b7
FG
4798 }
4799
4800 return $nbd;
4801}
4802
4803# see vm_start_nolock for parameters, additionally:
4804# migrate_opts:
bf8fc5a3 4805# storagemap = parsed storage map for allocating NBD disks
3898a563
FG
4806sub vm_start {
4807 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
4808
4809 PVE::QemuConfig->lock_config($vmid, sub {
4810 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
4811
4812 die "you can't start a vm if it's a template\n" if PVE::QemuConfig->is_template($conf);
4813
4814 $params->{resume} = PVE::QemuConfig->has_lock($conf, 'suspended');
4815
4816 PVE::QemuConfig->check_lock($conf)
4817 if !($params->{skiplock} || $params->{resume});
4818
4819 die "VM $vmid already running\n" if check_running($vmid, undef, $migrate_opts->{migratedfrom});
4820
ba5396b5
FG
4821 if (my $storagemap = $migrate_opts->{storagemap}) {
4822 my $replicated = $migrate_opts->{replicated_volumes};
4823 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
4824 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
4825
4826 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
4827 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
4828 }
4829 }
13cfe3b7 4830
3898a563
FG
4831 vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
4832 });
4833}
4834
4835
0c498cca
FG
4836# params:
4837# statefile => 'tcp', 'unix' for migration or path/volid for RAM state
4838# skiplock => 0/1, skip checking for config lock
4839# forcemachine => to force Qemu machine (rollback/migration)
4840# timeout => in seconds
4841# paused => start VM in paused state (backup)
3898a563 4842# resume => resume from hibernation
0c498cca 4843# migrate_opts:
ba5396b5 4844# nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
0c498cca
FG
4845# migratedfrom => source node
4846# spice_ticket => used for spice migration, passed via tunnel/stdin
4847# network => CIDR of migration network
4848# type => secure/insecure - tunnel over encrypted connection or plain-text
0c498cca
FG
4849# nbd_proto_version => int, 0 for TCP, 1 for UNIX
4850# replicated_volumes = which volids should be re-used with bitmaps for nbd migration
3898a563
FG
4851sub vm_start_nolock {
4852 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
1e3baf05 4853
3898a563
FG
4854 my $statefile = $params->{statefile};
4855 my $resume = $params->{resume};
3dcb98d5 4856
3898a563
FG
4857 my $migratedfrom = $migrate_opts->{migratedfrom};
4858 my $migration_type = $migrate_opts->{type};
7ceade4c 4859
3898a563
FG
4860 # clean up leftover reboot request files
4861 eval { clear_reboot_request($vmid); };
4862 warn $@ if $@;
1e3baf05 4863
3898a563
FG
4864 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4865 vmconfig_apply_pending($vmid, $conf, $storecfg);
4866 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4867 }
64457ed4 4868
3898a563 4869 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
055d554d 4870
3898a563 4871 my $defaults = load_defaults();
0c9a7596 4872
3898a563
FG
4873 # set environment variable useful inside network script
4874 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
6c47d546 4875
3898a563 4876 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
9e784b11 4877
3898a563
FG
4878 my $forcemachine = $params->{forcemachine};
4879 if ($resume) {
4880 # enforce machine type on suspended vm to ensure HW compatibility
4881 $forcemachine = $conf->{runningmachine};
4882 print "Resuming suspended VM\n";
4883 }
7ceade4c 4884
3898a563 4885 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
6c47d546 4886
3898a563
FG
4887 my $migration_ip;
4888 my $get_migration_ip = sub {
4889 my ($nodename) = @_;
b24e1ac2 4890
3898a563 4891 return $migration_ip if defined($migration_ip);
b24e1ac2 4892
3898a563 4893 my $cidr = $migrate_opts->{network};
0c498cca 4894
3898a563
FG
4895 if (!defined($cidr)) {
4896 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
4897 $cidr = $dc_conf->{migration}->{network};
4898 }
b24e1ac2 4899
3898a563
FG
4900 if (defined($cidr)) {
4901 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
b24e1ac2 4902
3898a563
FG
4903 die "could not get IP: no address configured on local " .
4904 "node for network '$cidr'\n" if scalar(@$ips) == 0;
b24e1ac2 4905
3898a563
FG
4906 die "could not get IP: multiple addresses configured on local " .
4907 "node for network '$cidr'\n" if scalar(@$ips) > 1;
b24e1ac2 4908
3898a563
FG
4909 $migration_ip = @$ips[0];
4910 }
b24e1ac2 4911
3898a563
FG
4912 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
4913 if !defined($migration_ip);
b24e1ac2 4914
3898a563
FG
4915 return $migration_ip;
4916 };
b24e1ac2 4917
3898a563
FG
4918 my $migrate_uri;
4919 if ($statefile) {
4920 if ($statefile eq 'tcp') {
4921 my $localip = "localhost";
4922 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
4923 my $nodename = nodename();
2de2d6f7 4924
3898a563
FG
4925 if (!defined($migration_type)) {
4926 if (defined($datacenterconf->{migration}->{type})) {
4927 $migration_type = $datacenterconf->{migration}->{type};
4928 } else {
4929 $migration_type = 'secure';
b7a5a225 4930 }
3898a563 4931 }
b7a5a225 4932
3898a563
FG
4933 if ($migration_type eq 'insecure') {
4934 $localip = $get_migration_ip->($nodename);
4935 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4936 }
2de2d6f7 4937
3898a563
FG
4938 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4939 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4940 $migrate_uri = "tcp:${localip}:${migrate_port}";
4941 push @$cmd, '-incoming', $migrate_uri;
4942 push @$cmd, '-S';
1c9d54bf 4943
3898a563
FG
4944 } elsif ($statefile eq 'unix') {
4945 # should be default for secure migrations as a ssh TCP forward
4946 # tunnel is not deterministic reliable ready and fails regurarly
4947 # to set up in time, so use UNIX socket forwards
4948 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4949 unlink $socket_addr;
54323eed 4950
3898a563 4951 $migrate_uri = "unix:$socket_addr";
1c9d54bf 4952
3898a563
FG
4953 push @$cmd, '-incoming', $migrate_uri;
4954 push @$cmd, '-S';
1c9d54bf 4955
3898a563
FG
4956 } elsif (-e $statefile) {
4957 push @$cmd, '-loadstate', $statefile;
4958 } else {
4959 my $statepath = PVE::Storage::path($storecfg, $statefile);
4960 push @$vollist, $statefile;
4961 push @$cmd, '-loadstate', $statepath;
4962 }
4963 } elsif ($params->{paused}) {
4964 push @$cmd, '-S';
4965 }
4966
4967 # host pci devices
4968 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4969 my $d = parse_hostpci($conf->{"hostpci$i"});
4970 next if !$d;
4971 my $pcidevices = $d->{pciid};
4972 foreach my $pcidevice (@$pcidevices) {
4973 my $pciid = $pcidevice->{id};
4974
4975 my $info = PVE::SysFSTools::pci_device_info("$pciid");
4976 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
4977 die "no pci device info for device '$pciid'\n" if !$info;
4978
4979 if ($d->{mdev}) {
4980 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
4981 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5c1d42b7 4982 } else {
3898a563
FG
4983 die "can't unbind/bind pci group to vfio '$pciid'\n"
4984 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
4985 die "can't reset pci device '$pciid'\n"
4986 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
1e3baf05 4987 }
3898a563
FG
4988 }
4989 }
1e3baf05 4990
3898a563 4991 PVE::Storage::activate_volumes($storecfg, $vollist);
1e3baf05 4992
3898a563
FG
4993 eval {
4994 run_command(['/bin/systemctl', 'stop', "$vmid.scope"],
4995 outfunc => sub {}, errfunc => sub {});
4996 };
4997 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
4998 # timeout should be more than enough here...
4999 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
5000
5001 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5002 : $defaults->{cpuunits};
5003
5004 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
5005 my %run_params = (
5006 timeout => $statefile ? undef : $start_timeout,
5007 umask => 0077,
5008 noerr => 1,
5009 );
1e3baf05 5010
3898a563
FG
5011 # when migrating, prefix QEMU output so other side can pick up any
5012 # errors that might occur and show the user
5013 if ($migratedfrom) {
5014 $run_params{quiet} = 1;
5015 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
5016 }
8bf30c2a 5017
3898a563
FG
5018 my %properties = (
5019 Slice => 'qemu.slice',
5020 KillMode => 'none',
5021 CPUShares => $cpuunits
5022 );
7023f3ea 5023
3898a563
FG
5024 if (my $cpulimit = $conf->{cpulimit}) {
5025 $properties{CPUQuota} = int($cpulimit * 100);
5026 }
5027 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
7023f3ea 5028
3898a563
FG
5029 my $run_qemu = sub {
5030 PVE::Tools::run_fork sub {
5031 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
6e0216d8 5032
3898a563
FG
5033 my $exitcode = run_command($cmd, %run_params);
5034 die "QEMU exited with code $exitcode\n" if $exitcode;
503308ed 5035 };
3898a563 5036 };
503308ed 5037
3898a563 5038 if ($conf->{hugepages}) {
7023f3ea 5039
3898a563
FG
5040 my $code = sub {
5041 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5042 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
7023f3ea 5043
3898a563
FG
5044 PVE::QemuServer::Memory::hugepages_mount();
5045 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
7023f3ea 5046
503308ed 5047 eval { $run_qemu->() };
3898a563
FG
5048 if (my $err = $@) {
5049 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5050 die $err;
5051 }
77cde36b 5052
3898a563
FG
5053 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5054 };
5055 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
1e3baf05 5056
3898a563
FG
5057 } else {
5058 eval { $run_qemu->() };
5059 }
afdb31d5 5060
3898a563
FG
5061 if (my $err = $@) {
5062 # deactivate volumes if start fails
5063 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5064 die "start failed: $err";
5065 }
62de2cbd 5066
3898a563 5067 print "migration listens on $migrate_uri\n" if $migrate_uri;
eb8cddb5 5068
3898a563
FG
5069 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5070 eval { mon_cmd($vmid, "cont"); };
5071 warn $@ if $@;
5072 }
2189246c 5073
3898a563 5074 #start nbd server for storage migration
13cfe3b7 5075 if (my $nbd = $migrate_opts->{nbd}) {
3898a563 5076 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
2189246c 5077
3898a563
FG
5078 my $migrate_storage_uri;
5079 # nbd_protocol_version > 0 for unix socket support
5080 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5081 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5082 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix', data => { path => $socket_path } } );
5083 $migrate_storage_uri = "nbd:unix:$socket_path";
5084 } else {
5085 my $nodename = nodename();
5086 my $localip = $get_migration_ip->($nodename);
5087 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5088 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5089
5090 mon_cmd($vmid, "nbd-server-start", addr => { type => 'inet', data => { host => "${localip}", port => "${storage_migrate_port}" } } );
5091 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5092 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
2189246c
AD
5093 }
5094
13cfe3b7 5095 foreach my $opt (sort keys %$nbd) {
ba5396b5
FG
5096 my $drivestr = $nbd->{$opt}->{drivestr};
5097 my $volid = $nbd->{$opt}->{volid};
3898a563
FG
5098 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5099 print "storage migration listens on $migrate_storage_uri:exportname=drive-$opt volume:$drivestr\n";
ba5396b5
FG
5100 print "re-using replicated volume: $opt - $volid\n"
5101 if $nbd->{$opt}->{replicated};
3898a563
FG
5102 }
5103 }
a89fded1 5104
3898a563
FG
5105 if ($migratedfrom) {
5106 eval {
5107 set_migration_caps($vmid);
5108 };
5109 warn $@ if $@;
5110
5111 if ($spice_port) {
5112 print "spice listens on port $spice_port\n";
5113 if ($migrate_opts->{spice_ticket}) {
5114 mon_cmd($vmid, "set_password", protocol => 'spice', password => $migrate_opts->{spice_ticket});
5115 mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
95a4b4a9 5116 }
3898a563 5117 }
95a4b4a9 5118
3898a563
FG
5119 } else {
5120 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5121 if !$statefile && $conf->{balloon};
25088687 5122
3898a563
FG
5123 foreach my $opt (keys %$conf) {
5124 next if $opt !~ m/^net\d+$/;
5125 my $nicconf = parse_net($conf->{$opt});
5126 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
e18b0b99 5127 }
3898a563 5128 }
a1b7d579 5129
3898a563
FG
5130 mon_cmd($vmid, 'qom-set',
5131 path => "machine/peripheral/balloon0",
5132 property => "guest-stats-polling-interval",
5133 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
eb065317 5134
3898a563
FG
5135 if ($resume) {
5136 print "Resumed VM, removing state\n";
5137 if (my $vmstate = $conf->{vmstate}) {
5138 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5139 PVE::Storage::vdisk_free($storecfg, $vmstate);
7ceade4c 5140 }
3898a563
FG
5141 delete $conf->@{qw(lock vmstate runningmachine)};
5142 PVE::QemuConfig->write_config($vmid, $conf);
5143 }
7ceade4c 5144
3898a563 5145 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
1e3baf05
DM
5146}
5147
1e3baf05 5148sub vm_commandline {
b14477e7 5149 my ($storecfg, $vmid, $snapname) = @_;
1e3baf05 5150
ffda963f 5151 my $conf = PVE::QemuConfig->load_config($vmid);
092868c4 5152 my $forcemachine;
1e3baf05 5153
b14477e7
RV
5154 if ($snapname) {
5155 my $snapshot = $conf->{snapshots}->{$snapname};
87d92707
TL
5156 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5157
092868c4
SR
5158 # check for a 'runningmachine' in snapshot
5159 $forcemachine = $snapshot->{runningmachine} if $snapshot->{runningmachine};
5160
87d92707 5161 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
b14477e7 5162
b14477e7
RV
5163 $conf = $snapshot;
5164 }
5165
1e3baf05
DM
5166 my $defaults = load_defaults();
5167
092868c4 5168 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
1e3baf05 5169
5930c1ff 5170 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5171}
5172
5173sub vm_reset {
5174 my ($vmid, $skiplock) = @_;
5175
ffda963f 5176 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5177
ffda963f 5178 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5179
ffda963f 5180 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5181
0a13e08e 5182 mon_cmd($vmid, "system_reset");
ff1a2432
DM
5183 });
5184}
5185
5186sub get_vm_volumes {
5187 my ($conf) = @_;
1e3baf05 5188
ff1a2432 5189 my $vollist = [];
d5769dc2 5190 foreach_volid($conf, sub {
392f8b5d 5191 my ($volid, $attr) = @_;
ff1a2432 5192
d5769dc2 5193 return if $volid =~ m|^/|;
ff1a2432 5194
d5769dc2
DM
5195 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5196 return if !$sid;
ff1a2432
DM
5197
5198 push @$vollist, $volid;
1e3baf05 5199 });
ff1a2432
DM
5200
5201 return $vollist;
5202}
5203
5204sub vm_stop_cleanup {
70b04821 5205 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5206
745fed70 5207 eval {
ff1a2432 5208
254575e9
DM
5209 if (!$keepActive) {
5210 my $vollist = get_vm_volumes($conf);
5211 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5212 }
a1b7d579 5213
ab6a046f 5214 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5215 unlink "/var/run/qemu-server/${vmid}.$ext";
5216 }
a1b7d579 5217
6dbcb073
DC
5218 if ($conf->{ivshmem}) {
5219 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
4c5a6a24
TL
5220 # just delete it for now, VMs which have this already open do not
5221 # are affected, but new VMs will get a separated one. If this
5222 # becomes an issue we either add some sort of ref-counting or just
5223 # add a "don't delete on stop" flag to the ivshmem format.
6dbcb073
DC
5224 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
5225 }
5226
6ab45bd7
DC
5227 foreach my $key (keys %$conf) {
5228 next if $key !~ m/^hostpci(\d+)$/;
5229 my $hostpciindex = $1;
5230 my $d = parse_hostpci($conf->{$key});
5231 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5232
5233 foreach my $pci (@{$d->{pciid}}) {
2fd24788 5234 my $pciid = $pci->{id};
6ab45bd7
DC
5235 PVE::SysFSTools::pci_cleanup_mdev_device($pciid, $uuid);
5236 }
5237 }
5238
70b04821 5239 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5240 };
5241 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5242}
5243
575d19da
DC
5244# call only in locked context
5245sub _do_vm_stop {
5246 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
9269013a 5247
575d19da
DC
5248 my $pid = check_running($vmid, $nocheck);
5249 return if !$pid;
1e3baf05 5250
575d19da
DC
5251 my $conf;
5252 if (!$nocheck) {
5253 $conf = PVE::QemuConfig->load_config($vmid);
5254 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5255 if (!defined($timeout) && $shutdown && $conf->{startup}) {
5256 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
5257 $timeout = $opts->{down} if $opts->{down};
e6c3b671 5258 }
575d19da
DC
5259 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
5260 }
19672434 5261
575d19da
DC
5262 eval {
5263 if ($shutdown) {
5264 if (defined($conf) && parse_guest_agent($conf)->{enabled}) {
0a13e08e 5265 mon_cmd($vmid, "guest-shutdown", timeout => $timeout);
9269013a 5266 } else {
0a13e08e 5267 mon_cmd($vmid, "system_powerdown");
1e3baf05
DM
5268 }
5269 } else {
0a13e08e 5270 mon_cmd($vmid, "quit");
1e3baf05 5271 }
575d19da
DC
5272 };
5273 my $err = $@;
1e3baf05 5274
575d19da
DC
5275 if (!$err) {
5276 $timeout = 60 if !defined($timeout);
1e3baf05
DM
5277
5278 my $count = 0;
e6c3b671 5279 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5280 $count++;
5281 sleep 1;
5282 }
5283
5284 if ($count >= $timeout) {
575d19da
DC
5285 if ($force) {
5286 warn "VM still running - terminating now with SIGTERM\n";
5287 kill 15, $pid;
5288 } else {
5289 die "VM quit/powerdown failed - got timeout\n";
5290 }
5291 } else {
5292 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5293 return;
1e3baf05 5294 }
575d19da
DC
5295 } else {
5296 if ($force) {
5297 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5298 kill 15, $pid;
5299 } else {
5300 die "VM quit/powerdown failed\n";
5301 }
5302 }
5303
5304 # wait again
5305 $timeout = 10;
5306
5307 my $count = 0;
5308 while (($count < $timeout) && check_running($vmid, $nocheck)) {
5309 $count++;
5310 sleep 1;
5311 }
5312
5313 if ($count >= $timeout) {
5314 warn "VM still running - terminating now with SIGKILL\n";
5315 kill 9, $pid;
5316 sleep 1;
5317 }
1e3baf05 5318
575d19da
DC
5319 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5320}
5321
5322# Note: use $nocheck to skip tests if VM configuration file exists.
5323# We need that when migration VMs to other nodes (files already moved)
5324# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5325sub vm_stop {
5326 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5327
5328 $force = 1 if !defined($force) && !$shutdown;
5329
5330 if ($migratedfrom){
5331 my $pid = check_running($vmid, $nocheck, $migratedfrom);
5332 kill 15, $pid if $pid;
5333 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5334 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
5335 return;
5336 }
5337
5338 PVE::QemuConfig->lock_config($vmid, sub {
5339 _do_vm_stop($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
ff1a2432 5340 });
1e3baf05
DM
5341}
5342
165411f0
DC
5343sub vm_reboot {
5344 my ($vmid, $timeout) = @_;
5345
5346 PVE::QemuConfig->lock_config($vmid, sub {
66026117 5347 eval {
165411f0 5348
66026117
OB
5349 # only reboot if running, as qmeventd starts it again on a stop event
5350 return if !check_running($vmid);
165411f0 5351
66026117 5352 create_reboot_request($vmid);
165411f0 5353
66026117
OB
5354 my $storecfg = PVE::Storage::config();
5355 _do_vm_stop($storecfg, $vmid, undef, undef, $timeout, 1);
165411f0 5356
66026117
OB
5357 };
5358 if (my $err = $@) {
3c1c3fe6 5359 # avoid that the next normal shutdown will be confused for a reboot
66026117
OB
5360 clear_reboot_request($vmid);
5361 die $err;
5362 }
165411f0
DC
5363 });
5364}
5365
75c24bba 5366# note: if using the statestorage parameter, the caller has to check privileges
1e3baf05 5367sub vm_suspend {
48b4cdc2 5368 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
5369
5370 my $conf;
5371 my $path;
5372 my $storecfg;
5373 my $vmstate;
1e3baf05 5374
ffda963f 5375 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5376
159719e5 5377 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5378
159719e5 5379 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 5380 PVE::QemuConfig->check_lock($conf)
159719e5
DC
5381 if !($skiplock || $is_backing_up);
5382
5383 die "cannot suspend to disk during backup\n"
5384 if $is_backing_up && $includestate;
bcb7c9cf 5385
159719e5
DC
5386 if ($includestate) {
5387 $conf->{lock} = 'suspending';
5388 my $date = strftime("%Y-%m-%d", localtime(time()));
5389 $storecfg = PVE::Storage::config();
75c24bba
DC
5390 if (!$statestorage) {
5391 $statestorage = find_vmstate_storage($conf, $storecfg);
5392 # check permissions for the storage
5393 my $rpcenv = PVE::RPCEnvironment::get();
5394 if ($rpcenv->{type} ne 'cli') {
5395 my $authuser = $rpcenv->get_user();
5396 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5397 }
5398 }
5399
5400
48b4cdc2 5401 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
5402 $path = PVE::Storage::path($storecfg, $vmstate);
5403 PVE::QemuConfig->write_config($vmid, $conf);
5404 } else {
0a13e08e 5405 mon_cmd($vmid, "stop");
159719e5 5406 }
1e3baf05 5407 });
159719e5
DC
5408
5409 if ($includestate) {
5410 # save vm state
5411 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
5412
5413 eval {
0a13e08e 5414 mon_cmd($vmid, "savevm-start", statefile => $path);
159719e5 5415 for(;;) {
0a13e08e 5416 my $state = mon_cmd($vmid, "query-savevm");
159719e5
DC
5417 if (!$state->{status}) {
5418 die "savevm not active\n";
5419 } elsif ($state->{status} eq 'active') {
5420 sleep(1);
5421 next;
5422 } elsif ($state->{status} eq 'completed') {
b0a9a385 5423 print "State saved, quitting\n";
159719e5
DC
5424 last;
5425 } elsif ($state->{status} eq 'failed' && $state->{error}) {
5426 die "query-savevm failed with error '$state->{error}'\n"
5427 } else {
5428 die "query-savevm returned status '$state->{status}'\n";
5429 }
5430 }
5431 };
5432 my $err = $@;
5433
5434 PVE::QemuConfig->lock_config($vmid, sub {
5435 $conf = PVE::QemuConfig->load_config($vmid);
5436 if ($err) {
5437 # cleanup, but leave suspending lock, to indicate something went wrong
5438 eval {
0a13e08e 5439 mon_cmd($vmid, "savevm-end");
159719e5
DC
5440 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5441 PVE::Storage::vdisk_free($storecfg, $vmstate);
5442 delete $conf->@{qw(vmstate runningmachine)};
5443 PVE::QemuConfig->write_config($vmid, $conf);
5444 };
5445 warn $@ if $@;
5446 die $err;
5447 }
5448
5449 die "lock changed unexpectedly\n"
5450 if !PVE::QemuConfig->has_lock($conf, 'suspending');
5451
0a13e08e 5452 mon_cmd($vmid, "quit");
159719e5
DC
5453 $conf->{lock} = 'suspended';
5454 PVE::QemuConfig->write_config($vmid, $conf);
5455 });
5456 }
1e3baf05
DM
5457}
5458
5459sub vm_resume {
289e0b85 5460 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 5461
ffda963f 5462 PVE::QemuConfig->lock_config($vmid, sub {
0a13e08e 5463 my $res = mon_cmd($vmid, 'query-status');
c2786bed
DC
5464 my $resume_cmd = 'cont';
5465
5466 if ($res->{status} && $res->{status} eq 'suspended') {
5467 $resume_cmd = 'system_wakeup';
5468 }
5469
289e0b85 5470 if (!$nocheck) {
1e3baf05 5471
ffda963f 5472 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5473
e79706d4
FG
5474 PVE::QemuConfig->check_lock($conf)
5475 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 5476 }
3e24733b 5477
0a13e08e 5478 mon_cmd($vmid, $resume_cmd);
1e3baf05
DM
5479 });
5480}
5481
5fdbe4f0
DM
5482sub vm_sendkey {
5483 my ($vmid, $skiplock, $key) = @_;
1e3baf05 5484
ffda963f 5485 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5486
ffda963f 5487 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 5488
7b7c6d1b 5489 # there is no qmp command, so we use the human monitor command
0a13e08e 5490 my $res = PVE::QemuServer::Monitor::hmp_cmd($vmid, "sendkey $key");
d30820d6 5491 die $res if $res ne '';
1e3baf05
DM
5492 });
5493}
5494
3e16d5fc
DM
5495# vzdump restore implementaion
5496
ed221350 5497sub tar_archive_read_firstfile {
3e16d5fc 5498 my $archive = shift;
afdb31d5 5499
3e16d5fc
DM
5500 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
5501
5502 # try to detect archive type first
387ba257 5503 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 5504 die "unable to open file '$archive'\n";
387ba257 5505 my $firstfile = <$fh>;
3e16d5fc 5506 kill 15, $pid;
387ba257 5507 close $fh;
3e16d5fc
DM
5508
5509 die "ERROR: archive contaions no data\n" if !$firstfile;
5510 chomp $firstfile;
5511
5512 return $firstfile;
5513}
5514
ed221350
DM
5515sub tar_restore_cleanup {
5516 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
5517
5518 print STDERR "starting cleanup\n";
5519
5520 if (my $fd = IO::File->new($statfile, "r")) {
5521 while (defined(my $line = <$fd>)) {
5522 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5523 my $volid = $2;
5524 eval {
5525 if ($volid =~ m|^/|) {
5526 unlink $volid || die 'unlink failed\n';
5527 } else {
ed221350 5528 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 5529 }
afdb31d5 5530 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
5531 };
5532 print STDERR "unable to cleanup '$volid' - $@" if $@;
5533 } else {
5534 print STDERR "unable to parse line in statfile - $line";
afdb31d5 5535 }
3e16d5fc
DM
5536 }
5537 $fd->close();
5538 }
5539}
5540
d1e92cf6 5541sub restore_file_archive {
a0d1b1a2 5542 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 5543
91bd6c90
DM
5544 my $format = $opts->{format};
5545 my $comp;
5546
5547 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5548 $format = 'tar' if !$format;
5549 $comp = 'gzip';
5550 } elsif ($archive =~ m/\.tar$/) {
5551 $format = 'tar' if !$format;
5552 } elsif ($archive =~ m/.tar.lzo$/) {
5553 $format = 'tar' if !$format;
5554 $comp = 'lzop';
5555 } elsif ($archive =~ m/\.vma$/) {
5556 $format = 'vma' if !$format;
5557 } elsif ($archive =~ m/\.vma\.gz$/) {
5558 $format = 'vma' if !$format;
5559 $comp = 'gzip';
5560 } elsif ($archive =~ m/\.vma\.lzo$/) {
5561 $format = 'vma' if !$format;
5562 $comp = 'lzop';
5563 } else {
5564 $format = 'vma' if !$format; # default
5565 }
5566
5567 # try to detect archive format
5568 if ($format eq 'tar') {
5569 return restore_tar_archive($archive, $vmid, $user, $opts);
5570 } else {
5571 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
5572 }
5573}
5574
d1e92cf6
DM
5575# hepler to remove disks that will not be used after restore
5576my $restore_cleanup_oldconf = sub {
5577 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
5578
5579 foreach_drive($oldconf, sub {
5580 my ($ds, $drive) = @_;
5581
5582 return if drive_is_cdrom($drive, 1);
5583
5584 my $volid = $drive->{file};
5585 return if !$volid || $volid =~ m|^/|;
5586
5587 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
5588 return if !$path || !$owner || ($owner != $vmid);
5589
5590 # Note: only delete disk we want to restore
5591 # other volumes will become unused
5592 if ($virtdev_hash->{$ds}) {
5593 eval { PVE::Storage::vdisk_free($storecfg, $volid); };
5594 if (my $err = $@) {
5595 warn $err;
5596 }
5597 }
5598 });
5599
5600 # delete vmstate files, after the restore we have no snapshots anymore
5601 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
5602 my $snap = $oldconf->{snapshots}->{$snapname};
5603 if ($snap->{vmstate}) {
5604 eval { PVE::Storage::vdisk_free($storecfg, $snap->{vmstate}); };
5605 if (my $err = $@) {
5606 warn $err;
5607 }
5608 }
5609 }
5610};
5611
9f3d73bc
DM
5612# Helper to parse vzdump backup device hints
5613#
5614# $rpcenv: Environment, used to ckeck storage permissions
5615# $user: User ID, to check storage permissions
5616# $storecfg: Storage configuration
5617# $fh: the file handle for reading the configuration
5618# $devinfo: should contain device sizes for all backu-up'ed devices
5619# $options: backup options (pool, default storage)
5620#
5621# Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
5622my $parse_backup_hints = sub {
5623 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
d1e92cf6 5624
9f3d73bc 5625 my $virtdev_hash = {};
d1e92cf6 5626
9f3d73bc
DM
5627 while (defined(my $line = <$fh>)) {
5628 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5629 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5630 die "archive does not contain data for drive '$virtdev'\n"
5631 if !$devinfo->{$devname};
5632
5633 if (defined($options->{storage})) {
5634 $storeid = $options->{storage} || 'local';
5635 } elsif (!$storeid) {
5636 $storeid = 'local';
d1e92cf6 5637 }
9f3d73bc
DM
5638 $format = 'raw' if !$format;
5639 $devinfo->{$devname}->{devname} = $devname;
5640 $devinfo->{$devname}->{virtdev} = $virtdev;
5641 $devinfo->{$devname}->{format} = $format;
5642 $devinfo->{$devname}->{storeid} = $storeid;
5643
5644 # check permission on storage
5645 my $pool = $options->{pool}; # todo: do we need that?
5646 if ($user ne 'root@pam') {
5647 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
d1e92cf6 5648 }
d1e92cf6 5649
9f3d73bc
DM
5650 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5651 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
5652 my $virtdev = $1;
5653 my $drive = parse_drive($virtdev, $2);
5654 if (drive_is_cloudinit($drive)) {
5655 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
5656 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5657 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
d1e92cf6 5658
9f3d73bc
DM
5659 $virtdev_hash->{$virtdev} = {
5660 format => $format,
5661 storeid => $options->{storage} // $storeid,
5662 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
5663 is_cloudinit => 1,
5664 };
d1e92cf6 5665 }
9f3d73bc
DM
5666 }
5667 }
d1e92cf6 5668
9f3d73bc
DM
5669 return $virtdev_hash;
5670};
d1e92cf6 5671
9f3d73bc
DM
5672# Helper to allocate and activate all volumes required for a restore
5673#
5674# $storecfg: Storage configuration
5675# $virtdev_hash: as returned by parse_backup_hints()
5676#
5677# Returns: { $virtdev => $volid }
5678my $restore_allocate_devices = sub {
5679 my ($storecfg, $virtdev_hash, $vmid) = @_;
d1e92cf6 5680
9f3d73bc
DM
5681 my $map = {};
5682 foreach my $virtdev (sort keys %$virtdev_hash) {
5683 my $d = $virtdev_hash->{$virtdev};
5684 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
5685 my $storeid = $d->{storeid};
5686 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
d1e92cf6 5687
9f3d73bc
DM
5688 # test if requested format is supported
5689 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5690 my $supported = grep { $_ eq $d->{format} } @$validFormats;
5691 $d->{format} = $defFormat if !$supported;
d1e92cf6 5692
9f3d73bc
DM
5693 my $name;
5694 if ($d->{is_cloudinit}) {
5695 $name = "vm-$vmid-cloudinit";
5696 $name .= ".$d->{format}" if $d->{format} ne 'raw';
d1e92cf6
DM
5697 }
5698
9f3d73bc 5699 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
d1e92cf6 5700
9f3d73bc
DM
5701 print STDERR "new volume ID is '$volid'\n";
5702 $d->{volid} = $volid;
d1e92cf6 5703
9f3d73bc 5704 PVE::Storage::activate_volumes($storecfg, [$volid]);
d1e92cf6 5705
9f3d73bc 5706 $map->{$virtdev} = $volid;
d1e92cf6
DM
5707 }
5708
9f3d73bc
DM
5709 return $map;
5710};
d1e92cf6 5711
9f3d73bc 5712my $restore_update_config_line = sub {
91bd6c90
DM
5713 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5714
5715 return if $line =~ m/^\#qmdump\#/;
5716 return if $line =~ m/^\#vzdump\#/;
5717 return if $line =~ m/^lock:/;
5718 return if $line =~ m/^unused\d+:/;
5719 return if $line =~ m/^parent:/;
5720
b5b99790 5721 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
5722 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5723 # try to convert old 1.X settings
5724 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5725 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
5726 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 5727 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
5728 my $net = {
5729 model => $model,
5730 bridge => "vmbr$ind",
5731 macaddr => $macaddr,
5732 };
5733 my $netstr = print_net($net);
5734
5735 print $outfd "net$cookie->{netcount}: $netstr\n";
5736 $cookie->{netcount}++;
5737 }
5738 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5739 my ($id, $netstr) = ($1, $2);
5740 my $net = parse_net($netstr);
b5b99790 5741 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90
DM
5742 $netstr = print_net($net);
5743 print $outfd "$id: $netstr\n";
6470743f 5744 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
91bd6c90 5745 my $virtdev = $1;
907ea891 5746 my $value = $3;
d9faf790
WB
5747 my $di = parse_drive($virtdev, $value);
5748 if (defined($di->{backup}) && !$di->{backup}) {
91bd6c90 5749 print $outfd "#$line";
c0f7406e 5750 } elsif ($map->{$virtdev}) {
8fd57431 5751 delete $di->{format}; # format can change on restore
91bd6c90 5752 $di->{file} = $map->{$virtdev};
71c58bb7 5753 $value = print_drive($di);
91bd6c90
DM
5754 print $outfd "$virtdev: $value\n";
5755 } else {
5756 print $outfd $line;
5757 }
1a0c2f03 5758 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 5759 my $vmgenid = $1;
6ee499ff 5760 if ($vmgenid ne '0') {
1a0c2f03 5761 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
5762 $vmgenid = generate_uuid();
5763 }
1a0c2f03 5764 print $outfd "vmgenid: $vmgenid\n";
19a5dd55
WL
5765 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5766 my ($uuid, $uuid_str);
5767 UUID::generate($uuid);
5768 UUID::unparse($uuid, $uuid_str);
5769 my $smbios1 = parse_smbios1($2);
5770 $smbios1->{uuid} = $uuid_str;
5771 print $outfd $1.print_smbios1($smbios1)."\n";
91bd6c90
DM
5772 } else {
5773 print $outfd $line;
5774 }
9f3d73bc
DM
5775};
5776
5777my $restore_deactivate_volumes = sub {
5778 my ($storecfg, $devinfo) = @_;
5779
5780 my $vollist = [];
5781 foreach my $devname (keys %$devinfo) {
5782 my $volid = $devinfo->{$devname}->{volid};
5783 push @$vollist, $volid if $volid;
5784 }
5785
5786 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5787};
5788
5789my $restore_destroy_volumes = sub {
5790 my ($storecfg, $devinfo) = @_;
5791
5792 foreach my $devname (keys %$devinfo) {
5793 my $volid = $devinfo->{$devname}->{volid};
5794 next if !$volid;
5795 eval {
5796 if ($volid =~ m|^/|) {
5797 unlink $volid || die 'unlink failed\n';
5798 } else {
5799 PVE::Storage::vdisk_free($storecfg, $volid);
5800 }
5801 print STDERR "temporary volume '$volid' sucessfuly removed\n";
5802 };
5803 print STDERR "unable to cleanup '$volid' - $@" if $@;
5804 }
5805};
91bd6c90
DM
5806
5807sub scan_volids {
5808 my ($cfg, $vmid) = @_;
5809
5810 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid);
5811
5812 my $volid_hash = {};
5813 foreach my $storeid (keys %$info) {
5814 foreach my $item (@{$info->{$storeid}}) {
5815 next if !($item->{volid} && $item->{size});
5996a936 5816 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
5817 $volid_hash->{$item->{volid}} = $item;
5818 }
5819 }
5820
5821 return $volid_hash;
5822}
5823
68b108ee 5824sub update_disk_config {
91bd6c90 5825 my ($vmid, $conf, $volid_hash) = @_;
be190583 5826
91bd6c90 5827 my $changes;
53b81297 5828 my $prefix = "VM $vmid:";
91bd6c90 5829
c449137a
DC
5830 # used and unused disks
5831 my $referenced = {};
91bd6c90 5832
5996a936
DM
5833 # Note: it is allowed to define multiple storages with same path (alias), so
5834 # we need to check both 'volid' and real 'path' (two different volid can point
5835 # to the same path).
5836
c449137a 5837 my $referencedpath = {};
be190583 5838
91bd6c90 5839 # update size info
0c4fef3f 5840 PVE::QemuConfig->foreach_volume($conf, sub {
ca04977c 5841 my ($opt, $drive) = @_;
91bd6c90 5842
ca04977c
FE
5843 my $volid = $drive->{file};
5844 return if !$volid;
91bd6c90 5845
ca04977c
FE
5846 # mark volid as "in-use" for next step
5847 $referenced->{$volid} = 1;
5848 if ($volid_hash->{$volid} &&
5849 (my $path = $volid_hash->{$volid}->{path})) {
5850 $referencedpath->{$path} = 1;
91bd6c90 5851 }
ca04977c
FE
5852
5853 return if drive_is_cdrom($drive);
5854 return if !$volid_hash->{$volid};
5855
5856 my ($updated, $old_size, $new_size) = PVE::QemuServer::Drive::update_disksize($drive, $volid_hash);
5857 if (defined($updated)) {
5858 $changes = 1;
5859 $conf->{$opt} = print_drive($updated);
5860 print "$prefix size of disk '$volid' ($opt) updated from $old_size to $new_size\n";
5861 }
5862 });
91bd6c90 5863
5996a936 5864 # remove 'unusedX' entry if volume is used
ca04977c
FE
5865 PVE::QemuConfig->foreach_unused_volume($conf, sub {
5866 my ($opt, $drive) = @_;
5867
5868 my $volid = $drive->{file};
5869 return if !$volid;
5870
5996a936 5871 my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 5872 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
68b108ee 5873 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5996a936
DM
5874 $changes = 1;
5875 delete $conf->{$opt};
5876 }
c449137a
DC
5877
5878 $referenced->{$volid} = 1;
5879 $referencedpath->{$path} = 1 if $path;
ca04977c 5880 });
5996a936 5881
91bd6c90
DM
5882 foreach my $volid (sort keys %$volid_hash) {
5883 next if $volid =~ m/vm-$vmid-state-/;
c449137a 5884 next if $referenced->{$volid};
5996a936
DM
5885 my $path = $volid_hash->{$volid}->{path};
5886 next if !$path; # just to be sure
c449137a 5887 next if $referencedpath->{$path};
91bd6c90 5888 $changes = 1;
53b81297 5889 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
68b108ee 5890 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
c449137a 5891 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
5892 }
5893
5894 return $changes;
5895}
5896
5897sub rescan {
9224dcee 5898 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 5899
20519efc 5900 my $cfg = PVE::Storage::config();
91bd6c90 5901
b9a1a3ab
TL
5902 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5903 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
4771526a
AA
5904 foreach my $stor (keys %{$cfg->{ids}}) {
5905 delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
5906 }
5907
53b81297 5908 print "rescan volumes...\n";
91bd6c90
DM
5909 my $volid_hash = scan_volids($cfg, $vmid);
5910
5911 my $updatefn = sub {
5912 my ($vmid) = @_;
5913
ffda963f 5914 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 5915
ffda963f 5916 PVE::QemuConfig->check_lock($conf);
91bd6c90 5917
03da3f0d
DM
5918 my $vm_volids = {};
5919 foreach my $volid (keys %$volid_hash) {
5920 my $info = $volid_hash->{$volid};
5921 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
5922 }
5923
68b108ee 5924 my $changes = update_disk_config($vmid, $conf, $vm_volids);
91bd6c90 5925
9224dcee 5926 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
5927 };
5928
5929 if (defined($vmid)) {
5930 if ($nolock) {
5931 &$updatefn($vmid);
5932 } else {
ffda963f 5933 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
5934 }
5935 } else {
5936 my $vmlist = config_list();
5937 foreach my $vmid (keys %$vmlist) {
5938 if ($nolock) {
5939 &$updatefn($vmid);
5940 } else {
ffda963f 5941 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 5942 }
91bd6c90
DM
5943 }
5944 }
5945}
5946
9f3d73bc
DM
5947sub restore_proxmox_backup_archive {
5948 my ($archive, $vmid, $user, $options) = @_;
5949
5950 my $storecfg = PVE::Storage::config();
5951
5952 my ($storeid, $volname) = PVE::Storage::parse_volume_id($archive);
5953 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5954
5955 my $server = $scfg->{server};
5956 my $datastore = $scfg->{datastore};
5957 my $username = $scfg->{username} // 'root@pam';
5958 my $fingerprint = $scfg->{fingerprint};
5959
5960 my $repo = "$username\@$server:$datastore";
5961 my $password = PVE::Storage::PBSPlugin::pbs_get_password($scfg, $storeid);
5962 local $ENV{PBS_PASSWORD} = $password;
5963 local $ENV{PBS_FINGERPRINT} = $fingerprint if defined($fingerprint);
5964
5965 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
5966 PVE::Storage::parse_volname($storecfg, $archive);
5967
5968 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
5969
5970 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
5971
5972 my $tmpdir = "/var/tmp/vzdumptmp$$";
5973 rmtree $tmpdir;
5974 mkpath $tmpdir;
5975
5976 my $conffile = PVE::QemuConfig->config_file($vmid);
5977 my $tmpfn = "$conffile.$$.tmp";
5978 # disable interrupts (always do cleanups)
5979 local $SIG{INT} =
5980 local $SIG{TERM} =
5981 local $SIG{QUIT} =
5982 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
5983
5984 # Note: $oldconf is undef if VM does not exists
5985 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
5986 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
5987
5988 my $rpcenv = PVE::RPCEnvironment::get();
5989 my $devinfo = {};
5990
5991 eval {
5992 # enable interrupts
5993 local $SIG{INT} =
5994 local $SIG{TERM} =
5995 local $SIG{QUIT} =
5996 local $SIG{HUP} =
5997 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
5998
5999 my $cfgfn = "$tmpdir/qemu-server.conf";
6000 my $firewall_config_fn = "$tmpdir/fw.conf";
6001 my $index_fn = "$tmpdir/index.json";
6002
6003 my $cmd = "restore";
6004
6005 my $param = [$pbs_backup_name, "index.json", $index_fn];
6006 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6007 my $index = PVE::Tools::file_get_contents($index_fn);
6008 $index = decode_json($index);
6009
6010 # print Dumper($index);
6011 foreach my $info (@{$index->{files}}) {
6012 if ($info->{filename} =~ m/^(drive-\S+).img.fidx$/) {
6013 my $devname = $1;
6014 if ($info->{size} =~ m/^(\d+)$/) { # untaint size
6015 $devinfo->{$devname}->{size} = $1;
6016 } else {
6017 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6018 }
6019 }
6020 }
6021
6022 my $is_qemu_server_backup = scalar(grep { $_->{filename} eq 'qemu-server.conf.blob' } @{$index->{files}});
6023 if (!$is_qemu_server_backup) {
6024 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6025 }
6026 my $has_firewall_config = scalar(grep { $_->{filename} eq 'fw.conf.blob' } @{$index->{files}});
6027
6028 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6029 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6030
6031 if ($has_firewall_config) {
6032 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6033 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6034
6035 my $pve_firewall_dir = '/etc/pve/firewall';
6036 mkdir $pve_firewall_dir; # make sure the dir exists
6037 PVE::Tools::file_copy($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6038 }
6039
6040 my $fh = IO::File->new($cfgfn, "r") ||
6041 "unable to read qemu-server.conf - $!\n";
6042
6043 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6044
6045 # fixme: rate limit?
6046
6047 # create empty/temp config
6048 PVE::Tools::file_set_contents($conffile, "memory: 128\nlock: create");
6049
6050 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6051
6052 # allocate volumes
6053 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6054
6055 foreach my $virtdev (sort keys %$virtdev_hash) {
6056 my $d = $virtdev_hash->{$virtdev};
6057 next if $d->{is_cloudinit}; # no need to restore cloudinit
6058
6059 my $volid = $d->{volid};
6060
6061 my $path = PVE::Storage::path($storecfg, $volid);
9f3d73bc
DM
6062
6063 my $pbs_restore_cmd = [
e400f5e5 6064 '/usr/bin/pbs-restore',
9f3d73bc
DM
6065 '--repository', $repo,
6066 $pbs_backup_name,
e400f5e5
DM
6067 "$d->{devname}.img.fidx",
6068 $path,
9f3d73bc
DM
6069 '--verbose',
6070 ];
6071
e400f5e5
DM
6072 if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $volid)) {
6073 push @$pbs_restore_cmd, '--skip-zero';
6074 }
9f3d73bc 6075
e400f5e5 6076 my $dbg_cmdstring = PVE::Tools::cmd2string($pbs_restore_cmd);
9f3d73bc 6077 print "restore proxmox backup image: $dbg_cmdstring\n";
e400f5e5 6078 run_command($pbs_restore_cmd);
9f3d73bc
DM
6079 }
6080
6081 $fh->seek(0, 0) || die "seek failed - $!\n";
6082
6083 my $outfd = new IO::File ($tmpfn, "w") ||
6084 die "unable to write config for VM $vmid\n";
6085
6086 my $cookie = { netcount => 0 };
6087 while (defined(my $line = <$fh>)) {
6088 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $options->{unique});
6089 }
6090
6091 $fh->close();
6092 $outfd->close();
6093 };
6094 my $err = $@;
6095
6096 $restore_deactivate_volumes->($storecfg, $devinfo);
6097
6098 rmtree $tmpdir;
6099
6100 if ($err) {
6101 unlink $tmpfn;
6102 $restore_destroy_volumes->($storecfg, $devinfo);
6103 die $err;
6104 }
6105
6106 rename($tmpfn, $conffile) ||
6107 die "unable to commit configuration file '$conffile'\n";
6108
6109 PVE::Cluster::cfs_update(); # make sure we read new file
6110
6111 eval { rescan($vmid, 1); };
6112 warn $@ if $@;
6113}
6114
91bd6c90
DM
6115sub restore_vma_archive {
6116 my ($archive, $vmid, $user, $opts, $comp) = @_;
6117
91bd6c90
DM
6118 my $readfrom = $archive;
6119
7c536e11
WB
6120 my $cfg = PVE::Storage::config();
6121 my $commands = [];
6122 my $bwlimit = $opts->{bwlimit};
6123
6124 my $dbg_cmdstring = '';
6125 my $add_pipe = sub {
6126 my ($cmd) = @_;
6127 push @$commands, $cmd;
6128 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6129 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 6130 $readfrom = '-';
7c536e11
WB
6131 };
6132
6133 my $input = undef;
6134 if ($archive eq '-') {
6135 $input = '<&STDIN';
6136 } else {
6137 # If we use a backup from a PVE defined storage we also consider that
6138 # storage's rate limit:
6139 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
6140 if (defined($volid)) {
6141 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
6142 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
6143 if ($readlimit) {
6144 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 6145 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
6146 $add_pipe->($cstream);
6147 }
6148 }
6149 }
6150
6151 if ($comp) {
6152 my $cmd;
91bd6c90 6153 if ($comp eq 'gzip') {
7c536e11 6154 $cmd = ['zcat', $readfrom];
91bd6c90 6155 } elsif ($comp eq 'lzop') {
7c536e11 6156 $cmd = ['lzop', '-d', '-c', $readfrom];
91bd6c90
DM
6157 } else {
6158 die "unknown compression method '$comp'\n";
6159 }
7c536e11 6160 $add_pipe->($cmd);
91bd6c90
DM
6161 }
6162
6163 my $tmpdir = "/var/tmp/vzdumptmp$$";
6164 rmtree $tmpdir;
6165
6166 # disable interrupts (always do cleanups)
5b97ef24
TL
6167 local $SIG{INT} =
6168 local $SIG{TERM} =
6169 local $SIG{QUIT} =
6170 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
6171
6172 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6173 POSIX::mkfifo($mapfifo, 0600);
6174 my $fifofh;
6175
6176 my $openfifo = sub {
6177 open($fifofh, '>', $mapfifo) || die $!;
6178 };
6179
7c536e11 6180 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
6181
6182 my $oldtimeout;
6183 my $timeout = 5;
6184
6185 my $devinfo = {};
6186
6187 my $rpcenv = PVE::RPCEnvironment::get();
6188
ffda963f 6189 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90
DM
6190 my $tmpfn = "$conffile.$$.tmp";
6191
ae200950 6192 # Note: $oldconf is undef if VM does not exist
ffda963f
FG
6193 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6194 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
ed221350 6195
7c536e11
WB
6196 my %storage_limits;
6197
91bd6c90 6198 my $print_devmap = sub {
91bd6c90
DM
6199 my $cfgfn = "$tmpdir/qemu-server.conf";
6200
6201 # we can read the config - that is already extracted
6202 my $fh = IO::File->new($cfgfn, "r") ||
6203 "unable to read qemu-server.conf - $!\n";
6204
6738ab9c 6205 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
6206 if (-f $fwcfgfn) {
6207 my $pve_firewall_dir = '/etc/pve/firewall';
6208 mkdir $pve_firewall_dir; # make sure the dir exists
6209 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6210 }
6738ab9c 6211
9f3d73bc 6212 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
91bd6c90 6213
7c536e11
WB
6214 foreach my $key (keys %storage_limits) {
6215 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
6216 next if !$limit;
6217 print STDERR "rate limit for storage $key: $limit KiB/s\n";
6218 $storage_limits{$key} = $limit * 1024;
6219 }
6220
91bd6c90 6221 foreach my $devname (keys %$devinfo) {
be190583
DM
6222 die "found no device mapping information for device '$devname'\n"
6223 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
6224 }
6225
ed221350 6226 # create empty/temp config
be190583 6227 if ($oldconf) {
ed221350 6228 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
d1e92cf6 6229 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
ed221350
DM
6230 }
6231
9f3d73bc
DM
6232 # allocate volumes
6233 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6234
6235 # print restore information to $fifofh
91bd6c90
DM
6236 foreach my $virtdev (sort keys %$virtdev_hash) {
6237 my $d = $virtdev_hash->{$virtdev};
9f3d73bc
DM
6238 next if $d->{is_cloudinit}; # no need to restore cloudinit
6239
7c536e11 6240 my $storeid = $d->{storeid};
9f3d73bc 6241 my $volid = $d->{volid};
7c536e11
WB
6242
6243 my $map_opts = '';
6244 if (my $limit = $storage_limits{$storeid}) {
6245 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6246 }
8fd57431 6247
91bd6c90 6248 my $write_zeros = 1;
88240a83 6249 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
6250 $write_zeros = 0;
6251 }
6252
9f3d73bc 6253 my $path = PVE::Storage::path($cfg, $volid);
87056e18 6254
9f3d73bc 6255 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 6256
9f3d73bc 6257 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
91bd6c90
DM
6258 }
6259
6260 $fh->seek(0, 0) || die "seek failed - $!\n";
6261
6262 my $outfd = new IO::File ($tmpfn, "w") ||
6263 die "unable to write config for VM $vmid\n";
6264
6265 my $cookie = { netcount => 0 };
6266 while (defined(my $line = <$fh>)) {
9f3d73bc 6267 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
91bd6c90
DM
6268 }
6269
6270 $fh->close();
6271 $outfd->close();
6272 };
6273
6274 eval {
6275 # enable interrupts
6cb0144a
EK
6276 local $SIG{INT} =
6277 local $SIG{TERM} =
6278 local $SIG{QUIT} =
6279 local $SIG{HUP} =
6280 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
6281 local $SIG{ALRM} = sub { die "got timeout\n"; };
6282
6283 $oldtimeout = alarm($timeout);
6284
6285 my $parser = sub {
6286 my $line = shift;
6287
6288 print "$line\n";
6289
6290 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6291 my ($dev_id, $size, $devname) = ($1, $2, $3);
6292 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6293 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 6294 # we correctly received the vma config, so we can disable
3cf90d7a
DM
6295 # the timeout now for disk allocation (set to 10 minutes, so
6296 # that we always timeout if something goes wrong)
6297 alarm(600);
91bd6c90
DM
6298 &$print_devmap();
6299 print $fifofh "done\n";
6300 my $tmp = $oldtimeout || 0;
6301 $oldtimeout = undef;
6302 alarm($tmp);
6303 close($fifofh);
6304 }
6305 };
be190583 6306
7c536e11
WB
6307 print "restore vma archive: $dbg_cmdstring\n";
6308 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
6309 };
6310 my $err = $@;
6311
6312 alarm($oldtimeout) if $oldtimeout;
6313
9f3d73bc 6314 $restore_deactivate_volumes->($cfg, $devinfo);
5f96f4df 6315
91bd6c90 6316 unlink $mapfifo;
9f3d73bc 6317 rmtree $tmpdir;
91bd6c90
DM
6318
6319 if ($err) {
91bd6c90 6320 unlink $tmpfn;
9f3d73bc 6321 $restore_destroy_volumes->($cfg, $devinfo);
91bd6c90
DM
6322 die $err;
6323 }
6324
ed221350 6325 rename($tmpfn, $conffile) ||
91bd6c90
DM
6326 die "unable to commit configuration file '$conffile'\n";
6327
ed221350
DM
6328 PVE::Cluster::cfs_update(); # make sure we read new file
6329
91bd6c90
DM
6330 eval { rescan($vmid, 1); };
6331 warn $@ if $@;
6332}
6333
6334sub restore_tar_archive {
6335 my ($archive, $vmid, $user, $opts) = @_;
6336
9c502e26 6337 if ($archive ne '-') {
ed221350 6338 my $firstfile = tar_archive_read_firstfile($archive);
9c502e26
DM
6339 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6340 if $firstfile ne 'qemu-server.conf';
6341 }
3e16d5fc 6342
20519efc 6343 my $storecfg = PVE::Storage::config();
ebb55558 6344
4b026937
TL
6345 # avoid zombie disks when restoring over an existing VM -> cleanup first
6346 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6347 # skiplock=1 because qmrestore has set the 'create' lock itself already
ffda963f 6348 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
b04ea584 6349 destroy_vm($storecfg, $vmid, 1, { lock => 'restore' }) if -f $vmcfgfn;
ed221350 6350
3e16d5fc
DM
6351 my $tocmd = "/usr/lib/qemu-server/qmextract";
6352
2415a446 6353 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 6354 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
6355 $tocmd .= ' --prealloc' if $opts->{prealloc};
6356 $tocmd .= ' --info' if $opts->{info};
6357
a0d1b1a2 6358 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 6359 # so we pipe to zcat
2415a446
DM
6360 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6361 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
6362
6363 my $tmpdir = "/var/tmp/vzdumptmp$$";
6364 mkpath $tmpdir;
6365
6366 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6367 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 6368 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 6369
ffda963f 6370 my $conffile = PVE::QemuConfig->config_file($vmid);
3e16d5fc
DM
6371 my $tmpfn = "$conffile.$$.tmp";
6372
6373 # disable interrupts (always do cleanups)
6cb0144a
EK
6374 local $SIG{INT} =
6375 local $SIG{TERM} =
6376 local $SIG{QUIT} =
6377 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 6378
afdb31d5 6379 eval {
3e16d5fc 6380 # enable interrupts
6cb0144a
EK
6381 local $SIG{INT} =
6382 local $SIG{TERM} =
6383 local $SIG{QUIT} =
6384 local $SIG{HUP} =
6385 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 6386
9c502e26
DM
6387 if ($archive eq '-') {
6388 print "extracting archive from STDIN\n";
6389 run_command($cmd, input => "<&STDIN");
6390 } else {
6391 print "extracting archive '$archive'\n";
6392 run_command($cmd);
6393 }
3e16d5fc
DM
6394
6395 return if $opts->{info};
6396
6397 # read new mapping
6398 my $map = {};
6399 my $statfile = "$tmpdir/qmrestore.stat";
6400 if (my $fd = IO::File->new($statfile, "r")) {
6401 while (defined (my $line = <$fd>)) {
6402 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6403 $map->{$1} = $2 if $1;
6404 } else {
6405 print STDERR "unable to parse line in statfile - $line\n";
6406 }
6407 }
6408 $fd->close();
6409 }
6410
6411 my $confsrc = "$tmpdir/qemu-server.conf";
6412
6413 my $srcfd = new IO::File($confsrc, "r") ||
6414 die "unable to open file '$confsrc'\n";
6415
6416 my $outfd = new IO::File ($tmpfn, "w") ||
6417 die "unable to write config for VM $vmid\n";
6418
91bd6c90 6419 my $cookie = { netcount => 0 };
3e16d5fc 6420 while (defined (my $line = <$srcfd>)) {
9f3d73bc 6421 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
3e16d5fc
DM
6422 }
6423
6424 $srcfd->close();
6425 $outfd->close();
6426 };
7dc7f315 6427 if (my $err = $@) {
3e16d5fc 6428 unlink $tmpfn;
ed221350 6429 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
3e16d5fc 6430 die $err;
afdb31d5 6431 }
3e16d5fc
DM
6432
6433 rmtree $tmpdir;
6434
6435 rename $tmpfn, $conffile ||
6436 die "unable to commit configuration file '$conffile'\n";
91bd6c90 6437
ed221350
DM
6438 PVE::Cluster::cfs_update(); # make sure we read new file
6439
91bd6c90
DM
6440 eval { rescan($vmid, 1); };
6441 warn $@ if $@;
3e16d5fc
DM
6442};
6443
65a5ce88 6444sub foreach_storage_used_by_vm {
18bfb361
DM
6445 my ($conf, $func) = @_;
6446
6447 my $sidhash = {};
6448
8ddbcf8b
FG
6449 foreach_drive($conf, sub {
6450 my ($ds, $drive) = @_;
6451 return if drive_is_cdrom($drive);
18bfb361
DM
6452
6453 my $volid = $drive->{file};
6454
6455 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 6456 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 6457 });
18bfb361
DM
6458
6459 foreach my $sid (sort keys %$sidhash) {
6460 &$func($sid);
6461 }
6462}
6463
6c9f59c1
TL
6464my $qemu_snap_storage = {
6465 rbd => 1,
6466};
e5eaa028
WL
6467sub do_snapshots_with_qemu {
6468 my ($storecfg, $volid) = @_;
6469
6470 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 6471 my $scfg = $storecfg->{ids}->{$storage_name};
e5eaa028 6472
8aa2ed7c 6473 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
6474 return 1;
6475 }
6476
6477 if ($volid =~ m/\.(qcow2|qed)$/){
6478 return 1;
6479 }
6480
6481 return undef;
6482}
6483
4dcc780c 6484sub qga_check_running {
a4938c72 6485 my ($vmid, $nowarn) = @_;
4dcc780c 6486
0a13e08e 6487 eval { mon_cmd($vmid, "guest-ping", timeout => 3); };
4dcc780c 6488 if ($@) {
a4938c72 6489 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
6490 return 0;
6491 }
6492 return 1;
6493}
6494
04a69bb4
AD
6495sub template_create {
6496 my ($vmid, $conf, $disk) = @_;
6497
04a69bb4 6498 my $storecfg = PVE::Storage::config();
04a69bb4 6499
9cd07842
DM
6500 foreach_drive($conf, sub {
6501 my ($ds, $drive) = @_;
6502
6503 return if drive_is_cdrom($drive);
6504 return if $disk && $ds ne $disk;
6505
6506 my $volid = $drive->{file};
bbd56097 6507 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 6508
04a69bb4
AD
6509 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
6510 $drive->{file} = $voliddst;
71c58bb7 6511 $conf->{$ds} = print_drive($drive);
ffda963f 6512 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 6513 });
04a69bb4
AD
6514}
6515
92bdc3f0
DC
6516sub convert_iscsi_path {
6517 my ($path) = @_;
6518
6519 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
6520 my $portal = $1;
6521 my $target = $2;
6522 my $lun = $3;
6523
6524 my $initiator_name = get_initiator_name();
6525
6526 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6527 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6528 }
6529
6530 die "cannot convert iscsi path '$path', unkown format\n";
6531}
6532
5133de42 6533sub qemu_img_convert {
988e2714 6534 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
6535
6536 my $storecfg = PVE::Storage::config();
6537 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
6538 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
6539
af1f1ec0 6540 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6bb91c17 6541
af1f1ec0
DC
6542 my $cachemode;
6543 my $src_path;
6544 my $src_is_iscsi = 0;
bdd1feef 6545 my $src_format;
6bb91c17 6546
af1f1ec0
DC
6547 if ($src_storeid) {
6548 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
5133de42 6549 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
af1f1ec0
DC
6550 $src_format = qemu_img_format($src_scfg, $src_volname);
6551 $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
6552 $src_is_iscsi = ($src_path =~ m|^iscsi://|);
6553 $cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
6554 } elsif (-f $src_volid) {
6555 $src_path = $src_volid;
e0fd2b2f 6556 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
af1f1ec0
DC
6557 $src_format = $1;
6558 }
6559 }
5133de42 6560
af1f1ec0 6561 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
5133de42 6562
af1f1ec0
DC
6563 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6564 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
6565 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6566 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
5133de42 6567
af1f1ec0
DC
6568 my $cmd = [];
6569 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
bdd1feef
TL
6570 push @$cmd, '-l', "snapshot.name=$snapname"
6571 if $snapname && $src_format && $src_format eq "qcow2";
af1f1ec0
DC
6572 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
6573 push @$cmd, '-T', $cachemode if defined($cachemode);
6574
6575 if ($src_is_iscsi) {
6576 push @$cmd, '--image-opts';
6577 $src_path = convert_iscsi_path($src_path);
bdd1feef 6578 } elsif ($src_format) {
af1f1ec0
DC
6579 push @$cmd, '-f', $src_format;
6580 }
92bdc3f0 6581
af1f1ec0
DC
6582 if ($dst_is_iscsi) {
6583 push @$cmd, '--target-image-opts';
6584 $dst_path = convert_iscsi_path($dst_path);
6585 } else {
6586 push @$cmd, '-O', $dst_format;
6587 }
92bdc3f0 6588
af1f1ec0 6589 push @$cmd, $src_path;
92bdc3f0 6590
af1f1ec0
DC
6591 if (!$dst_is_iscsi && $is_zero_initialized) {
6592 push @$cmd, "zeroinit:$dst_path";
6593 } else {
6594 push @$cmd, $dst_path;
6595 }
92bdc3f0 6596
af1f1ec0
DC
6597 my $parser = sub {
6598 my $line = shift;
6599 if($line =~ m/\((\S+)\/100\%\)/){
6600 my $percent = $1;
6601 my $transferred = int($size * $percent / 100);
6602 my $remaining = $size - $transferred;
92bdc3f0 6603
af1f1ec0 6604 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
988e2714 6605 }
5133de42 6606
af1f1ec0 6607 };
5133de42 6608
af1f1ec0
DC
6609 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
6610 my $err = $@;
6611 die "copy failed: $err" if $err;
5133de42
AD
6612}
6613
6614sub qemu_img_format {
6615 my ($scfg, $volname) = @_;
6616
e0fd2b2f 6617 if ($scfg->{path} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
5133de42 6618 return $1;
be190583 6619 } else {
5133de42 6620 return "raw";
5133de42
AD
6621 }
6622}
6623
cfad42af 6624sub qemu_drive_mirror {
bc6c8231 6625 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
cfad42af 6626
5a345967
AD
6627 $jobs = {} if !$jobs;
6628
6629 my $qemu_target;
6630 my $format;
35e4ab04 6631 $jobs->{"drive-$drive"} = {};
152fe752 6632
1e5143de 6633 if ($dst_volid =~ /^nbd:/) {
87955688 6634 $qemu_target = $dst_volid;
5a345967 6635 $format = "nbd";
5a345967 6636 } else {
5a345967
AD
6637 my $storecfg = PVE::Storage::config();
6638 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
6639
6640 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 6641
5a345967 6642 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 6643
5a345967 6644 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 6645
5a345967
AD
6646 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
6647 }
988e2714
WB
6648
6649 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
6650 $opts->{format} = $format if $format;
6651
bc6c8231
FG
6652 if (defined($src_bitmap)) {
6653 $opts->{sync} = 'incremental';
6654 $opts->{bitmap} = $src_bitmap;
6655 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
6656 }
6657
9fa05d31 6658 if (defined($bwlimit)) {
f6409f61
TL
6659 $opts->{speed} = $bwlimit * 1024;
6660 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
6661 } else {
6662 print "drive mirror is starting for drive-$drive\n";
6663 }
21ccdb50 6664
6dde5ea2 6665 # if a job already runs for this device we get an error, catch it for cleanup
0a13e08e 6666 eval { mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
6667 if (my $err = $@) {
6668 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
6669 warn "$@\n" if $@;
6670 die "mirroring error: $err\n";
5a345967
AD
6671 }
6672
e02fb126 6673 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga);
5a345967
AD
6674}
6675
db1f8b39
FG
6676# $completion can be either
6677# 'complete': wait until all jobs are ready, block-job-complete them (default)
6678# 'cancel': wait until all jobs are ready, block-job-cancel them
6679# 'skip': wait until all jobs are ready, return with block jobs in ready state
5a345967 6680sub qemu_drive_mirror_monitor {
e02fb126
ML
6681 my ($vmid, $vmiddst, $jobs, $completion, $qga) = @_;
6682
db1f8b39 6683 $completion //= 'complete';
2e953867 6684
08ac653f 6685 eval {
5a345967
AD
6686 my $err_complete = 0;
6687
08ac653f 6688 while (1) {
5a345967
AD
6689 die "storage migration timed out\n" if $err_complete > 300;
6690
0a13e08e 6691 my $stats = mon_cmd($vmid, "query-block-jobs");
08ac653f 6692
5a345967
AD
6693 my $running_mirror_jobs = {};
6694 foreach my $stat (@$stats) {
6695 next if $stat->{type} ne 'mirror';
6696 $running_mirror_jobs->{$stat->{device}} = $stat;
6697 }
08ac653f 6698
5a345967 6699 my $readycounter = 0;
67fb9de6 6700
5a345967
AD
6701 foreach my $job (keys %$jobs) {
6702
6703 if(defined($jobs->{$job}->{complete}) && !defined($running_mirror_jobs->{$job})) {
6704 print "$job : finished\n";
6705 delete $jobs->{$job};
6706 next;
6707 }
6708
bd2d5fe6 6709 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
f34ebd52 6710
5a345967
AD
6711 my $busy = $running_mirror_jobs->{$job}->{busy};
6712 my $ready = $running_mirror_jobs->{$job}->{ready};
6713 if (my $total = $running_mirror_jobs->{$job}->{len}) {
6714 my $transferred = $running_mirror_jobs->{$job}->{offset} || 0;
6715 my $remaining = $total - $transferred;
6716 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 6717
5a345967
AD
6718 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6719 }
f34ebd52 6720
d1782eba 6721 $readycounter++ if $running_mirror_jobs->{$job}->{ready};
5a345967 6722 }
b467f79a 6723
5a345967
AD
6724 last if scalar(keys %$jobs) == 0;
6725
6726 if ($readycounter == scalar(keys %$jobs)) {
6727 print "all mirroring jobs are ready \n";
e02fb126 6728 last if $completion eq 'skip'; #do the complete later
5a345967
AD
6729
6730 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
6731 my $agent_running = $qga && qga_check_running($vmid);
6732 if ($agent_running) {
5619e74a 6733 print "freeze filesystem\n";
0a13e08e 6734 eval { mon_cmd($vmid, "guest-fsfreeze-freeze"); };
5619e74a
AD
6735 } else {
6736 print "suspend vm\n";
6737 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
6738 }
6739
5a345967
AD
6740 # if we clone a disk for a new target vm, we don't switch the disk
6741 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 6742
1a988fd2 6743 if ($agent_running) {
5619e74a 6744 print "unfreeze filesystem\n";
0a13e08e 6745 eval { mon_cmd($vmid, "guest-fsfreeze-thaw"); };
5619e74a
AD
6746 } else {
6747 print "resume vm\n";
6748 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
6749 }
6750
2e953867 6751 last;
5a345967
AD
6752 } else {
6753
6754 foreach my $job (keys %$jobs) {
6755 # try to switch the disk if source and destination are on the same guest
bd2d5fe6 6756 print "$job: Completing block job...\n";
5a345967 6757
e02fb126 6758 my $op;
db1f8b39 6759 if ($completion eq 'complete') {
e02fb126 6760 $op = 'block-job-complete';
db1f8b39 6761 } elsif ($completion eq 'cancel') {
e02fb126
ML
6762 $op = 'block-job-cancel';
6763 } else {
6764 die "invalid completion value: $completion\n";
6765 }
6766 eval { mon_cmd($vmid, $op, device => $job) };
5a345967 6767 if ($@ =~ m/cannot be completed/) {
bd2d5fe6 6768 print "$job: Block job cannot be completed, try again.\n";
5a345967
AD
6769 $err_complete++;
6770 }else {
bd2d5fe6 6771 print "$job: Completed successfully.\n";
5a345967
AD
6772 $jobs->{$job}->{complete} = 1;
6773 }
6774 }
2e953867 6775 }
08ac653f 6776 }
08ac653f 6777 sleep 1;
cfad42af 6778 }
08ac653f 6779 };
88383920 6780 my $err = $@;
08ac653f 6781
88383920 6782 if ($err) {
5a345967 6783 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
88383920
DM
6784 die "mirroring error: $err";
6785 }
6786
5a345967
AD
6787}
6788
6789sub qemu_blockjobs_cancel {
6790 my ($vmid, $jobs) = @_;
6791
6792 foreach my $job (keys %$jobs) {
bd2d5fe6 6793 print "$job: Cancelling block job\n";
0a13e08e 6794 eval { mon_cmd($vmid, "block-job-cancel", device => $job); };
5a345967
AD
6795 $jobs->{$job}->{cancel} = 1;
6796 }
6797
6798 while (1) {
0a13e08e 6799 my $stats = mon_cmd($vmid, "query-block-jobs");
5a345967
AD
6800
6801 my $running_jobs = {};
6802 foreach my $stat (@$stats) {
6803 $running_jobs->{$stat->{device}} = $stat;
6804 }
6805
6806 foreach my $job (keys %$jobs) {
6807
bd2d5fe6
WB
6808 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
6809 print "$job: Done.\n";
5a345967
AD
6810 delete $jobs->{$job};
6811 }
6812 }
6813
6814 last if scalar(keys %$jobs) == 0;
6815
6816 sleep 1;
cfad42af
AD
6817 }
6818}
6819
152fe752 6820sub clone_disk {
be190583 6821 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
818ce80e 6822 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
152fe752
DM
6823
6824 my $newvolid;
6825
6826 if (!$full) {
6827 print "create linked clone of drive $drivename ($drive->{file})\n";
258e646c 6828 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
6829 push @$newvollist, $newvolid;
6830 } else {
5a345967 6831
152fe752
DM
6832 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
6833 $storeid = $storage if $storage;
6834
44549149 6835 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752
DM
6836 my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
6837
6838 print "create full clone of drive $drivename ($drive->{file})\n";
931432bd 6839 my $name = undef;
7fe8b44c
TL
6840 if (drive_is_cloudinit($drive)) {
6841 $name = "vm-$newvmid-cloudinit";
6842 $name .= ".$dst_format" if $dst_format ne 'raw';
6843 $snapname = undef;
6844 $size = PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE;
818ce80e
DC
6845 } elsif ($drivename eq 'efidisk0') {
6846 $size = get_efivars_size($conf);
7fe8b44c 6847 }
931432bd 6848 $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
152fe752
DM
6849 push @$newvollist, $newvolid;
6850
3999f370 6851 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 6852
7fe8b44c
TL
6853 if (drive_is_cloudinit($drive)) {
6854 goto no_data_clone;
6855 }
6856
988e2714 6857 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
152fe752 6858 if (!$running || $snapname) {
d189e590 6859 # TODO: handle bwlimits
818ce80e
DC
6860 if ($drivename eq 'efidisk0') {
6861 # the relevant data on the efidisk may be smaller than the source
6862 # e.g. on RBD/ZFS, so we use dd to copy only the amount
6863 # that is given by the OVMF_VARS.fd
6864 my $src_path = PVE::Storage::path($storecfg, $drive->{file});
6865 my $dst_path = PVE::Storage::path($storecfg, $newvolid);
6866 run_command(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size", "if=$src_path", "of=$dst_path"]);
6867 } else {
6868 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
6869 }
152fe752 6870 } else {
2e541679
AD
6871
6872 my $kvmver = get_running_qemu_version ($vmid);
2ea5fb7e 6873 if (!min_version($kvmver, 2, 7)) {
961af8a3
WB
6874 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6875 if $drive->{iothread};
2e541679 6876 }
2af848a2 6877
db1f8b39 6878 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $completion, $qga, $bwlimit);
be190583 6879 }
152fe752
DM
6880 }
6881
7fe8b44c 6882no_data_clone:
152fe752
DM
6883 my ($size) = PVE::Storage::volume_size_info($storecfg, $newvolid, 3);
6884
6885 my $disk = $drive;
6886 $disk->{format} = undef;
6887 $disk->{file} = $newvolid;
6888 $disk->{size} = $size;
6889
6890 return $disk;
6891}
6892
98cfd8b6
AD
6893sub get_running_qemu_version {
6894 my ($vmid) = @_;
0a13e08e 6895 my $res = mon_cmd($vmid, "query-version");
98cfd8b6
AD
6896 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6897}
6898
249c4a6c
AD
6899sub qemu_use_old_bios_files {
6900 my ($machine_type) = @_;
6901
6902 return if !$machine_type;
6903
6904 my $use_old_bios_files = undef;
6905
6906 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6907 $machine_type = $1;
6908 $use_old_bios_files = 1;
6909 } else {
9471e48b 6910 my $version = PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version());
249c4a6c
AD
6911 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6912 # load new efi bios files on migration. So this hack is required to allow
6913 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6914 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
2ea5fb7e 6915 $use_old_bios_files = !min_version($version, 2, 4);
249c4a6c
AD
6916 }
6917
6918 return ($use_old_bios_files, $machine_type);
6919}
6920
818ce80e
DC
6921sub get_efivars_size {
6922 my ($conf) = @_;
6923 my $arch = get_vm_arch($conf);
6924 my (undef, $ovmf_vars) = get_ovmf_files($arch);
6925 die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
6926 return -s $ovmf_vars;
6927}
6928
6929sub update_efidisk_size {
6930 my ($conf) = @_;
6931
6932 return if !defined($conf->{efidisk0});
6933
6934 my $disk = PVE::QemuServer::parse_drive('efidisk0', $conf->{efidisk0});
6935 $disk->{size} = get_efivars_size($conf);
6936 $conf->{efidisk0} = print_drive($disk);
6937
6938 return;
6939}
6940
96ed3574
WB
6941sub create_efidisk($$$$$) {
6942 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
3e1f1122 6943
96ed3574
WB
6944 my (undef, $ovmf_vars) = get_ovmf_files($arch);
6945 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 6946
af1f1ec0
DC
6947 my $vars_size_b = -s $ovmf_vars;
6948 my $vars_size = PVE::Tools::convert_size($vars_size_b, 'b' => 'kb');
3e1f1122
TL
6949 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6950 PVE::Storage::activate_volumes($storecfg, [$volid]);
6951
af1f1ec0 6952 qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0);
340dbcf7 6953 my ($size) = PVE::Storage::volume_size_info($storecfg, $volid, 3);
3e1f1122 6954
340dbcf7 6955 return ($volid, $size/1024);
3e1f1122
TL
6956}
6957
22de899a
AD
6958sub vm_iothreads_list {
6959 my ($vmid) = @_;
6960
0a13e08e 6961 my $res = mon_cmd($vmid, 'query-iothreads');
22de899a
AD
6962
6963 my $iothreads = {};
6964 foreach my $iothread (@$res) {
6965 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
6966 }
6967
6968 return $iothreads;
6969}
6970
ee034f5c
AD
6971sub scsihw_infos {
6972 my ($conf, $drive) = @_;
6973
6974 my $maxdev = 0;
6975
7fe1b688 6976 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 6977 $maxdev = 7;
a1511b3c 6978 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
6979 $maxdev = 1;
6980 } else {
6981 $maxdev = 256;
6982 }
6983
6984 my $controller = int($drive->{index} / $maxdev);
a1511b3c 6985 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
ee034f5c
AD
6986
6987 return ($maxdev, $controller, $controller_prefix);
6988}
a1511b3c 6989
4317f69f
AD
6990sub windows_version {
6991 my ($ostype) = @_;
6992
6993 return 0 if !$ostype;
6994
6995 my $winversion = 0;
6996
6997 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6998 $winversion = 5;
6999 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7000 $winversion = 6;
7001 } elsif ($ostype =~ m/^win(\d+)$/) {
7002 $winversion = $1;
7003 }
7004
7005 return $winversion;
7006}
7007
44549149
EK
7008sub resolve_dst_disk_format {
7009 my ($storecfg, $storeid, $src_volname, $format) = @_;
7010 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7011
7012 if (!$format) {
7013 # if no target format is specified, use the source disk format as hint
7014 if ($src_volname) {
7015 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7016 $format = qemu_img_format($scfg, $src_volname);
7017 } else {
7018 return $defFormat;
7019 }
7020 }
7021
7022 # test if requested format is supported - else use default
7023 my $supported = grep { $_ eq $format } @$validFormats;
7024 $format = $defFormat if !$supported;
7025 return $format;
7026}
7027
66cebc46
DC
7028# NOTE: if this logic changes, please update docs & possibly gui logic
7029sub find_vmstate_storage {
7030 my ($conf, $storecfg) = @_;
7031
7032 # first, return storage from conf if set
7033 return $conf->{vmstatestorage} if $conf->{vmstatestorage};
7034
7035 my ($target, $shared, $local);
7036
7037 foreach_storage_used_by_vm($conf, sub {
7038 my ($sid) = @_;
7039 my $scfg = PVE::Storage::storage_config($storecfg, $sid);
7040 my $dst = $scfg->{shared} ? \$shared : \$local;
7041 $$dst = $sid if !$$dst || $scfg->{path}; # prefer file based storage
7042 });
7043
7044 # second, use shared storage where VM has at least one disk
7045 # third, use local storage where VM has at least one disk
7046 # fall back to local storage
7047 $target = $shared // $local // 'local';
7048
7049 return $target;
7050}
7051
6ee499ff 7052sub generate_uuid {
ae2fcb3b
EK
7053 my ($uuid, $uuid_str);
7054 UUID::generate($uuid);
7055 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
7056 return $uuid_str;
7057}
7058
7059sub generate_smbios1_uuid {
7060 return "uuid=".generate_uuid();
ae2fcb3b
EK
7061}
7062
9c152e87
TL
7063sub nbd_stop {
7064 my ($vmid) = @_;
7065
0a13e08e 7066 mon_cmd($vmid, 'nbd-server-stop');
9c152e87
TL
7067}
7068
dae98db9
DC
7069sub create_reboot_request {
7070 my ($vmid) = @_;
7071 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7072 or die "failed to create reboot trigger file: $!\n";
7073 close($fh);
7074}
7075
7076sub clear_reboot_request {
7077 my ($vmid) = @_;
7078 my $path = "/run/qemu-server/$vmid.reboot";
7079 my $res = 0;
7080
7081 $res = unlink($path);
7082 die "could not remove reboot request for $vmid: $!"
7083 if !$res && $! != POSIX::ENOENT;
7084
7085 return $res;
7086}
7087
65e866e5
DM
7088# bash completion helper
7089
7090sub complete_backup_archives {
7091 my ($cmdname, $pname, $cvalue) = @_;
7092
7093 my $cfg = PVE::Storage::config();
7094
7095 my $storeid;
7096
7097 if ($cvalue =~ m/^([^:]+):/) {
7098 $storeid = $1;
7099 }
7100
7101 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
7102
7103 my $res = [];
7104 foreach my $id (keys %$data) {
7105 foreach my $item (@{$data->{$id}}) {
7106 next if $item->{format} !~ m/^vma\.(gz|lzo)$/;
7107 push @$res, $item->{volid} if defined($item->{volid});
7108 }
7109 }
7110
7111 return $res;
7112}
7113
7114my $complete_vmid_full = sub {
7115 my ($running) = @_;
7116
7117 my $idlist = vmstatus();
7118
7119 my $res = [];
7120
7121 foreach my $id (keys %$idlist) {
7122 my $d = $idlist->{$id};
7123 if (defined($running)) {
7124 next if $d->{template};
7125 next if $running && $d->{status} ne 'running';
7126 next if !$running && $d->{status} eq 'running';
7127 }
7128 push @$res, $id;
7129
7130 }
7131 return $res;
7132};
7133
7134sub complete_vmid {
7135 return &$complete_vmid_full();
7136}
7137
7138sub complete_vmid_stopped {
7139 return &$complete_vmid_full(0);
7140}
7141
7142sub complete_vmid_running {
7143 return &$complete_vmid_full(1);
7144}
7145
335af808
DM
7146sub complete_storage {
7147
7148 my $cfg = PVE::Storage::config();
7149 my $ids = $cfg->{ids};
7150
7151 my $res = [];
7152 foreach my $sid (keys %$ids) {
7153 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 7154 next if !$ids->{$sid}->{content}->{images};
335af808
DM
7155 push @$res, $sid;
7156 }
7157
7158 return $res;
7159}
7160
255e9c54
AL
7161sub complete_migration_storage {
7162 my ($cmd, $param, $current_value, $all_args) = @_;
7163
7164 my $targetnode = @$all_args[1];
7165
7166 my $cfg = PVE::Storage::config();
7167 my $ids = $cfg->{ids};
7168
7169 my $res = [];
7170 foreach my $sid (keys %$ids) {
7171 next if !PVE::Storage::storage_check_enabled($cfg, $sid, $targetnode, 1);
7172 next if !$ids->{$sid}->{content}->{images};
7173 push @$res, $sid;
7174 }
7175
7176 return $res;
7177}
7178
1e3baf05 71791;