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