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