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