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