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