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