]> git.proxmox.com Git - qemu-server.git/blob - PVE/QemuServer.pm
only use vhost-net for native kvm machines
[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 if (is_native($arch)) {
1954 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model} eq 'virtio';
1955 }
1956
1957 my $vmname = $conf->{name} || "vm$vmid";
1958
1959 my $netdev = "";
1960 my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
1961
1962 if ($net->{bridge}) {
1963 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1964 } else {
1965 $netdev = "type=user,id=$netid,hostname=$vmname";
1966 }
1967
1968 $netdev .= ",queues=$net->{queues}" if ($net->{queues} && $net->{model} eq 'virtio');
1969
1970 return $netdev;
1971 }
1972
1973
1974 sub print_cpu_device {
1975 my ($conf, $id) = @_;
1976
1977 my $kvm = $conf->{kvm} // 1;
1978 my $cpu = $kvm ? "kvm64" : "qemu64";
1979 if (my $cputype = $conf->{cpu}) {
1980 my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
1981 or die "Cannot parse cpu description: $cputype\n";
1982 $cpu = $cpuconf->{cputype};
1983 }
1984
1985 my $cores = $conf->{cores} || 1;
1986
1987 my $current_core = ($id - 1) % $cores;
1988 my $current_socket = int(($id - 1 - $current_core)/$cores);
1989
1990 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1991 }
1992
1993 my $vga_map = {
1994 'cirrus' => 'cirrus-vga',
1995 'std' => 'VGA',
1996 'vmware' => 'vmware-svga',
1997 'virtio' => 'virtio-vga',
1998 };
1999
2000 sub print_vga_device {
2001 my ($conf, $vga, $id, $qxlnum, $bridges) = @_;
2002
2003 my $type = $vga_map->{$vga->{type}};
2004 my $vgamem_mb = $vga->{memory};
2005 if ($qxlnum) {
2006 $type = $id ? 'qxl' : 'qxl-vga';
2007 }
2008 die "no devicetype for $vga->{type}\n" if !$type;
2009
2010 my $memory = "";
2011 if ($vgamem_mb) {
2012 if ($vga->{type} eq 'virtio') {
2013 my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
2014 $memory = ",max_hostmem=$bytes";
2015 } elsif ($qxlnum) {
2016 # from https://www.spice-space.org/multiple-monitors.html
2017 $memory = ",vgamem_mb=$vga->{memory}";
2018 my $ram = $vgamem_mb * 4;
2019 my $vram = $vgamem_mb * 2;
2020 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2021 } else {
2022 $memory = ",vgamem_mb=$vga->{memory}";
2023 }
2024 } elsif ($qxlnum && $id) {
2025 $memory = ",ram_size=67108864,vram_size=33554432";
2026 }
2027
2028 my $q35 = machine_type_is_q35($conf);
2029 my $vgaid = "vga" . ($id // '');
2030 my $pciaddr;
2031
2032 if ($q35 && $vgaid eq 'vga') {
2033 # the first display uses pcie.0 bus on q35 machines
2034 $pciaddr = print_pcie_addr($vgaid, $bridges);
2035 } else {
2036 $pciaddr = print_pci_addr($vgaid, $bridges);
2037 }
2038
2039 return "$type,id=${vgaid}${memory}${pciaddr}";
2040 }
2041
2042 sub drive_is_cloudinit {
2043 my ($drive) = @_;
2044 return $drive->{file} =~ m@[:/]vm-\d+-cloudinit(?:\.$QEMU_FORMAT_RE)?$@;
2045 }
2046
2047 sub drive_is_cdrom {
2048 my ($drive, $exclude_cloudinit) = @_;
2049
2050 return 0 if $exclude_cloudinit && drive_is_cloudinit($drive);
2051
2052 return $drive && $drive->{media} && ($drive->{media} eq 'cdrom');
2053
2054 }
2055
2056 sub parse_number_sets {
2057 my ($set) = @_;
2058 my $res = [];
2059 foreach my $part (split(/;/, $set)) {
2060 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2061 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2062 push @$res, [ $1, $2 ];
2063 } else {
2064 die "invalid range: $part\n";
2065 }
2066 }
2067 return $res;
2068 }
2069
2070 sub parse_numa {
2071 my ($data) = @_;
2072
2073 my $res = PVE::JSONSchema::parse_property_string($numa_fmt, $data);
2074 $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
2075 $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
2076 return $res;
2077 }
2078
2079 sub parse_hostpci {
2080 my ($value) = @_;
2081
2082 return undef if !$value;
2083
2084 my $res = PVE::JSONSchema::parse_property_string($hostpci_fmt, $value);
2085
2086 my @idlist = split(/;/, $res->{host});
2087 delete $res->{host};
2088 foreach my $id (@idlist) {
2089 if ($id =~ /^$PCIRE$/) {
2090 if (defined($2)) {
2091 push @{$res->{pciid}}, { id => $1, function => $2 };
2092 } else {
2093 my $pcidevices = lspci($1);
2094 $res->{pciid} = $pcidevices->{$1};
2095 }
2096 } else {
2097 # should have been caught by parse_property_string already
2098 die "failed to parse PCI id: $id\n";
2099 }
2100 }
2101 return $res;
2102 }
2103
2104 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2105 sub parse_net {
2106 my ($data) = @_;
2107
2108 my $res = eval { PVE::JSONSchema::parse_property_string($net_fmt, $data) };
2109 if ($@) {
2110 warn $@;
2111 return undef;
2112 }
2113 if (!defined($res->{macaddr})) {
2114 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
2115 $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
2116 }
2117 return $res;
2118 }
2119
2120 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2121 sub parse_ipconfig {
2122 my ($data) = @_;
2123
2124 my $res = eval { PVE::JSONSchema::parse_property_string($ipconfig_fmt, $data) };
2125 if ($@) {
2126 warn $@;
2127 return undef;
2128 }
2129
2130 if ($res->{gw} && !$res->{ip}) {
2131 warn 'gateway specified without specifying an IP address';
2132 return undef;
2133 }
2134 if ($res->{gw6} && !$res->{ip6}) {
2135 warn 'IPv6 gateway specified without specifying an IPv6 address';
2136 return undef;
2137 }
2138 if ($res->{gw} && $res->{ip} eq 'dhcp') {
2139 warn 'gateway specified together with DHCP';
2140 return undef;
2141 }
2142 if ($res->{gw6} && $res->{ip6} !~ /^$IPV6RE/) {
2143 # gw6 + auto/dhcp
2144 warn "IPv6 gateway specified together with $res->{ip6} address";
2145 return undef;
2146 }
2147
2148 if (!$res->{ip} && !$res->{ip6}) {
2149 return { ip => 'dhcp', ip6 => 'dhcp' };
2150 }
2151
2152 return $res;
2153 }
2154
2155 sub print_net {
2156 my $net = shift;
2157
2158 return PVE::JSONSchema::print_property_string($net, $net_fmt);
2159 }
2160
2161 sub add_random_macs {
2162 my ($settings) = @_;
2163
2164 foreach my $opt (keys %$settings) {
2165 next if $opt !~ m/^net(\d+)$/;
2166 my $net = parse_net($settings->{$opt});
2167 next if !$net;
2168 $settings->{$opt} = print_net($net);
2169 }
2170 }
2171
2172 sub vm_is_volid_owner {
2173 my ($storecfg, $vmid, $volid) = @_;
2174
2175 if ($volid !~ m|^/|) {
2176 my ($path, $owner);
2177 eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
2178 if ($owner && ($owner == $vmid)) {
2179 return 1;
2180 }
2181 }
2182
2183 return undef;
2184 }
2185
2186 sub split_flagged_list {
2187 my $text = shift || '';
2188 $text =~ s/[,;]/ /g;
2189 $text =~ s/^\s+//;
2190 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2191 }
2192
2193 sub join_flagged_list {
2194 my ($how, $lst) = @_;
2195 join $how, map { $lst->{$_} . $_ } keys %$lst;
2196 }
2197
2198 sub vmconfig_delete_pending_option {
2199 my ($conf, $key, $force) = @_;
2200
2201 delete $conf->{pending}->{$key};
2202 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
2203 $pending_delete_hash->{$key} = $force ? '!' : '';
2204 $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
2205 }
2206
2207 sub vmconfig_undelete_pending_option {
2208 my ($conf, $key) = @_;
2209
2210 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
2211 delete $pending_delete_hash->{$key};
2212
2213 if (%$pending_delete_hash) {
2214 $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
2215 } else {
2216 delete $conf->{pending}->{delete};
2217 }
2218 }
2219
2220 sub vmconfig_register_unused_drive {
2221 my ($storecfg, $vmid, $conf, $drive) = @_;
2222
2223 if (drive_is_cloudinit($drive)) {
2224 eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
2225 warn $@ if $@;
2226 } elsif (!drive_is_cdrom($drive)) {
2227 my $volid = $drive->{file};
2228 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
2229 PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
2230 }
2231 }
2232 }
2233
2234 sub vmconfig_cleanup_pending {
2235 my ($conf) = @_;
2236
2237 # remove pending changes when nothing changed
2238 my $changes;
2239 foreach my $opt (keys %{$conf->{pending}}) {
2240 if (defined($conf->{$opt}) && ($conf->{pending}->{$opt} eq $conf->{$opt})) {
2241 $changes = 1;
2242 delete $conf->{pending}->{$opt};
2243 }
2244 }
2245
2246 my $current_delete_hash = split_flagged_list($conf->{pending}->{delete});
2247 my $pending_delete_hash = {};
2248 while (my ($opt, $force) = each %$current_delete_hash) {
2249 if (defined($conf->{$opt})) {
2250 $pending_delete_hash->{$opt} = $force;
2251 } else {
2252 $changes = 1;
2253 }
2254 }
2255
2256 if (%$pending_delete_hash) {
2257 $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
2258 } else {
2259 delete $conf->{pending}->{delete};
2260 }
2261
2262 return $changes;
2263 }
2264
2265 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2266 my $smbios1_fmt = {
2267 uuid => {
2268 type => 'string',
2269 pattern => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2270 format_description => 'UUID',
2271 description => "Set SMBIOS1 UUID.",
2272 optional => 1,
2273 },
2274 version => {
2275 type => 'string',
2276 pattern => '\S+',
2277 format_description => 'string',
2278 description => "Set SMBIOS1 version.",
2279 optional => 1,
2280 },
2281 serial => {
2282 type => 'string',
2283 pattern => '\S+',
2284 format_description => 'string',
2285 description => "Set SMBIOS1 serial number.",
2286 optional => 1,
2287 },
2288 manufacturer => {
2289 type => 'string',
2290 pattern => '\S+',
2291 format_description => 'string',
2292 description => "Set SMBIOS1 manufacturer.",
2293 optional => 1,
2294 },
2295 product => {
2296 type => 'string',
2297 pattern => '\S+',
2298 format_description => 'string',
2299 description => "Set SMBIOS1 product ID.",
2300 optional => 1,
2301 },
2302 sku => {
2303 type => 'string',
2304 pattern => '\S+',
2305 format_description => 'string',
2306 description => "Set SMBIOS1 SKU string.",
2307 optional => 1,
2308 },
2309 family => {
2310 type => 'string',
2311 pattern => '\S+',
2312 format_description => 'string',
2313 description => "Set SMBIOS1 family string.",
2314 optional => 1,
2315 },
2316 };
2317
2318 sub parse_smbios1 {
2319 my ($data) = @_;
2320
2321 my $res = eval { PVE::JSONSchema::parse_property_string($smbios1_fmt, $data) };
2322 warn $@ if $@;
2323 return $res;
2324 }
2325
2326 sub print_smbios1 {
2327 my ($smbios1) = @_;
2328 return PVE::JSONSchema::print_property_string($smbios1, $smbios1_fmt);
2329 }
2330
2331 PVE::JSONSchema::register_format('pve-qm-smbios1', $smbios1_fmt);
2332
2333 PVE::JSONSchema::register_format('pve-qm-bootdisk', \&verify_bootdisk);
2334 sub verify_bootdisk {
2335 my ($value, $noerr) = @_;
2336
2337 return $value if is_valid_drivename($value);
2338
2339 return undef if $noerr;
2340
2341 die "invalid boot disk '$value'\n";
2342 }
2343
2344 sub parse_watchdog {
2345 my ($value) = @_;
2346
2347 return undef if !$value;
2348
2349 my $res = eval { PVE::JSONSchema::parse_property_string($watchdog_fmt, $value) };
2350 warn $@ if $@;
2351 return $res;
2352 }
2353
2354 sub parse_guest_agent {
2355 my ($value) = @_;
2356
2357 return {} if !defined($value->{agent});
2358
2359 my $res = eval { PVE::JSONSchema::parse_property_string($agent_fmt, $value->{agent}) };
2360 warn $@ if $@;
2361
2362 # if the agent is disabled ignore the other potentially set properties
2363 return {} if !$res->{enabled};
2364 return $res;
2365 }
2366
2367 sub parse_vga {
2368 my ($value) = @_;
2369
2370 return {} if !$value;
2371 my $res = eval { PVE::JSONSchema::parse_property_string($vga_fmt, $value) };
2372 warn $@ if $@;
2373 return $res;
2374 }
2375
2376 PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
2377 sub verify_usb_device {
2378 my ($value, $noerr) = @_;
2379
2380 return $value if parse_usb_device($value);
2381
2382 return undef if $noerr;
2383
2384 die "unable to parse usb device\n";
2385 }
2386
2387 # add JSON properties for create and set function
2388 sub json_config_properties {
2389 my $prop = shift;
2390
2391 foreach my $opt (keys %$confdesc) {
2392 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2393 $prop->{$opt} = $confdesc->{$opt};
2394 }
2395
2396 return $prop;
2397 }
2398
2399 # return copy of $confdesc_cloudinit to generate documentation
2400 sub cloudinit_config_properties {
2401
2402 return dclone($confdesc_cloudinit);
2403 }
2404
2405 sub check_type {
2406 my ($key, $value) = @_;
2407
2408 die "unknown setting '$key'\n" if !$confdesc->{$key};
2409
2410 my $type = $confdesc->{$key}->{type};
2411
2412 if (!defined($value)) {
2413 die "got undefined value\n";
2414 }
2415
2416 if ($value =~ m/[\n\r]/) {
2417 die "property contains a line feed\n";
2418 }
2419
2420 if ($type eq 'boolean') {
2421 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2422 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2423 die "type check ('boolean') failed - got '$value'\n";
2424 } elsif ($type eq 'integer') {
2425 return int($1) if $value =~ m/^(\d+)$/;
2426 die "type check ('integer') failed - got '$value'\n";
2427 } elsif ($type eq 'number') {
2428 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2429 die "type check ('number') failed - got '$value'\n";
2430 } elsif ($type eq 'string') {
2431 if (my $fmt = $confdesc->{$key}->{format}) {
2432 PVE::JSONSchema::check_format($fmt, $value);
2433 return $value;
2434 }
2435 $value =~ s/^\"(.*)\"$/$1/;
2436 return $value;
2437 } else {
2438 die "internal error"
2439 }
2440 }
2441
2442 sub check_iommu_support{
2443 #fixme : need to check IOMMU support
2444 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2445
2446 my $iommu=1;
2447 return $iommu;
2448
2449 }
2450
2451 sub touch_config {
2452 my ($vmid) = @_;
2453
2454 my $conf = PVE::QemuConfig->config_file($vmid);
2455 utime undef, undef, $conf;
2456 }
2457
2458 sub destroy_vm {
2459 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2460
2461 my $conffile = PVE::QemuConfig->config_file($vmid);
2462
2463 my $conf = PVE::QemuConfig->load_config($vmid);
2464
2465 PVE::QemuConfig->check_lock($conf) if !$skiplock;
2466
2467 if ($conf->{template}) {
2468 # check if any base image is still used by a linked clone
2469 foreach_drive($conf, sub {
2470 my ($ds, $drive) = @_;
2471
2472 return if drive_is_cdrom($drive);
2473
2474 my $volid = $drive->{file};
2475
2476 return if !$volid || $volid =~ m|^/|;
2477
2478 die "base volume '$volid' is still in use by linked cloned\n"
2479 if PVE::Storage::volume_is_base_and_used($storecfg, $volid);
2480
2481 });
2482 }
2483
2484 # only remove disks owned by this VM
2485 foreach_drive($conf, sub {
2486 my ($ds, $drive) = @_;
2487
2488 return if drive_is_cdrom($drive, 1);
2489
2490 my $volid = $drive->{file};
2491
2492 return if !$volid || $volid =~ m|^/|;
2493
2494 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
2495 return if !$path || !$owner || ($owner != $vmid);
2496
2497 eval {
2498 PVE::Storage::vdisk_free($storecfg, $volid);
2499 };
2500 warn "Could not remove disk '$volid', check manually: $@" if $@;
2501
2502 });
2503
2504 if ($keep_empty_config) {
2505 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
2506 } else {
2507 unlink $conffile;
2508 }
2509
2510 # also remove unused disk
2511 eval {
2512 my $dl = PVE::Storage::vdisk_list($storecfg, undef, $vmid);
2513
2514 eval {
2515 PVE::Storage::foreach_volid($dl, sub {
2516 my ($volid, $sid, $volname, $d) = @_;
2517 PVE::Storage::vdisk_free($storecfg, $volid);
2518 });
2519 };
2520 warn $@ if $@;
2521
2522 };
2523 warn $@ if $@;
2524 }
2525
2526 sub parse_vm_config {
2527 my ($filename, $raw) = @_;
2528
2529 return undef if !defined($raw);
2530
2531 my $res = {
2532 digest => Digest::SHA::sha1_hex($raw),
2533 snapshots => {},
2534 pending => {},
2535 };
2536
2537 $filename =~ m|/qemu-server/(\d+)\.conf$|
2538 || die "got strange filename '$filename'";
2539
2540 my $vmid = $1;
2541
2542 my $conf = $res;
2543 my $descr;
2544 my $section = '';
2545
2546 my @lines = split(/\n/, $raw);
2547 foreach my $line (@lines) {
2548 next if $line =~ m/^\s*$/;
2549
2550 if ($line =~ m/^\[PENDING\]\s*$/i) {
2551 $section = 'pending';
2552 if (defined($descr)) {
2553 $descr =~ s/\s+$//;
2554 $conf->{description} = $descr;
2555 }
2556 $descr = undef;
2557 $conf = $res->{$section} = {};
2558 next;
2559
2560 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2561 $section = $1;
2562 if (defined($descr)) {
2563 $descr =~ s/\s+$//;
2564 $conf->{description} = $descr;
2565 }
2566 $descr = undef;
2567 $conf = $res->{snapshots}->{$section} = {};
2568 next;
2569 }
2570
2571 if ($line =~ m/^\#(.*)\s*$/) {
2572 $descr = '' if !defined($descr);
2573 $descr .= PVE::Tools::decode_text($1) . "\n";
2574 next;
2575 }
2576
2577 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2578 $descr = '' if !defined($descr);
2579 $descr .= PVE::Tools::decode_text($2);
2580 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2581 $conf->{snapstate} = $1;
2582 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2583 my $key = $1;
2584 my $value = $2;
2585 $conf->{$key} = $value;
2586 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2587 my $value = $1;
2588 if ($section eq 'pending') {
2589 $conf->{delete} = $value; # we parse this later
2590 } else {
2591 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2592 }
2593 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2594 my $key = $1;
2595 my $value = $2;
2596 eval { $value = check_type($key, $value); };
2597 if ($@) {
2598 warn "vm $vmid - unable to parse value of '$key' - $@";
2599 } else {
2600 $key = 'ide2' if $key eq 'cdrom';
2601 my $fmt = $confdesc->{$key}->{format};
2602 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2603 my $v = parse_drive($key, $value);
2604 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
2605 $v->{file} = $volid;
2606 $value = print_drive($vmid, $v);
2607 } else {
2608 warn "vm $vmid - unable to parse value of '$key'\n";
2609 next;
2610 }
2611 }
2612
2613 $conf->{$key} = $value;
2614 }
2615 }
2616 }
2617
2618 if (defined($descr)) {
2619 $descr =~ s/\s+$//;
2620 $conf->{description} = $descr;
2621 }
2622 delete $res->{snapstate}; # just to be sure
2623
2624 return $res;
2625 }
2626
2627 sub write_vm_config {
2628 my ($filename, $conf) = @_;
2629
2630 delete $conf->{snapstate}; # just to be sure
2631
2632 if ($conf->{cdrom}) {
2633 die "option ide2 conflicts with cdrom\n" if $conf->{ide2};
2634 $conf->{ide2} = $conf->{cdrom};
2635 delete $conf->{cdrom};
2636 }
2637
2638 # we do not use 'smp' any longer
2639 if ($conf->{sockets}) {
2640 delete $conf->{smp};
2641 } elsif ($conf->{smp}) {
2642 $conf->{sockets} = $conf->{smp};
2643 delete $conf->{cores};
2644 delete $conf->{smp};
2645 }
2646
2647 my $used_volids = {};
2648
2649 my $cleanup_config = sub {
2650 my ($cref, $pending, $snapname) = @_;
2651
2652 foreach my $key (keys %$cref) {
2653 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2654 $key eq 'snapstate' || $key eq 'pending';
2655 my $value = $cref->{$key};
2656 if ($key eq 'delete') {
2657 die "propertry 'delete' is only allowed in [PENDING]\n"
2658 if !$pending;
2659 # fixme: check syntax?
2660 next;
2661 }
2662 eval { $value = check_type($key, $value); };
2663 die "unable to parse value of '$key' - $@" if $@;
2664
2665 $cref->{$key} = $value;
2666
2667 if (!$snapname && is_valid_drivename($key)) {
2668 my $drive = parse_drive($key, $value);
2669 $used_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
2670 }
2671 }
2672 };
2673
2674 &$cleanup_config($conf);
2675
2676 &$cleanup_config($conf->{pending}, 1);
2677
2678 foreach my $snapname (keys %{$conf->{snapshots}}) {
2679 die "internal error" if $snapname eq 'pending';
2680 &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
2681 }
2682
2683 # remove 'unusedX' settings if we re-add a volume
2684 foreach my $key (keys %$conf) {
2685 my $value = $conf->{$key};
2686 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2687 delete $conf->{$key};
2688 }
2689 }
2690
2691 my $generate_raw_config = sub {
2692 my ($conf, $pending) = @_;
2693
2694 my $raw = '';
2695
2696 # add description as comment to top of file
2697 if (defined(my $descr = $conf->{description})) {
2698 if ($descr) {
2699 foreach my $cl (split(/\n/, $descr)) {
2700 $raw .= '#' . PVE::Tools::encode_text($cl) . "\n";
2701 }
2702 } else {
2703 $raw .= "#\n" if $pending;
2704 }
2705 }
2706
2707 foreach my $key (sort keys %$conf) {
2708 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2709 $raw .= "$key: $conf->{$key}\n";
2710 }
2711 return $raw;
2712 };
2713
2714 my $raw = &$generate_raw_config($conf);
2715
2716 if (scalar(keys %{$conf->{pending}})){
2717 $raw .= "\n[PENDING]\n";
2718 $raw .= &$generate_raw_config($conf->{pending}, 1);
2719 }
2720
2721 foreach my $snapname (sort keys %{$conf->{snapshots}}) {
2722 $raw .= "\n[$snapname]\n";
2723 $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
2724 }
2725
2726 return $raw;
2727 }
2728
2729 sub load_defaults {
2730
2731 my $res = {};
2732
2733 # we use static defaults from our JSON schema configuration
2734 foreach my $key (keys %$confdesc) {
2735 if (defined(my $default = $confdesc->{$key}->{default})) {
2736 $res->{$key} = $default;
2737 }
2738 }
2739
2740 return $res;
2741 }
2742
2743 sub config_list {
2744 my $vmlist = PVE::Cluster::get_vmlist();
2745 my $res = {};
2746 return $res if !$vmlist || !$vmlist->{ids};
2747 my $ids = $vmlist->{ids};
2748
2749 foreach my $vmid (keys %$ids) {
2750 my $d = $ids->{$vmid};
2751 next if !$d->{node} || $d->{node} ne $nodename;
2752 next if !$d->{type} || $d->{type} ne 'qemu';
2753 $res->{$vmid}->{exists} = 1;
2754 }
2755 return $res;
2756 }
2757
2758 # test if VM uses local resources (to prevent migration)
2759 sub check_local_resources {
2760 my ($conf, $noerr) = @_;
2761
2762 my $loc_res = 0;
2763
2764 $loc_res = 1 if $conf->{hostusb}; # old syntax
2765 $loc_res = 1 if $conf->{hostpci}; # old syntax
2766
2767 foreach my $k (keys %$conf) {
2768 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2769 # sockets are safe: they will recreated be on the target side post-migrate
2770 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2771 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2772 }
2773
2774 die "VM uses local resources\n" if $loc_res && !$noerr;
2775
2776 return $loc_res;
2777 }
2778
2779 # check if used storages are available on all nodes (use by migrate)
2780 sub check_storage_availability {
2781 my ($storecfg, $conf, $node) = @_;
2782
2783 foreach_drive($conf, sub {
2784 my ($ds, $drive) = @_;
2785
2786 my $volid = $drive->{file};
2787 return if !$volid;
2788
2789 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2790 return if !$sid;
2791
2792 # check if storage is available on both nodes
2793 my $scfg = PVE::Storage::storage_check_node($storecfg, $sid);
2794 PVE::Storage::storage_check_node($storecfg, $sid, $node);
2795 });
2796 }
2797
2798 # list nodes where all VM images are available (used by has_feature API)
2799 sub shared_nodes {
2800 my ($conf, $storecfg) = @_;
2801
2802 my $nodelist = PVE::Cluster::get_nodelist();
2803 my $nodehash = { map { $_ => 1 } @$nodelist };
2804 my $nodename = PVE::INotify::nodename();
2805
2806 foreach_drive($conf, sub {
2807 my ($ds, $drive) = @_;
2808
2809 my $volid = $drive->{file};
2810 return if !$volid;
2811
2812 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2813 if ($storeid) {
2814 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2815 if ($scfg->{disable}) {
2816 $nodehash = {};
2817 } elsif (my $avail = $scfg->{nodes}) {
2818 foreach my $node (keys %$nodehash) {
2819 delete $nodehash->{$node} if !$avail->{$node};
2820 }
2821 } elsif (!$scfg->{shared}) {
2822 foreach my $node (keys %$nodehash) {
2823 delete $nodehash->{$node} if $node ne $nodename
2824 }
2825 }
2826 }
2827 });
2828
2829 return $nodehash
2830 }
2831
2832 sub check_cmdline {
2833 my ($pidfile, $pid) = @_;
2834
2835 my $fh = IO::File->new("/proc/$pid/cmdline", "r");
2836 if (defined($fh)) {
2837 my $line = <$fh>;
2838 $fh->close;
2839 return undef if !$line;
2840 my @param = split(/\0/, $line);
2841
2842 my $cmd = $param[0];
2843 return if !$cmd || ($cmd !~ m|kvm$| && $cmd !~ m@(?:^|/)qemu-system-[^/]+$@);
2844
2845 for (my $i = 0; $i < scalar (@param); $i++) {
2846 my $p = $param[$i];
2847 next if !$p;
2848 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2849 my $p = $param[$i+1];
2850 return 1 if $p && ($p eq $pidfile);
2851 return undef;
2852 }
2853 }
2854 }
2855 return undef;
2856 }
2857
2858 sub check_running {
2859 my ($vmid, $nocheck, $node) = @_;
2860
2861 my $filename = PVE::QemuConfig->config_file($vmid, $node);
2862
2863 die "unable to find configuration file for VM $vmid - no such machine\n"
2864 if !$nocheck && ! -f $filename;
2865
2866 my $pidfile = pidfile_name($vmid);
2867
2868 if (my $fd = IO::File->new("<$pidfile")) {
2869 my $st = stat($fd);
2870 my $line = <$fd>;
2871 close($fd);
2872
2873 my $mtime = $st->mtime;
2874 if ($mtime > time()) {
2875 warn "file '$filename' modified in future\n";
2876 }
2877
2878 if ($line =~ m/^(\d+)$/) {
2879 my $pid = $1;
2880 if (check_cmdline($pidfile, $pid)) {
2881 if (my $pinfo = PVE::ProcFSTools::check_process_running($pid)) {
2882 return $pid;
2883 }
2884 }
2885 }
2886 }
2887
2888 return undef;
2889 }
2890
2891 sub vzlist {
2892
2893 my $vzlist = config_list();
2894
2895 my $fd = IO::Dir->new($var_run_tmpdir) || return $vzlist;
2896
2897 while (defined(my $de = $fd->read)) {
2898 next if $de !~ m/^(\d+)\.pid$/;
2899 my $vmid = $1;
2900 next if !defined($vzlist->{$vmid});
2901 if (my $pid = check_running($vmid)) {
2902 $vzlist->{$vmid}->{pid} = $pid;
2903 }
2904 }
2905
2906 return $vzlist;
2907 }
2908
2909 sub disksize {
2910 my ($storecfg, $conf) = @_;
2911
2912 my $bootdisk = $conf->{bootdisk};
2913 return undef if !$bootdisk;
2914 return undef if !is_valid_drivename($bootdisk);
2915
2916 return undef if !$conf->{$bootdisk};
2917
2918 my $drive = parse_drive($bootdisk, $conf->{$bootdisk});
2919 return undef if !defined($drive);
2920
2921 return undef if drive_is_cdrom($drive);
2922
2923 my $volid = $drive->{file};
2924 return undef if !$volid;
2925
2926 return $drive->{size};
2927 }
2928
2929 our $vmstatus_return_properties = {
2930 vmid => get_standard_option('pve-vmid'),
2931 status => {
2932 description => "Qemu process status.",
2933 type => 'string',
2934 enum => ['stopped', 'running'],
2935 },
2936 maxmem => {
2937 description => "Maximum memory in bytes.",
2938 type => 'integer',
2939 optional => 1,
2940 renderer => 'bytes',
2941 },
2942 maxdisk => {
2943 description => "Root disk size in bytes.",
2944 type => 'integer',
2945 optional => 1,
2946 renderer => 'bytes',
2947 },
2948 name => {
2949 description => "VM name.",
2950 type => 'string',
2951 optional => 1,
2952 },
2953 qmpstatus => {
2954 description => "Qemu QMP agent status.",
2955 type => 'string',
2956 optional => 1,
2957 },
2958 pid => {
2959 description => "PID of running qemu process.",
2960 type => 'integer',
2961 optional => 1,
2962 },
2963 uptime => {
2964 description => "Uptime.",
2965 type => 'integer',
2966 optional => 1,
2967 renderer => 'duration',
2968 },
2969 cpus => {
2970 description => "Maximum usable CPUs.",
2971 type => 'number',
2972 optional => 1,
2973 },
2974 };
2975
2976 my $last_proc_pid_stat;
2977
2978 # get VM status information
2979 # This must be fast and should not block ($full == false)
2980 # We only query KVM using QMP if $full == true (this can be slow)
2981 sub vmstatus {
2982 my ($opt_vmid, $full) = @_;
2983
2984 my $res = {};
2985
2986 my $storecfg = PVE::Storage::config();
2987
2988 my $list = vzlist();
2989 my $defaults = load_defaults();
2990
2991 my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
2992
2993 my $cpucount = $cpuinfo->{cpus} || 1;
2994
2995 foreach my $vmid (keys %$list) {
2996 next if $opt_vmid && ($vmid ne $opt_vmid);
2997
2998 my $cfspath = PVE::QemuConfig->cfs_config_path($vmid);
2999 my $conf = PVE::Cluster::cfs_read_file($cfspath) || {};
3000
3001 my $d = { vmid => $vmid };
3002 $d->{pid} = $list->{$vmid}->{pid};
3003
3004 # fixme: better status?
3005 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
3006
3007 my $size = disksize($storecfg, $conf);
3008 if (defined($size)) {
3009 $d->{disk} = 0; # no info available
3010 $d->{maxdisk} = $size;
3011 } else {
3012 $d->{disk} = 0;
3013 $d->{maxdisk} = 0;
3014 }
3015
3016 $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
3017 * ($conf->{cores} || $defaults->{cores});
3018 $d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
3019 $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
3020
3021 $d->{name} = $conf->{name} || "VM $vmid";
3022 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
3023 : $defaults->{memory}*(1024*1024);
3024
3025 if ($conf->{balloon}) {
3026 $d->{balloon_min} = $conf->{balloon}*(1024*1024);
3027 $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
3028 : $defaults->{shares};
3029 }
3030
3031 $d->{uptime} = 0;
3032 $d->{cpu} = 0;
3033 $d->{mem} = 0;
3034
3035 $d->{netout} = 0;
3036 $d->{netin} = 0;
3037
3038 $d->{diskread} = 0;
3039 $d->{diskwrite} = 0;
3040
3041 $d->{template} = PVE::QemuConfig->is_template($conf);
3042
3043 $d->{serial} = 1 if conf_has_serial($conf);
3044
3045 $res->{$vmid} = $d;
3046 }
3047
3048 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
3049 foreach my $dev (keys %$netdev) {
3050 next if $dev !~ m/^tap([1-9]\d*)i/;
3051 my $vmid = $1;
3052 my $d = $res->{$vmid};
3053 next if !$d;
3054
3055 $d->{netout} += $netdev->{$dev}->{receive};
3056 $d->{netin} += $netdev->{$dev}->{transmit};
3057
3058 if ($full) {
3059 $d->{nics}->{$dev}->{netout} = $netdev->{$dev}->{receive};
3060 $d->{nics}->{$dev}->{netin} = $netdev->{$dev}->{transmit};
3061 }
3062
3063 }
3064
3065 my $ctime = gettimeofday;
3066
3067 foreach my $vmid (keys %$list) {
3068
3069 my $d = $res->{$vmid};
3070 my $pid = $d->{pid};
3071 next if !$pid;
3072
3073 my $pstat = PVE::ProcFSTools::read_proc_pid_stat($pid);
3074 next if !$pstat; # not running
3075
3076 my $used = $pstat->{utime} + $pstat->{stime};
3077
3078 $d->{uptime} = int(($uptime - $pstat->{starttime})/$cpuinfo->{user_hz});
3079
3080 if ($pstat->{vsize}) {
3081 $d->{mem} = int(($pstat->{rss}/$pstat->{vsize})*$d->{maxmem});
3082 }
3083
3084 my $old = $last_proc_pid_stat->{$pid};
3085 if (!$old) {
3086 $last_proc_pid_stat->{$pid} = {
3087 time => $ctime,
3088 used => $used,
3089 cpu => 0,
3090 };
3091 next;
3092 }
3093
3094 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz};
3095
3096 if ($dtime > 1000) {
3097 my $dutime = $used - $old->{used};
3098
3099 $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
3100 $last_proc_pid_stat->{$pid} = {
3101 time => $ctime,
3102 used => $used,
3103 cpu => $d->{cpu},
3104 };
3105 } else {
3106 $d->{cpu} = $old->{cpu};
3107 }
3108 }
3109
3110 return $res if !$full;
3111
3112 my $qmpclient = PVE::QMPClient->new();
3113
3114 my $ballooncb = sub {
3115 my ($vmid, $resp) = @_;
3116
3117 my $info = $resp->{'return'};
3118 return if !$info->{max_mem};
3119
3120 my $d = $res->{$vmid};
3121
3122 # use memory assigned to VM
3123 $d->{maxmem} = $info->{max_mem};
3124 $d->{balloon} = $info->{actual};
3125
3126 if (defined($info->{total_mem}) && defined($info->{free_mem})) {
3127 $d->{mem} = $info->{total_mem} - $info->{free_mem};
3128 $d->{freemem} = $info->{free_mem};
3129 }
3130
3131 $d->{ballooninfo} = $info;
3132 };
3133
3134 my $blockstatscb = sub {
3135 my ($vmid, $resp) = @_;
3136 my $data = $resp->{'return'} || [];
3137 my $totalrdbytes = 0;
3138 my $totalwrbytes = 0;
3139
3140 for my $blockstat (@$data) {
3141 $totalrdbytes = $totalrdbytes + $blockstat->{stats}->{rd_bytes};
3142 $totalwrbytes = $totalwrbytes + $blockstat->{stats}->{wr_bytes};
3143
3144 $blockstat->{device} =~ s/drive-//;
3145 $res->{$vmid}->{blockstat}->{$blockstat->{device}} = $blockstat->{stats};
3146 }
3147 $res->{$vmid}->{diskread} = $totalrdbytes;
3148 $res->{$vmid}->{diskwrite} = $totalwrbytes;
3149 };
3150
3151 my $statuscb = sub {
3152 my ($vmid, $resp) = @_;
3153
3154 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3155 # this fails if ballon driver is not loaded, so this must be
3156 # the last commnand (following command are aborted if this fails).
3157 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3158
3159 my $status = 'unknown';
3160 if (!defined($status = $resp->{'return'}->{status})) {
3161 warn "unable to get VM status\n";
3162 return;
3163 }
3164
3165 $res->{$vmid}->{qmpstatus} = $resp->{'return'}->{status};
3166 };
3167
3168 foreach my $vmid (keys %$list) {
3169 next if $opt_vmid && ($vmid ne $opt_vmid);
3170 next if !$res->{$vmid}->{pid}; # not running
3171 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3172 }
3173
3174 $qmpclient->queue_execute(undef, 2);
3175
3176 foreach my $vmid (keys %$list) {
3177 next if $opt_vmid && ($vmid ne $opt_vmid);
3178 $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
3179 }
3180
3181 return $res;
3182 }
3183
3184 sub foreach_drive {
3185 my ($conf, $func, @param) = @_;
3186
3187 foreach my $ds (valid_drive_names()) {
3188 next if !defined($conf->{$ds});
3189
3190 my $drive = parse_drive($ds, $conf->{$ds});
3191 next if !$drive;
3192
3193 &$func($ds, $drive, @param);
3194 }
3195 }
3196
3197 sub foreach_volid {
3198 my ($conf, $func, @param) = @_;
3199
3200 my $volhash = {};
3201
3202 my $test_volid = sub {
3203 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3204
3205 return if !$volid;
3206
3207 $volhash->{$volid}->{cdrom} //= 1;
3208 $volhash->{$volid}->{cdrom} = 0 if !$is_cdrom;
3209
3210 $volhash->{$volid}->{replicate} //= 0;
3211 $volhash->{$volid}->{replicate} = 1 if $replicate;
3212
3213 $volhash->{$volid}->{shared} //= 0;
3214 $volhash->{$volid}->{shared} = 1 if $shared;
3215
3216 $volhash->{$volid}->{referenced_in_config} //= 0;
3217 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
3218
3219 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
3220 if defined($snapname);
3221 };
3222
3223 foreach_drive($conf, sub {
3224 my ($ds, $drive) = @_;
3225 $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, undef);
3226 });
3227
3228 foreach my $snapname (keys %{$conf->{snapshots}}) {
3229 my $snap = $conf->{snapshots}->{$snapname};
3230 $test_volid->($snap->{vmstate}, 0, 1, $snapname);
3231 foreach_drive($snap, sub {
3232 my ($ds, $drive) = @_;
3233 $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, $snapname);
3234 });
3235 }
3236
3237 foreach my $volid (keys %$volhash) {
3238 &$func($volid, $volhash->{$volid}, @param);
3239 }
3240 }
3241
3242 sub conf_has_serial {
3243 my ($conf) = @_;
3244
3245 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3246 if ($conf->{"serial$i"}) {
3247 return 1;
3248 }
3249 }
3250
3251 return 0;
3252 }
3253
3254 sub vga_conf_has_spice {
3255 my ($vga) = @_;
3256
3257 my $vgaconf = parse_vga($vga);
3258 my $vgatype = $vgaconf->{type};
3259 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3260
3261 return $1 || 1;
3262 }
3263
3264 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3265 sub get_host_arch() {
3266 $host_arch = (POSIX::uname())[4] if !$host_arch;
3267 return $host_arch;
3268 }
3269
3270 sub is_native($) {
3271 my ($arch) = @_;
3272 return get_host_arch() eq $arch;
3273 }
3274
3275 my $default_machines = {
3276 x86_64 => 'pc',
3277 aarch64 => 'virt',
3278 };
3279
3280 sub get_basic_machine_info {
3281 my ($conf, $forcemachine) = @_;
3282
3283 my $arch = $conf->{arch} // get_host_arch();
3284 my $machine = $forcemachine || $conf->{machine} || $default_machines->{$arch};
3285 return ($arch, $machine);
3286 }
3287
3288 sub get_ovmf_files($) {
3289 my ($arch) = @_;
3290
3291 my $ovmf = $OVMF->{$arch}
3292 or die "no OVMF images known for architecture '$arch'\n";
3293
3294 return @$ovmf;
3295 }
3296
3297 my $Arch2Qemu = {
3298 aarch64 => '/usr/bin/qemu-system-aarch64',
3299 x86_64 => '/usr/bin/qemu-system-x86_64',
3300 };
3301 sub get_command_for_arch($) {
3302 my ($arch) = @_;
3303 return '/usr/bin/kvm' if is_native($arch);
3304
3305 my $cmd = $Arch2Qemu->{$arch}
3306 or die "don't know how to emulate architecture '$arch'\n";
3307 return $cmd;
3308 }
3309
3310 sub get_cpu_options {
3311 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3312
3313 my $cpuFlags = [];
3314 my $ostype = $conf->{ostype};
3315
3316 my $cpu = $kvm ? "kvm64" : "qemu64";
3317 if ($arch eq 'aarch64') {
3318 $cpu = 'cortex-a57';
3319 }
3320 if (my $cputype = $conf->{cpu}) {
3321 my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
3322 or die "Cannot parse cpu description: $cputype\n";
3323 $cpu = $cpuconf->{cputype};
3324 $kvm_off = 1 if $cpuconf->{hidden};
3325
3326 if (defined(my $flags = $cpuconf->{flags})) {
3327 push @$cpuFlags, split(";", $flags);
3328 }
3329 }
3330
3331 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3332
3333 push @$cpuFlags , '-x2apic'
3334 if $conf->{ostype} && $conf->{ostype} eq 'solaris';
3335
3336 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3337
3338 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3339
3340 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
3341
3342 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3343 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3344 }
3345
3346 add_hyperv_enlightenments($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios}, $gpu_passthrough) if $kvm;
3347
3348 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3349
3350 push @$cpuFlags, 'kvm=off' if $kvm_off;
3351
3352 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3353 push @$cpuFlags, "vendor=${cpu_vendor}"
3354 if $cpu_vendor ne 'default';
3355 } elsif ($arch ne 'aarch64') {
3356 die "internal error"; # should not happen
3357 }
3358
3359 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3360
3361 return ('-cpu', $cpu);
3362 }
3363
3364 sub config_to_command {
3365 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3366
3367 my $cmd = [];
3368 my $globalFlags = [];
3369 my $machineFlags = [];
3370 my $rtcFlags = [];
3371 my $devices = [];
3372 my $pciaddr = '';
3373 my $bridges = {};
3374 my $kvmver = kvm_user_version();
3375 my $vernum = 0; # unknown
3376 my $ostype = $conf->{ostype};
3377 my $winversion = windows_version($ostype);
3378 my $kvm = $conf->{kvm};
3379
3380 my ($arch, $machine_type) = get_basic_machine_info($conf, $forcemachine);
3381 $kvm //= 1 if is_native($arch);
3382
3383 if ($kvm) {
3384 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3385 if !defined kvm_version();
3386 }
3387
3388 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3389 $vernum = $1*1000000+$2*1000;
3390 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3391 $vernum = $1*1000000+$2*1000+$3;
3392 }
3393
3394 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3395
3396 my $have_ovz = -f '/proc/vz/vestat';
3397
3398 my $q35 = machine_type_is_q35($conf);
3399 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
3400 my $use_old_bios_files = undef;
3401 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
3402
3403 my $cpuunits = defined($conf->{cpuunits}) ?
3404 $conf->{cpuunits} : $defaults->{cpuunits};
3405
3406 push @$cmd, get_command_for_arch($arch);
3407
3408 push @$cmd, '-id', $vmid;
3409
3410 my $vmname = $conf->{name} || "vm$vmid";
3411
3412 push @$cmd, '-name', $vmname;
3413
3414 my $use_virtio = 0;
3415
3416 my $qmpsocket = qmp_socket($vmid);
3417 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3418 push @$cmd, '-mon', "chardev=qmp,mode=control";
3419
3420 if (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 12)) {
3421 my $eventsocket = qmp_socket($vmid, 0, 'event');
3422 push @$cmd, '-chardev', "socket,id=qmp-event,path=$eventsocket,server,nowait";
3423 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3424 }
3425
3426 push @$cmd, '-pidfile' , pidfile_name($vmid);
3427
3428 push @$cmd, '-daemonize';
3429
3430 if ($conf->{smbios1}) {
3431 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3432 }
3433
3434 if ($conf->{vmgenid}) {
3435 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid};
3436 }
3437
3438 my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch);
3439 if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
3440 die "uefi base image not found\n" if ! -f $ovmf_code;
3441
3442 my $path;
3443 my $format;
3444 if (my $efidisk = $conf->{efidisk0}) {
3445 my $d = PVE::JSONSchema::parse_property_string($efidisk_fmt, $efidisk);
3446 my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
3447 $format = $d->{format};
3448 if ($storeid) {
3449 $path = PVE::Storage::path($storecfg, $d->{file});
3450 if (!defined($format)) {
3451 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
3452 $format = qemu_img_format($scfg, $volname);
3453 }
3454 } else {
3455 $path = $d->{file};
3456 die "efidisk format must be specified\n"
3457 if !defined($format);
3458 }
3459 } else {
3460 warn "no efidisk configured! Using temporary efivars disk.\n";
3461 $path = "/tmp/$vmid-ovmf.fd";
3462 PVE::Tools::file_copy($ovmf_vars, $path, -s $ovmf_vars);
3463 $format = 'raw';
3464 }
3465
3466 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3467 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3468 }
3469
3470
3471 # add usb controllers
3472 my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $q35, $usbdesc->{format}, $MAX_USB_DEVICES);
3473 push @$devices, @usbcontrollers if @usbcontrollers;
3474 my $vga = parse_vga($conf->{vga});
3475
3476 my $qxlnum = vga_conf_has_spice($conf->{vga});
3477 $vga->{type} = 'qxl' if $qxlnum;
3478
3479 if (!$vga->{type}) {
3480 if (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 9)) {
3481 $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
3482 } else {
3483 $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
3484 }
3485 }
3486
3487 # enable absolute mouse coordinates (needed by vnc)
3488 my $tablet;
3489 if (defined($conf->{tablet})) {
3490 $tablet = $conf->{tablet};
3491 } else {
3492 $tablet = $defaults->{tablet};
3493 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3494 $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3495 }
3496
3497 push @$devices, '-device', print_tabletdevice_full($conf) if $tablet;
3498
3499 my $kvm_off = 0;
3500 my $gpu_passthrough;
3501
3502 # host pci devices
3503 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3504 my $d = parse_hostpci($conf->{"hostpci$i"});
3505 next if !$d;
3506
3507 my $pcie = $d->{pcie};
3508 if($pcie){
3509 die "q35 machine model is not enabled" if !$q35;
3510 $pciaddr = print_pcie_addr("hostpci$i");
3511 }else{
3512 $pciaddr = print_pci_addr("hostpci$i", $bridges);
3513 }
3514
3515 my $rombar = defined($d->{rombar}) && !$d->{rombar} ? ',rombar=0' : '';
3516 my $romfile = $d->{romfile};
3517
3518 my $xvga = '';
3519 if ($d->{'x-vga'}) {
3520 $xvga = ',x-vga=on';
3521 $kvm_off = 1;
3522 $vga->{type} = 'none';
3523 $gpu_passthrough = 1;
3524
3525 if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
3526 $xvga = "";
3527 }
3528 }
3529 my $pcidevices = $d->{pciid};
3530 my $multifunction = 1 if @$pcidevices > 1;
3531
3532 my $j=0;
3533 foreach my $pcidevice (@$pcidevices) {
3534
3535 my $id = "hostpci$i";
3536 $id .= ".$j" if $multifunction;
3537 my $addr = $pciaddr;
3538 $addr .= ".$j" if $multifunction;
3539 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3540
3541 if($j == 0){
3542 $devicestr .= "$rombar$xvga";
3543 $devicestr .= ",multifunction=on" if $multifunction;
3544 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3545 }
3546
3547 push @$devices, '-device', $devicestr;
3548 $j++;
3549 }
3550 }
3551
3552 # usb devices
3553 my @usbdevices = PVE::QemuServer::USB::get_usb_devices($conf, $usbdesc->{format}, $MAX_USB_DEVICES);
3554 push @$devices, @usbdevices if @usbdevices;
3555 # serial devices
3556 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3557 if (my $path = $conf->{"serial$i"}) {
3558 if ($path eq 'socket') {
3559 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3560 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3561 push @$devices, '-device', "isa-serial,chardev=serial$i";
3562 } else {
3563 die "no such serial device\n" if ! -c $path;
3564 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3565 push @$devices, '-device', "isa-serial,chardev=serial$i";
3566 }
3567 }
3568 }
3569
3570 # parallel devices
3571 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3572 if (my $path = $conf->{"parallel$i"}) {
3573 die "no such parallel device\n" if ! -c $path;
3574 my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
3575 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3576 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3577 }
3578 }
3579
3580
3581 my $sockets = 1;
3582 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3583 $sockets = $conf->{sockets} if $conf->{sockets};
3584
3585 my $cores = $conf->{cores} || 1;
3586
3587 my $maxcpus = $sockets * $cores;
3588
3589 my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
3590
3591 my $allowed_vcpus = $cpuinfo->{cpus};
3592
3593 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3594 if ($allowed_vcpus < $maxcpus);
3595
3596 if($hotplug_features->{cpu} && qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 7)) {
3597
3598 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3599 for (my $i = 2; $i <= $vcpus; $i++) {
3600 my $cpustr = print_cpu_device($conf,$i);
3601 push @$cmd, '-device', $cpustr;
3602 }
3603
3604 } else {
3605
3606 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3607 }
3608 push @$cmd, '-nodefaults';
3609
3610 my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
3611
3612 my $bootindex_hash = {};
3613 my $i = 1;
3614 foreach my $o (split(//, $bootorder)) {
3615 $bootindex_hash->{$o} = $i*100;
3616 $i++;
3617 }
3618
3619 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3620
3621 push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
3622
3623 push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
3624
3625 if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
3626 push @$devices, '-device', print_vga_device($conf, $vga, undef, $qxlnum, $bridges);
3627 my $socket = vnc_socket($vmid);
3628 push @$cmd, '-vnc', "unix:$socket,x509,password";
3629 } else {
3630 push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
3631 push @$cmd, '-nographic';
3632 }
3633
3634 # time drift fix
3635 my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
3636
3637 my $useLocaltime = $conf->{localtime};
3638
3639 if ($winversion >= 5) { # windows
3640 $useLocaltime = 1 if !defined($conf->{localtime});
3641
3642 # use time drift fix when acpi is enabled
3643 if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3644 $tdf = 1 if !defined($conf->{tdf});
3645 }
3646 }
3647
3648 if ($winversion >= 6) {
3649 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3650 push @$cmd, '-no-hpet';
3651 }
3652
3653 push @$rtcFlags, 'driftfix=slew' if $tdf;
3654
3655 if (!$kvm) {
3656 push @$machineFlags, 'accel=tcg';
3657 }
3658
3659 if ($machine_type) {
3660 push @$machineFlags, "type=${machine_type}";
3661 }
3662
3663 if ($conf->{startdate}) {
3664 push @$rtcFlags, "base=$conf->{startdate}";
3665 } elsif ($useLocaltime) {
3666 push @$rtcFlags, 'base=localtime';
3667 }
3668
3669 push @$cmd, get_cpu_options($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3670
3671 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3672
3673 push @$cmd, '-S' if $conf->{freeze};
3674
3675 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
3676
3677 # enable sound
3678 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3679 #push @$cmd, '-soundhw', 'es1370';
3680 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3681
3682 if (parse_guest_agent($conf)->{enabled}) {
3683 my $qgasocket = qmp_socket($vmid, 1);
3684 my $pciaddr = print_pci_addr("qga0", $bridges);
3685 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3686 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3687 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3688 }
3689
3690 my $spice_port;
3691
3692 if ($qxlnum) {
3693 if ($qxlnum > 1) {
3694 if ($winversion){
3695 for(my $i = 1; $i < $qxlnum; $i++){
3696 push @$devices, '-device', print_vga_device($conf, $vga, $i, $qxlnum, $bridges);
3697 }
3698 } else {
3699 # assume other OS works like Linux
3700 my ($ram, $vram) = ("134217728", "67108864");
3701 if ($vga->{memory}) {
3702 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
3703 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
3704 }
3705 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3706 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3707 }
3708 }
3709
3710 my $pciaddr = print_pci_addr("spice", $bridges);
3711
3712 my $nodename = PVE::INotify::nodename();
3713 my $pfamily = PVE::Tools::get_host_address_family($nodename);
3714 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
3715 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3716 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
3717 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
3718
3719 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3720
3721 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3722 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3723 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3724 }
3725
3726 # enable balloon by default, unless explicitly disabled
3727 if (!defined($conf->{balloon}) || $conf->{balloon}) {
3728 $pciaddr = print_pci_addr("balloon0", $bridges);
3729 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3730 }
3731
3732 if ($conf->{watchdog}) {
3733 my $wdopts = parse_watchdog($conf->{watchdog});
3734 $pciaddr = print_pci_addr("watchdog", $bridges);
3735 my $watchdog = $wdopts->{model} || 'i6300esb';
3736 push @$devices, '-device', "$watchdog$pciaddr";
3737 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
3738 }
3739
3740 my $vollist = [];
3741 my $scsicontroller = {};
3742 my $ahcicontroller = {};
3743 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
3744
3745 # Add iscsi initiator name if available
3746 if (my $initiator = get_initiator_name()) {
3747 push @$devices, '-iscsi', "initiator-name=$initiator";
3748 }
3749
3750 foreach_drive($conf, sub {
3751 my ($ds, $drive) = @_;
3752
3753 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
3754 push @$vollist, $drive->{file};
3755 }
3756
3757 # ignore efidisk here, already added in bios/fw handling code above
3758 return if $drive->{interface} eq 'efidisk';
3759
3760 $use_virtio = 1 if $ds =~ m/^virtio/;
3761
3762 if (drive_is_cdrom ($drive)) {
3763 if ($bootindex_hash->{d}) {
3764 $drive->{bootindex} = $bootindex_hash->{d};
3765 $bootindex_hash->{d} += 1;
3766 }
3767 } else {
3768 if ($bootindex_hash->{c}) {
3769 $drive->{bootindex} = $bootindex_hash->{c} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
3770 $bootindex_hash->{c} += 1;
3771 }
3772 }
3773
3774 if($drive->{interface} eq 'virtio'){
3775 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
3776 }
3777
3778 if ($drive->{interface} eq 'scsi') {
3779
3780 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
3781
3782 $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges);
3783 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
3784
3785 my $iothread = '';
3786 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
3787 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3788 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3789 } elsif ($drive->{iothread}) {
3790 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3791 }
3792
3793 my $queues = '';
3794 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
3795 $queues = ",num_queues=$drive->{queues}";
3796 }
3797
3798 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3799 $scsicontroller->{$controller}=1;
3800 }
3801
3802 if ($drive->{interface} eq 'sata') {
3803 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3804 $pciaddr = print_pci_addr("ahci$controller", $bridges);
3805 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3806 $ahcicontroller->{$controller}=1;
3807 }
3808
3809 my $drive_cmd = print_drive_full($storecfg, $vmid, $drive);
3810 push @$devices, '-drive',$drive_cmd;
3811 push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges);
3812 });
3813
3814 for (my $i = 0; $i < $MAX_NETS; $i++) {
3815 next if !$conf->{"net$i"};
3816 my $d = parse_net($conf->{"net$i"});
3817 next if !$d;
3818
3819 $use_virtio = 1 if $d->{model} eq 'virtio';
3820
3821 if ($bootindex_hash->{n}) {
3822 $d->{bootindex} = $bootindex_hash->{n};
3823 $bootindex_hash->{n} += 1;
3824 }
3825
3826 my $netdevfull = print_netdev_full($vmid,$conf,$d,"net$i");
3827 push @$devices, '-netdev', $netdevfull;
3828
3829 my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3830 push @$devices, '-device', $netdevicefull;
3831 }
3832
3833 if (!$q35) {
3834 # add pci bridges
3835 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
3836 $bridges->{1} = 1;
3837 $bridges->{2} = 1;
3838 }
3839
3840 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3841
3842 while (my ($k, $v) = each %$bridges) {
3843 $pciaddr = print_pci_addr("pci.$k");
3844 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3845 }
3846 }
3847
3848 # add custom args
3849 if ($conf->{args}) {
3850 my $aa = PVE::Tools::split_args($conf->{args});
3851 push @$cmd, @$aa;
3852 }
3853
3854 push @$cmd, @$devices;
3855 push @$cmd, '-rtc', join(',', @$rtcFlags)
3856 if scalar(@$rtcFlags);
3857 push @$cmd, '-machine', join(',', @$machineFlags)
3858 if scalar(@$machineFlags);
3859 push @$cmd, '-global', join(',', @$globalFlags)
3860 if scalar(@$globalFlags);
3861
3862 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
3863 }
3864
3865 sub vnc_socket {
3866 my ($vmid) = @_;
3867 return "${var_run_tmpdir}/$vmid.vnc";
3868 }
3869
3870 sub spice_port {
3871 my ($vmid) = @_;
3872
3873 my $res = vm_mon_cmd($vmid, 'query-spice');
3874
3875 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3876 }
3877
3878 sub qmp_socket {
3879 my ($vmid, $qga, $name) = @_;
3880 my $sockettype = $qga ? 'qga' : 'qmp';
3881 my $ext = $name ? '-'.$name : '';
3882 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3883 }
3884
3885 sub pidfile_name {
3886 my ($vmid) = @_;
3887 return "${var_run_tmpdir}/$vmid.pid";
3888 }
3889
3890 sub vm_devices_list {
3891 my ($vmid) = @_;
3892
3893 my $res = vm_mon_cmd($vmid, 'query-pci');
3894 my $devices_to_check = [];
3895 my $devices = {};
3896 foreach my $pcibus (@$res) {
3897 push @$devices_to_check, @{$pcibus->{devices}},
3898 }
3899
3900 while (@$devices_to_check) {
3901 my $to_check = [];
3902 for my $d (@$devices_to_check) {
3903 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3904 next if !$d->{'pci_bridge'};
3905
3906 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
3907 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
3908 }
3909 $devices_to_check = $to_check;
3910 }
3911
3912 my $resblock = vm_mon_cmd($vmid, 'query-block');
3913 foreach my $block (@$resblock) {
3914 if($block->{device} =~ m/^drive-(\S+)/){
3915 $devices->{$1} = 1;
3916 }
3917 }
3918
3919 my $resmice = vm_mon_cmd($vmid, 'query-mice');
3920 foreach my $mice (@$resmice) {
3921 if ($mice->{name} eq 'QEMU HID Tablet') {
3922 $devices->{tablet} = 1;
3923 last;
3924 }
3925 }
3926
3927 # for usb devices there is no query-usb
3928 # but we can iterate over the entries in
3929 # qom-list path=/machine/peripheral
3930 my $resperipheral = vm_mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
3931 foreach my $per (@$resperipheral) {
3932 if ($per->{name} =~ m/^usb\d+$/) {
3933 $devices->{$per->{name}} = 1;
3934 }
3935 }
3936
3937 return $devices;
3938 }
3939
3940 sub vm_deviceplug {
3941 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3942
3943 my $q35 = machine_type_is_q35($conf);
3944
3945 my $devices_list = vm_devices_list($vmid);
3946 return 1 if defined($devices_list->{$deviceid});
3947
3948 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3949
3950 if ($deviceid eq 'tablet') {
3951
3952 qemu_deviceadd($vmid, print_tabletdevice_full($conf));
3953
3954 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3955
3956 die "usb hotplug currently not reliable\n";
3957 # since we can't reliably hot unplug all added usb devices
3958 # and usb passthrough disables live migration
3959 # we disable usb hotplugging for now
3960 qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
3961
3962 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3963
3964 qemu_iothread_add($vmid, $deviceid, $device);
3965
3966 qemu_driveadd($storecfg, $vmid, $device);
3967 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device);
3968
3969 qemu_deviceadd($vmid, $devicefull);
3970 eval { qemu_deviceaddverify($vmid, $deviceid); };
3971 if (my $err = $@) {
3972 eval { qemu_drivedel($vmid, $deviceid); };
3973 warn $@ if $@;
3974 die $err;
3975 }
3976
3977 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3978
3979
3980 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
3981 my $pciaddr = print_pci_addr($deviceid);
3982 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
3983
3984 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3985
3986 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
3987 qemu_iothread_add($vmid, $deviceid, $device);
3988 $devicefull .= ",iothread=iothread-$deviceid";
3989 }
3990
3991 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
3992 $devicefull .= ",num_queues=$device->{queues}";
3993 }
3994
3995 qemu_deviceadd($vmid, $devicefull);
3996 qemu_deviceaddverify($vmid, $deviceid);
3997
3998 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3999
4000 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device);
4001 qemu_driveadd($storecfg, $vmid, $device);
4002
4003 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device);
4004 eval { qemu_deviceadd($vmid, $devicefull); };
4005 if (my $err = $@) {
4006 eval { qemu_drivedel($vmid, $deviceid); };
4007 warn $@ if $@;
4008 die $err;
4009 }
4010
4011 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4012
4013 return undef if !qemu_netdevadd($vmid, $conf, $device, $deviceid);
4014
4015 my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
4016 my $use_old_bios_files = undef;
4017 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
4018
4019 my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
4020 qemu_deviceadd($vmid, $netdevicefull);
4021 eval { qemu_deviceaddverify($vmid, $deviceid); };
4022 if (my $err = $@) {
4023 eval { qemu_netdevdel($vmid, $deviceid); };
4024 warn $@ if $@;
4025 die $err;
4026 }
4027
4028 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4029
4030 my $bridgeid = $2;
4031 my $pciaddr = print_pci_addr($deviceid);
4032 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4033
4034 qemu_deviceadd($vmid, $devicefull);
4035 qemu_deviceaddverify($vmid, $deviceid);
4036
4037 } else {
4038 die "can't hotplug device '$deviceid'\n";
4039 }
4040
4041 return 1;
4042 }
4043
4044 # fixme: this should raise exceptions on error!
4045 sub vm_deviceunplug {
4046 my ($vmid, $conf, $deviceid) = @_;
4047
4048 my $devices_list = vm_devices_list($vmid);
4049 return 1 if !defined($devices_list->{$deviceid});
4050
4051 die "can't unplug bootdisk" if $conf->{bootdisk} && $conf->{bootdisk} eq $deviceid;
4052
4053 if ($deviceid eq 'tablet') {
4054
4055 qemu_devicedel($vmid, $deviceid);
4056
4057 } elsif ($deviceid =~ m/^usb\d+$/) {
4058
4059 die "usb hotplug currently not reliable\n";
4060 # when unplugging usb devices this way,
4061 # there may be remaining usb controllers/hubs
4062 # so we disable it for now
4063 qemu_devicedel($vmid, $deviceid);
4064 qemu_devicedelverify($vmid, $deviceid);
4065
4066 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4067
4068 qemu_devicedel($vmid, $deviceid);
4069 qemu_devicedelverify($vmid, $deviceid);
4070 qemu_drivedel($vmid, $deviceid);
4071 qemu_iothread_del($conf, $vmid, $deviceid);
4072
4073 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4074
4075 qemu_devicedel($vmid, $deviceid);
4076 qemu_devicedelverify($vmid, $deviceid);
4077 qemu_iothread_del($conf, $vmid, $deviceid);
4078
4079 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4080
4081 qemu_devicedel($vmid, $deviceid);
4082 qemu_drivedel($vmid, $deviceid);
4083 qemu_deletescsihw($conf, $vmid, $deviceid);
4084
4085 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4086
4087 qemu_devicedel($vmid, $deviceid);
4088 qemu_devicedelverify($vmid, $deviceid);
4089 qemu_netdevdel($vmid, $deviceid);
4090
4091 } else {
4092 die "can't unplug device '$deviceid'\n";
4093 }
4094
4095 return 1;
4096 }
4097
4098 sub qemu_deviceadd {
4099 my ($vmid, $devicefull) = @_;
4100
4101 $devicefull = "driver=".$devicefull;
4102 my %options = split(/[=,]/, $devicefull);
4103
4104 vm_mon_cmd($vmid, "device_add" , %options);
4105 }
4106
4107 sub qemu_devicedel {
4108 my ($vmid, $deviceid) = @_;
4109
4110 my $ret = vm_mon_cmd($vmid, "device_del", id => $deviceid);
4111 }
4112
4113 sub qemu_iothread_add {
4114 my($vmid, $deviceid, $device) = @_;
4115
4116 if ($device->{iothread}) {
4117 my $iothreads = vm_iothreads_list($vmid);
4118 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4119 }
4120 }
4121
4122 sub qemu_iothread_del {
4123 my($conf, $vmid, $deviceid) = @_;
4124
4125 my $device = parse_drive($deviceid, $conf->{$deviceid});
4126 if ($device->{iothread}) {
4127 my $iothreads = vm_iothreads_list($vmid);
4128 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4129 }
4130 }
4131
4132 sub qemu_objectadd {
4133 my($vmid, $objectid, $qomtype) = @_;
4134
4135 vm_mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4136
4137 return 1;
4138 }
4139
4140 sub qemu_objectdel {
4141 my($vmid, $objectid) = @_;
4142
4143 vm_mon_cmd($vmid, "object-del", id => $objectid);
4144
4145 return 1;
4146 }
4147
4148 sub qemu_driveadd {
4149 my ($storecfg, $vmid, $device) = @_;
4150
4151 my $drive = print_drive_full($storecfg, $vmid, $device);
4152 $drive =~ s/\\/\\\\/g;
4153 my $ret = vm_human_monitor_command($vmid, "drive_add auto \"$drive\"");
4154
4155 # If the command succeeds qemu prints: "OK"
4156 return 1 if $ret =~ m/OK/s;
4157
4158 die "adding drive failed: $ret\n";
4159 }
4160
4161 sub qemu_drivedel {
4162 my($vmid, $deviceid) = @_;
4163
4164 my $ret = vm_human_monitor_command($vmid, "drive_del drive-$deviceid");
4165 $ret =~ s/^\s+//;
4166
4167 return 1 if $ret eq "";
4168
4169 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4170 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4171
4172 die "deleting drive $deviceid failed : $ret\n";
4173 }
4174
4175 sub qemu_deviceaddverify {
4176 my ($vmid, $deviceid) = @_;
4177
4178 for (my $i = 0; $i <= 5; $i++) {
4179 my $devices_list = vm_devices_list($vmid);
4180 return 1 if defined($devices_list->{$deviceid});
4181 sleep 1;
4182 }
4183
4184 die "error on hotplug device '$deviceid'\n";
4185 }
4186
4187
4188 sub qemu_devicedelverify {
4189 my ($vmid, $deviceid) = @_;
4190
4191 # need to verify that the device is correctly removed as device_del
4192 # is async and empty return is not reliable
4193
4194 for (my $i = 0; $i <= 5; $i++) {
4195 my $devices_list = vm_devices_list($vmid);
4196 return 1 if !defined($devices_list->{$deviceid});
4197 sleep 1;
4198 }
4199
4200 die "error on hot-unplugging device '$deviceid'\n";
4201 }
4202
4203 sub qemu_findorcreatescsihw {
4204 my ($storecfg, $conf, $vmid, $device) = @_;
4205
4206 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4207
4208 my $scsihwid="$controller_prefix$controller";
4209 my $devices_list = vm_devices_list($vmid);
4210
4211 if(!defined($devices_list->{$scsihwid})) {
4212 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
4213 }
4214
4215 return 1;
4216 }
4217
4218 sub qemu_deletescsihw {
4219 my ($conf, $vmid, $opt) = @_;
4220
4221 my $device = parse_drive($opt, $conf->{$opt});
4222
4223 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4224 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
4225 return 1;
4226 }
4227
4228 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4229
4230 my $devices_list = vm_devices_list($vmid);
4231 foreach my $opt (keys %{$devices_list}) {
4232 if (PVE::QemuServer::is_valid_drivename($opt)) {
4233 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4234 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4235 return 1;
4236 }
4237 }
4238 }
4239
4240 my $scsihwid="scsihw$controller";
4241
4242 vm_deviceunplug($vmid, $conf, $scsihwid);
4243
4244 return 1;
4245 }
4246
4247 sub qemu_add_pci_bridge {
4248 my ($storecfg, $conf, $vmid, $device) = @_;
4249
4250 my $bridges = {};
4251
4252 my $bridgeid;
4253
4254 print_pci_addr($device, $bridges);
4255
4256 while (my ($k, $v) = each %$bridges) {
4257 $bridgeid = $k;
4258 }
4259 return 1 if !defined($bridgeid) || $bridgeid < 1;
4260
4261 my $bridge = "pci.$bridgeid";
4262 my $devices_list = vm_devices_list($vmid);
4263
4264 if (!defined($devices_list->{$bridge})) {
4265 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
4266 }
4267
4268 return 1;
4269 }
4270
4271 sub qemu_set_link_status {
4272 my ($vmid, $device, $up) = @_;
4273
4274 vm_mon_cmd($vmid, "set_link", name => $device,
4275 up => $up ? JSON::true : JSON::false);
4276 }
4277
4278 sub qemu_netdevadd {
4279 my ($vmid, $conf, $device, $deviceid) = @_;
4280
4281 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
4282 my %options = split(/[=,]/, $netdev);
4283
4284 vm_mon_cmd($vmid, "netdev_add", %options);
4285 return 1;
4286 }
4287
4288 sub qemu_netdevdel {
4289 my ($vmid, $deviceid) = @_;
4290
4291 vm_mon_cmd($vmid, "netdev_del", id => $deviceid);
4292 }
4293
4294 sub qemu_usb_hotplug {
4295 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4296
4297 return if !$device;
4298
4299 # remove the old one first
4300 vm_deviceunplug($vmid, $conf, $deviceid);
4301
4302 # check if xhci controller is necessary and available
4303 if ($device->{usb3}) {
4304
4305 my $devicelist = vm_devices_list($vmid);
4306
4307 if (!$devicelist->{xhci}) {
4308 my $pciaddr = print_pci_addr("xhci");
4309 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4310 }
4311 }
4312 my $d = parse_usb_device($device->{host});
4313 $d->{usb3} = $device->{usb3};
4314
4315 # add the new one
4316 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4317 }
4318
4319 sub qemu_cpu_hotplug {
4320 my ($vmid, $conf, $vcpus) = @_;
4321
4322 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4323
4324 my $sockets = 1;
4325 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4326 $sockets = $conf->{sockets} if $conf->{sockets};
4327 my $cores = $conf->{cores} || 1;
4328 my $maxcpus = $sockets * $cores;
4329
4330 $vcpus = $maxcpus if !$vcpus;
4331
4332 die "you can't add more vcpus than maxcpus\n"
4333 if $vcpus > $maxcpus;
4334
4335 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4336
4337 if ($vcpus < $currentvcpus) {
4338
4339 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4340
4341 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4342 qemu_devicedel($vmid, "cpu$i");
4343 my $retry = 0;
4344 my $currentrunningvcpus = undef;
4345 while (1) {
4346 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4347 last if scalar(@{$currentrunningvcpus}) == $i-1;
4348 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4349 $retry++;
4350 sleep 1;
4351 }
4352 #update conf after each succesfull cpu unplug
4353 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4354 PVE::QemuConfig->write_config($vmid, $conf);
4355 }
4356 } else {
4357 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4358 }
4359
4360 return;
4361 }
4362
4363 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4364 die "vcpus in running vm does not match its configuration\n"
4365 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4366
4367 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4368
4369 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4370 my $cpustr = print_cpu_device($conf, $i);
4371 qemu_deviceadd($vmid, $cpustr);
4372
4373 my $retry = 0;
4374 my $currentrunningvcpus = undef;
4375 while (1) {
4376 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4377 last if scalar(@{$currentrunningvcpus}) == $i;
4378 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4379 sleep 1;
4380 $retry++;
4381 }
4382 #update conf after each succesfull cpu hotplug
4383 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4384 PVE::QemuConfig->write_config($vmid, $conf);
4385 }
4386 } else {
4387
4388 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4389 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4390 }
4391 }
4392 }
4393
4394 sub qemu_block_set_io_throttle {
4395 my ($vmid, $deviceid,
4396 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4397 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4398 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4399 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4400
4401 return if !check_running($vmid) ;
4402
4403 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4404 bps => int($bps),
4405 bps_rd => int($bps_rd),
4406 bps_wr => int($bps_wr),
4407 iops => int($iops),
4408 iops_rd => int($iops_rd),
4409 iops_wr => int($iops_wr),
4410 bps_max => int($bps_max),
4411 bps_rd_max => int($bps_rd_max),
4412 bps_wr_max => int($bps_wr_max),
4413 iops_max => int($iops_max),
4414 iops_rd_max => int($iops_rd_max),
4415 iops_wr_max => int($iops_wr_max),
4416 bps_max_length => int($bps_max_length),
4417 bps_rd_max_length => int($bps_rd_max_length),
4418 bps_wr_max_length => int($bps_wr_max_length),
4419 iops_max_length => int($iops_max_length),
4420 iops_rd_max_length => int($iops_rd_max_length),
4421 iops_wr_max_length => int($iops_wr_max_length),
4422 );
4423
4424 }
4425
4426 # old code, only used to shutdown old VM after update
4427 sub __read_avail {
4428 my ($fh, $timeout) = @_;
4429
4430 my $sel = new IO::Select;
4431 $sel->add($fh);
4432
4433 my $res = '';
4434 my $buf;
4435
4436 my @ready;
4437 while (scalar (@ready = $sel->can_read($timeout))) {
4438 my $count;
4439 if ($count = $fh->sysread($buf, 8192)) {
4440 if ($buf =~ /^(.*)\(qemu\) $/s) {
4441 $res .= $1;
4442 last;
4443 } else {
4444 $res .= $buf;
4445 }
4446 } else {
4447 if (!defined($count)) {
4448 die "$!\n";
4449 }
4450 last;
4451 }
4452 }
4453
4454 die "monitor read timeout\n" if !scalar(@ready);
4455
4456 return $res;
4457 }
4458
4459 sub qemu_block_resize {
4460 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4461
4462 my $running = check_running($vmid);
4463
4464 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4465
4466 return if !$running;
4467
4468 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4469
4470 }
4471
4472 sub qemu_volume_snapshot {
4473 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4474
4475 my $running = check_running($vmid);
4476
4477 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4478 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
4479 } else {
4480 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4481 }
4482 }
4483
4484 sub qemu_volume_snapshot_delete {
4485 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4486
4487 my $running = check_running($vmid);
4488
4489 if($running) {
4490
4491 $running = undef;
4492 my $conf = PVE::QemuConfig->load_config($vmid);
4493 foreach_drive($conf, sub {
4494 my ($ds, $drive) = @_;
4495 $running = 1 if $drive->{file} eq $volid;
4496 });
4497 }
4498
4499 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4500 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
4501 } else {
4502 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4503 }
4504 }
4505
4506 sub set_migration_caps {
4507 my ($vmid) = @_;
4508
4509 my $cap_ref = [];
4510
4511 my $enabled_cap = {
4512 "auto-converge" => 1,
4513 "xbzrle" => 1,
4514 "x-rdma-pin-all" => 0,
4515 "zero-blocks" => 0,
4516 "compress" => 0
4517 };
4518
4519 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4520
4521 for my $supported_capability (@$supported_capabilities) {
4522 push @$cap_ref, {
4523 capability => $supported_capability->{capability},
4524 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4525 };
4526 }
4527
4528 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4529 }
4530
4531 my $fast_plug_option = {
4532 'lock' => 1,
4533 'name' => 1,
4534 'onboot' => 1,
4535 'shares' => 1,
4536 'startup' => 1,
4537 'description' => 1,
4538 'protection' => 1,
4539 'vmstatestorage' => 1,
4540 };
4541
4542 # hotplug changes in [PENDING]
4543 # $selection hash can be used to only apply specified options, for
4544 # example: { cores => 1 } (only apply changed 'cores')
4545 # $errors ref is used to return error messages
4546 sub vmconfig_hotplug_pending {
4547 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4548
4549 my $defaults = load_defaults();
4550
4551 # commit values which do not have any impact on running VM first
4552 # Note: those option cannot raise errors, we we do not care about
4553 # $selection and always apply them.
4554
4555 my $add_error = sub {
4556 my ($opt, $msg) = @_;
4557 $errors->{$opt} = "hotplug problem - $msg";
4558 };
4559
4560 my $changes = 0;
4561 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4562 if ($fast_plug_option->{$opt}) {
4563 $conf->{$opt} = $conf->{pending}->{$opt};
4564 delete $conf->{pending}->{$opt};
4565 $changes = 1;
4566 }
4567 }
4568
4569 if ($changes) {
4570 PVE::QemuConfig->write_config($vmid, $conf);
4571 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4572 }
4573
4574 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4575
4576 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4577 while (my ($opt, $force) = each %$pending_delete_hash) {
4578 next if $selection && !$selection->{$opt};
4579 eval {
4580 if ($opt eq 'hotplug') {
4581 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4582 } elsif ($opt eq 'tablet') {
4583 die "skip\n" if !$hotplug_features->{usb};
4584 if ($defaults->{tablet}) {
4585 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4586 } else {
4587 vm_deviceunplug($vmid, $conf, $opt);
4588 }
4589 } elsif ($opt =~ m/^usb\d+/) {
4590 die "skip\n";
4591 # since we cannot reliably hot unplug usb devices
4592 # we are disabling it
4593 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4594 vm_deviceunplug($vmid, $conf, $opt);
4595 } elsif ($opt eq 'vcpus') {
4596 die "skip\n" if !$hotplug_features->{cpu};
4597 qemu_cpu_hotplug($vmid, $conf, undef);
4598 } elsif ($opt eq 'balloon') {
4599 # enable balloon device is not hotpluggable
4600 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4601 # here we reset the ballooning value to memory
4602 my $balloon = $conf->{memory} || $defaults->{memory};
4603 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4604 } elsif ($fast_plug_option->{$opt}) {
4605 # do nothing
4606 } elsif ($opt =~ m/^net(\d+)$/) {
4607 die "skip\n" if !$hotplug_features->{network};
4608 vm_deviceunplug($vmid, $conf, $opt);
4609 } elsif (is_valid_drivename($opt)) {
4610 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4611 vm_deviceunplug($vmid, $conf, $opt);
4612 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4613 } elsif ($opt =~ m/^memory$/) {
4614 die "skip\n" if !$hotplug_features->{memory};
4615 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4616 } elsif ($opt eq 'cpuunits') {
4617 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4618 } elsif ($opt eq 'cpulimit') {
4619 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4620 } else {
4621 die "skip\n";
4622 }
4623 };
4624 if (my $err = $@) {
4625 &$add_error($opt, $err) if $err ne "skip\n";
4626 } else {
4627 # save new config if hotplug was successful
4628 delete $conf->{$opt};
4629 vmconfig_undelete_pending_option($conf, $opt);
4630 PVE::QemuConfig->write_config($vmid, $conf);
4631 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4632 }
4633 }
4634
4635 my $apply_pending_cloudinit;
4636 $apply_pending_cloudinit = sub {
4637 my ($key, $value) = @_;
4638 $apply_pending_cloudinit = sub {}; # once is enough
4639
4640 my @cloudinit_opts = keys %$confdesc_cloudinit;
4641 foreach my $opt (keys %{$conf->{pending}}) {
4642 next if !grep { $_ eq $opt } @cloudinit_opts;
4643 $conf->{$opt} = delete $conf->{pending}->{$opt};
4644 }
4645
4646 my $new_conf = { %$conf };
4647 $new_conf->{$key} = $value;
4648 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4649 };
4650
4651 foreach my $opt (keys %{$conf->{pending}}) {
4652 next if $selection && !$selection->{$opt};
4653 my $value = $conf->{pending}->{$opt};
4654 eval {
4655 if ($opt eq 'hotplug') {
4656 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4657 } elsif ($opt eq 'tablet') {
4658 die "skip\n" if !$hotplug_features->{usb};
4659 if ($value == 1) {
4660 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4661 } elsif ($value == 0) {
4662 vm_deviceunplug($vmid, $conf, $opt);
4663 }
4664 } elsif ($opt =~ m/^usb\d+$/) {
4665 die "skip\n";
4666 # since we cannot reliably hot unplug usb devices
4667 # we are disabling it
4668 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4669 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4670 die "skip\n" if !$d;
4671 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4672 } elsif ($opt eq 'vcpus') {
4673 die "skip\n" if !$hotplug_features->{cpu};
4674 qemu_cpu_hotplug($vmid, $conf, $value);
4675 } elsif ($opt eq 'balloon') {
4676 # enable/disable balloning device is not hotpluggable
4677 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4678 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4679 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4680
4681 # allow manual ballooning if shares is set to zero
4682 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4683 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4684 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4685 }
4686 } elsif ($opt =~ m/^net(\d+)$/) {
4687 # some changes can be done without hotplug
4688 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4689 $vmid, $opt, $value);
4690 } elsif (is_valid_drivename($opt)) {
4691 # some changes can be done without hotplug
4692 my $drive = parse_drive($opt, $value);
4693 if (drive_is_cloudinit($drive)) {
4694 &$apply_pending_cloudinit($opt, $value);
4695 }
4696 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4697 $vmid, $opt, $value, 1);
4698 } elsif ($opt =~ m/^memory$/) { #dimms
4699 die "skip\n" if !$hotplug_features->{memory};
4700 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4701 } elsif ($opt eq 'cpuunits') {
4702 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4703 } elsif ($opt eq 'cpulimit') {
4704 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4705 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4706 } else {
4707 die "skip\n"; # skip non-hot-pluggable options
4708 }
4709 };
4710 if (my $err = $@) {
4711 &$add_error($opt, $err) if $err ne "skip\n";
4712 } else {
4713 # save new config if hotplug was successful
4714 $conf->{$opt} = $value;
4715 delete $conf->{pending}->{$opt};
4716 PVE::QemuConfig->write_config($vmid, $conf);
4717 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4718 }
4719 }
4720 }
4721
4722 sub try_deallocate_drive {
4723 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4724
4725 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4726 my $volid = $drive->{file};
4727 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4728 my $sid = PVE::Storage::parse_volume_id($volid);
4729 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
4730
4731 # check if the disk is really unused
4732 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4733 if is_volume_in_use($storecfg, $conf, $key, $volid);
4734 PVE::Storage::vdisk_free($storecfg, $volid);
4735 return 1;
4736 } else {
4737 # If vm is not owner of this disk remove from config
4738 return 1;
4739 }
4740 }
4741
4742 return undef;
4743 }
4744
4745 sub vmconfig_delete_or_detach_drive {
4746 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4747
4748 my $drive = parse_drive($opt, $conf->{$opt});
4749
4750 my $rpcenv = PVE::RPCEnvironment::get();
4751 my $authuser = $rpcenv->get_user();
4752
4753 if ($force) {
4754 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
4755 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4756 } else {
4757 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4758 }
4759 }
4760
4761 sub vmconfig_apply_pending {
4762 my ($vmid, $conf, $storecfg) = @_;
4763
4764 # cold plug
4765
4766 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4767 while (my ($opt, $force) = each %$pending_delete_hash) {
4768 die "internal error" if $opt =~ m/^unused/;
4769 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4770 if (!defined($conf->{$opt})) {
4771 vmconfig_undelete_pending_option($conf, $opt);
4772 PVE::QemuConfig->write_config($vmid, $conf);
4773 } elsif (is_valid_drivename($opt)) {
4774 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4775 vmconfig_undelete_pending_option($conf, $opt);
4776 delete $conf->{$opt};
4777 PVE::QemuConfig->write_config($vmid, $conf);
4778 } else {
4779 vmconfig_undelete_pending_option($conf, $opt);
4780 delete $conf->{$opt};
4781 PVE::QemuConfig->write_config($vmid, $conf);
4782 }
4783 }
4784
4785 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4786
4787 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4788 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4789
4790 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4791 # skip if nothing changed
4792 } elsif (is_valid_drivename($opt)) {
4793 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4794 if defined($conf->{$opt});
4795 $conf->{$opt} = $conf->{pending}->{$opt};
4796 } else {
4797 $conf->{$opt} = $conf->{pending}->{$opt};
4798 }
4799
4800 delete $conf->{pending}->{$opt};
4801 PVE::QemuConfig->write_config($vmid, $conf);
4802 }
4803 }
4804
4805 my $safe_num_ne = sub {
4806 my ($a, $b) = @_;
4807
4808 return 0 if !defined($a) && !defined($b);
4809 return 1 if !defined($a);
4810 return 1 if !defined($b);
4811
4812 return $a != $b;
4813 };
4814
4815 my $safe_string_ne = sub {
4816 my ($a, $b) = @_;
4817
4818 return 0 if !defined($a) && !defined($b);
4819 return 1 if !defined($a);
4820 return 1 if !defined($b);
4821
4822 return $a ne $b;
4823 };
4824
4825 sub vmconfig_update_net {
4826 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4827
4828 my $newnet = parse_net($value);
4829
4830 if ($conf->{$opt}) {
4831 my $oldnet = parse_net($conf->{$opt});
4832
4833 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4834 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4835 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4836 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4837
4838 # for non online change, we try to hot-unplug
4839 die "skip\n" if !$hotplug;
4840 vm_deviceunplug($vmid, $conf, $opt);
4841 } else {
4842
4843 die "internal error" if $opt !~ m/net(\d+)/;
4844 my $iface = "tap${vmid}i$1";
4845
4846 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4847 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4848 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4849 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4850 PVE::Network::tap_unplug($iface);
4851 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4852 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4853 # Rate can be applied on its own but any change above needs to
4854 # include the rate in tap_plug since OVS resets everything.
4855 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4856 }
4857
4858 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4859 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4860 }
4861
4862 return 1;
4863 }
4864 }
4865
4866 if ($hotplug) {
4867 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4868 } else {
4869 die "skip\n";
4870 }
4871 }
4872
4873 sub vmconfig_update_disk {
4874 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4875
4876 # fixme: do we need force?
4877
4878 my $drive = parse_drive($opt, $value);
4879
4880 if ($conf->{$opt}) {
4881
4882 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4883
4884 my $media = $drive->{media} || 'disk';
4885 my $oldmedia = $old_drive->{media} || 'disk';
4886 die "unable to change media type\n" if $media ne $oldmedia;
4887
4888 if (!drive_is_cdrom($old_drive)) {
4889
4890 if ($drive->{file} ne $old_drive->{file}) {
4891
4892 die "skip\n" if !$hotplug;
4893
4894 # unplug and register as unused
4895 vm_deviceunplug($vmid, $conf, $opt);
4896 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4897
4898 } else {
4899 # update existing disk
4900
4901 # skip non hotpluggable value
4902 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4903 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4904 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4905 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4906 die "skip\n";
4907 }
4908
4909 # apply throttle
4910 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4911 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4912 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4913 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4914 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4915 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4916 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4917 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4918 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4919 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4920 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4921 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4922 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4923 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4924 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4925 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4926 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4927 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4928
4929 qemu_block_set_io_throttle($vmid,"drive-$opt",
4930 ($drive->{mbps} || 0)*1024*1024,
4931 ($drive->{mbps_rd} || 0)*1024*1024,
4932 ($drive->{mbps_wr} || 0)*1024*1024,
4933 $drive->{iops} || 0,
4934 $drive->{iops_rd} || 0,
4935 $drive->{iops_wr} || 0,
4936 ($drive->{mbps_max} || 0)*1024*1024,
4937 ($drive->{mbps_rd_max} || 0)*1024*1024,
4938 ($drive->{mbps_wr_max} || 0)*1024*1024,
4939 $drive->{iops_max} || 0,
4940 $drive->{iops_rd_max} || 0,
4941 $drive->{iops_wr_max} || 0,
4942 $drive->{bps_max_length} || 1,
4943 $drive->{bps_rd_max_length} || 1,
4944 $drive->{bps_wr_max_length} || 1,
4945 $drive->{iops_max_length} || 1,
4946 $drive->{iops_rd_max_length} || 1,
4947 $drive->{iops_wr_max_length} || 1);
4948
4949 }
4950
4951 return 1;
4952 }
4953
4954 } else { # cdrom
4955
4956 if ($drive->{file} eq 'none') {
4957 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4958 if (drive_is_cloudinit($old_drive)) {
4959 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4960 }
4961 } else {
4962 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4963 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4964 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4965 }
4966
4967 return 1;
4968 }
4969 }
4970 }
4971
4972 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4973 # hotplug new disks
4974 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4975 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4976 }
4977
4978 sub vm_start {
4979 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4980 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4981
4982 PVE::QemuConfig->lock_config($vmid, sub {
4983 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4984
4985 die "you can't start a vm if it's a template\n" if PVE::QemuConfig->is_template($conf);
4986
4987 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4988
4989 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4990
4991 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4992 vmconfig_apply_pending($vmid, $conf, $storecfg);
4993 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4994 }
4995
4996 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4997
4998 my $defaults = load_defaults();
4999
5000 # set environment variable useful inside network script
5001 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5002
5003 my $local_volumes = {};
5004
5005 if ($targetstorage) {
5006 foreach_drive($conf, sub {
5007 my ($ds, $drive) = @_;
5008
5009 return if drive_is_cdrom($drive);
5010
5011 my $volid = $drive->{file};
5012
5013 return if !$volid;
5014
5015 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5016
5017 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5018 return if $scfg->{shared};
5019 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5020 });
5021
5022 my $format = undef;
5023
5024 foreach my $opt (sort keys %$local_volumes) {
5025
5026 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5027 my $drive = parse_drive($opt, $conf->{$opt});
5028
5029 #if remote storage is specified, use default format
5030 if ($targetstorage && $targetstorage ne "1") {
5031 $storeid = $targetstorage;
5032 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5033 $format = $defFormat;
5034 } else {
5035 #else we use same format than original
5036 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5037 $format = qemu_img_format($scfg, $volid);
5038 }
5039
5040 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5041 my $newdrive = $drive;
5042 $newdrive->{format} = $format;
5043 $newdrive->{file} = $newvolid;
5044 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5045 $local_volumes->{$opt} = $drivestr;
5046 #pass drive to conf for command line
5047 $conf->{$opt} = $drivestr;
5048 }
5049 }
5050
5051 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5052
5053 my $migrate_port = 0;
5054 my $migrate_uri;
5055 if ($statefile) {
5056 if ($statefile eq 'tcp') {
5057 my $localip = "localhost";
5058 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
5059 my $nodename = PVE::INotify::nodename();
5060
5061 if (!defined($migration_type)) {
5062 if (defined($datacenterconf->{migration}->{type})) {
5063 $migration_type = $datacenterconf->{migration}->{type};
5064 } else {
5065 $migration_type = 'secure';
5066 }
5067 }
5068
5069 if ($migration_type eq 'insecure') {
5070 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5071 if ($migrate_network_addr) {
5072 $localip = $migrate_network_addr;
5073 } else {
5074 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5075 }
5076
5077 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5078 }
5079
5080 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5081 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5082 $migrate_uri = "tcp:${localip}:${migrate_port}";
5083 push @$cmd, '-incoming', $migrate_uri;
5084 push @$cmd, '-S';
5085
5086 } elsif ($statefile eq 'unix') {
5087 # should be default for secure migrations as a ssh TCP forward
5088 # tunnel is not deterministic reliable ready and fails regurarly
5089 # to set up in time, so use UNIX socket forwards
5090 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5091 unlink $socket_addr;
5092
5093 $migrate_uri = "unix:$socket_addr";
5094
5095 push @$cmd, '-incoming', $migrate_uri;
5096 push @$cmd, '-S';
5097
5098 } else {
5099 push @$cmd, '-loadstate', $statefile;
5100 }
5101 } elsif ($paused) {
5102 push @$cmd, '-S';
5103 }
5104
5105 # host pci devices
5106 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5107 my $d = parse_hostpci($conf->{"hostpci$i"});
5108 next if !$d;
5109 my $pcidevices = $d->{pciid};
5110 foreach my $pcidevice (@$pcidevices) {
5111 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
5112
5113 my $info = pci_device_info("0000:$pciid");
5114 die "IOMMU not present\n" if !check_iommu_support();
5115 die "no pci device info for device '$pciid'\n" if !$info;
5116 die "can't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
5117 die "can't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
5118 }
5119 }
5120
5121 PVE::Storage::activate_volumes($storecfg, $vollist);
5122
5123 if (!check_running($vmid, 1)) {
5124 eval {
5125 run_command(['/bin/systemctl', 'stop', "$vmid.scope"],
5126 outfunc => sub {}, errfunc => sub {});
5127 };
5128 }
5129
5130 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5131 : $defaults->{cpuunits};
5132
5133 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5134 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5135
5136 my %properties = (
5137 Slice => 'qemu.slice',
5138 KillMode => 'none',
5139 CPUShares => $cpuunits
5140 );
5141
5142 if (my $cpulimit = $conf->{cpulimit}) {
5143 $properties{CPUQuota} = int($cpulimit * 100);
5144 }
5145 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5146
5147 my $run_qemu = sub {
5148 PVE::Tools::run_fork sub {
5149 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5150 run_command($cmd, %run_params);
5151 };
5152 };
5153
5154 if ($conf->{hugepages}) {
5155
5156 my $code = sub {
5157 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5158 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5159
5160 PVE::QemuServer::Memory::hugepages_mount();
5161 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5162
5163 eval { $run_qemu->() };
5164 if (my $err = $@) {
5165 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5166 die $err;
5167 }
5168
5169 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5170 };
5171 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5172
5173 } else {
5174 eval { $run_qemu->() };
5175 }
5176
5177 if (my $err = $@) {
5178 # deactivate volumes if start fails
5179 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5180 die "start failed: $err";
5181 }
5182
5183 print "migration listens on $migrate_uri\n" if $migrate_uri;
5184
5185 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5186 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5187 warn $@ if $@;
5188 }
5189
5190 #start nbd server for storage migration
5191 if ($targetstorage) {
5192 my $nodename = PVE::INotify::nodename();
5193 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5194 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5195 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5196 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5197
5198 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet', data => { host => "${localip}", port => "${migrate_port}" } } );
5199
5200 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5201
5202 foreach my $opt (sort keys %$local_volumes) {
5203 my $volid = $local_volumes->{$opt};
5204 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5205 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5206 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5207 }
5208 }
5209
5210 if ($migratedfrom) {
5211 eval {
5212 set_migration_caps($vmid);
5213 };
5214 warn $@ if $@;
5215
5216 if ($spice_port) {
5217 print "spice listens on port $spice_port\n";
5218 if ($spice_ticket) {
5219 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice', password => $spice_ticket);
5220 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice', time => "+30");
5221 }
5222 }
5223
5224 } else {
5225 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5226 if !$statefile && $conf->{balloon};
5227
5228 foreach my $opt (keys %$conf) {
5229 next if $opt !~ m/^net\d+$/;
5230 my $nicconf = parse_net($conf->{$opt});
5231 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5232 }
5233 }
5234
5235 vm_mon_cmd_nocheck($vmid, 'qom-set',
5236 path => "machine/peripheral/balloon0",
5237 property => "guest-stats-polling-interval",
5238 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5239
5240 });
5241 }
5242
5243 sub vm_mon_cmd {
5244 my ($vmid, $execute, %params) = @_;
5245
5246 my $cmd = { execute => $execute, arguments => \%params };
5247 vm_qmp_command($vmid, $cmd);
5248 }
5249
5250 sub vm_mon_cmd_nocheck {
5251 my ($vmid, $execute, %params) = @_;
5252
5253 my $cmd = { execute => $execute, arguments => \%params };
5254 vm_qmp_command($vmid, $cmd, 1);
5255 }
5256
5257 sub vm_qmp_command {
5258 my ($vmid, $cmd, $nocheck) = @_;
5259
5260 my $res;
5261
5262 my $timeout;
5263 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5264 $timeout = $cmd->{arguments}->{timeout};
5265 delete $cmd->{arguments}->{timeout};
5266 }
5267
5268 eval {
5269 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5270 my $sname = qmp_socket($vmid);
5271 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5272 my $qmpclient = PVE::QMPClient->new();
5273
5274 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5275 } else {
5276 die "unable to open monitor socket\n";
5277 }
5278 };
5279 if (my $err = $@) {
5280 syslog("err", "VM $vmid qmp command failed - $err");
5281 die $err;
5282 }
5283
5284 return $res;
5285 }
5286
5287 sub vm_human_monitor_command {
5288 my ($vmid, $cmdline) = @_;
5289
5290 my $res;
5291
5292 my $cmd = {
5293 execute => 'human-monitor-command',
5294 arguments => { 'command-line' => $cmdline},
5295 };
5296
5297 return vm_qmp_command($vmid, $cmd);
5298 }
5299
5300 sub vm_commandline {
5301 my ($storecfg, $vmid) = @_;
5302
5303 my $conf = PVE::QemuConfig->load_config($vmid);
5304
5305 my $defaults = load_defaults();
5306
5307 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5308
5309 return PVE::Tools::cmd2string($cmd);
5310 }
5311
5312 sub vm_reset {
5313 my ($vmid, $skiplock) = @_;
5314
5315 PVE::QemuConfig->lock_config($vmid, sub {
5316
5317 my $conf = PVE::QemuConfig->load_config($vmid);
5318
5319 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5320
5321 vm_mon_cmd($vmid, "system_reset");
5322 });
5323 }
5324
5325 sub get_vm_volumes {
5326 my ($conf) = @_;
5327
5328 my $vollist = [];
5329 foreach_volid($conf, sub {
5330 my ($volid, $attr) = @_;
5331
5332 return if $volid =~ m|^/|;
5333
5334 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5335 return if !$sid;
5336
5337 push @$vollist, $volid;
5338 });
5339
5340 return $vollist;
5341 }
5342
5343 sub vm_stop_cleanup {
5344 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5345
5346 eval {
5347
5348 if (!$keepActive) {
5349 my $vollist = get_vm_volumes($conf);
5350 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5351 }
5352
5353 foreach my $ext (qw(mon qmp pid vnc qga)) {
5354 unlink "/var/run/qemu-server/${vmid}.$ext";
5355 }
5356
5357 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
5358 };
5359 warn $@ if $@; # avoid errors - just warn
5360 }
5361
5362 # Note: use $nockeck to skip tests if VM configuration file exists.
5363 # We need that when migration VMs to other nodes (files already moved)
5364 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5365 sub vm_stop {
5366 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5367
5368 $force = 1 if !defined($force) && !$shutdown;
5369
5370 if ($migratedfrom){
5371 my $pid = check_running($vmid, $nocheck, $migratedfrom);
5372 kill 15, $pid if $pid;
5373 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5374 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
5375 return;
5376 }
5377
5378 PVE::QemuConfig->lock_config($vmid, sub {
5379
5380 my $pid = check_running($vmid, $nocheck);
5381 return if !$pid;
5382
5383 my $conf;
5384 if (!$nocheck) {
5385 $conf = PVE::QemuConfig->load_config($vmid);
5386 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5387 if (!defined($timeout) && $shutdown && $conf->{startup}) {
5388 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
5389 $timeout = $opts->{down} if $opts->{down};
5390 }
5391 }
5392
5393 $timeout = 60 if !defined($timeout);
5394
5395 eval {
5396 if ($shutdown) {
5397 if (defined($conf) && parse_guest_agent($conf)->{enabled}) {
5398 vm_qmp_command($vmid, { execute => "guest-shutdown" }, $nocheck);
5399 } else {
5400 vm_qmp_command($vmid, { execute => "system_powerdown" }, $nocheck);
5401 }
5402 } else {
5403 vm_qmp_command($vmid, { execute => "quit" }, $nocheck);
5404 }
5405 };
5406 my $err = $@;
5407
5408 if (!$err) {
5409 my $count = 0;
5410 while (($count < $timeout) && check_running($vmid, $nocheck)) {
5411 $count++;
5412 sleep 1;
5413 }
5414
5415 if ($count >= $timeout) {
5416 if ($force) {
5417 warn "VM still running - terminating now with SIGTERM\n";
5418 kill 15, $pid;
5419 } else {
5420 die "VM quit/powerdown failed - got timeout\n";
5421 }
5422 } else {
5423 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5424 return;
5425 }
5426 } else {
5427 if ($force) {
5428 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5429 kill 15, $pid;
5430 } else {
5431 die "VM quit/powerdown failed\n";
5432 }
5433 }
5434
5435 # wait again
5436 $timeout = 10;
5437
5438 my $count = 0;
5439 while (($count < $timeout) && check_running($vmid, $nocheck)) {
5440 $count++;
5441 sleep 1;
5442 }
5443
5444 if ($count >= $timeout) {
5445 warn "VM still running - terminating now with SIGKILL\n";
5446 kill 9, $pid;
5447 sleep 1;
5448 }
5449
5450 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5451 });
5452 }
5453
5454 sub vm_suspend {
5455 my ($vmid, $skiplock) = @_;
5456
5457 PVE::QemuConfig->lock_config($vmid, sub {
5458
5459 my $conf = PVE::QemuConfig->load_config($vmid);
5460
5461 PVE::QemuConfig->check_lock($conf)
5462 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
5463
5464 vm_mon_cmd($vmid, "stop");
5465 });
5466 }
5467
5468 sub vm_resume {
5469 my ($vmid, $skiplock, $nocheck) = @_;
5470
5471 PVE::QemuConfig->lock_config($vmid, sub {
5472
5473 my $res = vm_mon_cmd($vmid, 'query-status');
5474 my $resume_cmd = 'cont';
5475
5476 if ($res->{status} && $res->{status} eq 'suspended') {
5477 $resume_cmd = 'system_wakeup';
5478 }
5479
5480 if (!$nocheck) {
5481
5482 my $conf = PVE::QemuConfig->load_config($vmid);
5483
5484 PVE::QemuConfig->check_lock($conf)
5485 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
5486
5487 vm_mon_cmd($vmid, $resume_cmd);
5488
5489 } else {
5490 vm_mon_cmd_nocheck($vmid, $resume_cmd);
5491 }
5492 });
5493 }
5494
5495 sub vm_sendkey {
5496 my ($vmid, $skiplock, $key) = @_;
5497
5498 PVE::QemuConfig->lock_config($vmid, sub {
5499
5500 my $conf = PVE::QemuConfig->load_config($vmid);
5501
5502 # there is no qmp command, so we use the human monitor command
5503 vm_human_monitor_command($vmid, "sendkey $key");
5504 });
5505 }
5506
5507 sub vm_destroy {
5508 my ($storecfg, $vmid, $skiplock) = @_;
5509
5510 PVE::QemuConfig->lock_config($vmid, sub {
5511
5512 my $conf = PVE::QemuConfig->load_config($vmid);
5513
5514 if (!check_running($vmid)) {
5515 destroy_vm($storecfg, $vmid, undef, $skiplock);
5516 } else {
5517 die "VM $vmid is running - destroy failed\n";
5518 }
5519 });
5520 }
5521
5522 # pci helpers
5523
5524 sub file_write {
5525 my ($filename, $buf) = @_;
5526
5527 my $fh = IO::File->new($filename, "w");
5528 return undef if !$fh;
5529
5530 my $res = print $fh $buf;
5531
5532 $fh->close();
5533
5534 return $res;
5535 }
5536
5537 sub pci_device_info {
5538 my ($name) = @_;
5539
5540 my $res;
5541
5542 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5543 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5544
5545 my $irq = file_read_firstline("$pcisysfs/devices/$name/irq");
5546 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5547
5548 my $vendor = file_read_firstline("$pcisysfs/devices/$name/vendor");
5549 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5550
5551 my $product = file_read_firstline("$pcisysfs/devices/$name/device");
5552 return undef if !defined($product) || $product !~ s/^0x//;
5553
5554 $res = {
5555 name => $name,
5556 vendor => $vendor,
5557 product => $product,
5558 domain => $domain,
5559 bus => $bus,
5560 slot => $slot,
5561 func => $func,
5562 irq => $irq,
5563 has_fl_reset => -f "$pcisysfs/devices/$name/reset" || 0,
5564 };
5565
5566 return $res;
5567 }
5568
5569 sub pci_dev_reset {
5570 my ($dev) = @_;
5571
5572 my $name = $dev->{name};
5573
5574 my $fn = "$pcisysfs/devices/$name/reset";
5575
5576 return file_write($fn, "1");
5577 }
5578
5579 sub pci_dev_bind_to_vfio {
5580 my ($dev) = @_;
5581
5582 my $name = $dev->{name};
5583
5584 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5585
5586 if (!-d $vfio_basedir) {
5587 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5588 }
5589 die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir;
5590
5591 my $testdir = "$vfio_basedir/$name";
5592 return 1 if -d $testdir;
5593
5594 my $data = "$dev->{vendor} $dev->{product}";
5595 return undef if !file_write("$vfio_basedir/new_id", $data);
5596
5597 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5598 if (!file_write($fn, $name)) {
5599 return undef if -f $fn;
5600 }
5601
5602 $fn = "$vfio_basedir/bind";
5603 if (! -d $testdir) {
5604 return undef if !file_write($fn, $name);
5605 }
5606
5607 return -d $testdir;
5608 }
5609
5610 sub pci_dev_group_bind_to_vfio {
5611 my ($pciid) = @_;
5612
5613 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5614
5615 if (!-d $vfio_basedir) {
5616 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5617 }
5618 die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir;
5619
5620 # get IOMMU group devices
5621 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5622 my @devs = grep /^0000:/, readdir($D);
5623 closedir($D);
5624
5625 foreach my $pciid (@devs) {
5626 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5627
5628 # pci bridges, switches or root ports are not supported
5629 # they have a pci_bus subdirectory so skip them
5630 next if (-e "$pcisysfs/devices/$pciid/pci_bus");
5631
5632 my $info = pci_device_info($1);
5633 pci_dev_bind_to_vfio($info) || die "Cannot bind $pciid to vfio\n";
5634 }
5635
5636 return 1;
5637 }
5638
5639 # vzdump restore implementaion
5640
5641 sub tar_archive_read_firstfile {
5642 my $archive = shift;
5643
5644 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
5645
5646 # try to detect archive type first
5647 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5648 die "unable to open file '$archive'\n";
5649 my $firstfile = <$fh>;
5650 kill 15, $pid;
5651 close $fh;
5652
5653 die "ERROR: archive contaions no data\n" if !$firstfile;
5654 chomp $firstfile;
5655
5656 return $firstfile;
5657 }
5658
5659 sub tar_restore_cleanup {
5660 my ($storecfg, $statfile) = @_;
5661
5662 print STDERR "starting cleanup\n";
5663
5664 if (my $fd = IO::File->new($statfile, "r")) {
5665 while (defined(my $line = <$fd>)) {
5666 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5667 my $volid = $2;
5668 eval {
5669 if ($volid =~ m|^/|) {
5670 unlink $volid || die 'unlink failed\n';
5671 } else {
5672 PVE::Storage::vdisk_free($storecfg, $volid);
5673 }
5674 print STDERR "temporary volume '$volid' sucessfuly removed\n";
5675 };
5676 print STDERR "unable to cleanup '$volid' - $@" if $@;
5677 } else {
5678 print STDERR "unable to parse line in statfile - $line";
5679 }
5680 }
5681 $fd->close();
5682 }
5683 }
5684
5685 sub restore_archive {
5686 my ($archive, $vmid, $user, $opts) = @_;
5687
5688 my $format = $opts->{format};
5689 my $comp;
5690
5691 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5692 $format = 'tar' if !$format;
5693 $comp = 'gzip';
5694 } elsif ($archive =~ m/\.tar$/) {
5695 $format = 'tar' if !$format;
5696 } elsif ($archive =~ m/.tar.lzo$/) {
5697 $format = 'tar' if !$format;
5698 $comp = 'lzop';
5699 } elsif ($archive =~ m/\.vma$/) {
5700 $format = 'vma' if !$format;
5701 } elsif ($archive =~ m/\.vma\.gz$/) {
5702 $format = 'vma' if !$format;
5703 $comp = 'gzip';
5704 } elsif ($archive =~ m/\.vma\.lzo$/) {
5705 $format = 'vma' if !$format;
5706 $comp = 'lzop';
5707 } else {
5708 $format = 'vma' if !$format; # default
5709 }
5710
5711 # try to detect archive format
5712 if ($format eq 'tar') {
5713 return restore_tar_archive($archive, $vmid, $user, $opts);
5714 } else {
5715 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
5716 }
5717 }
5718
5719 sub restore_update_config_line {
5720 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5721
5722 return if $line =~ m/^\#qmdump\#/;
5723 return if $line =~ m/^\#vzdump\#/;
5724 return if $line =~ m/^lock:/;
5725 return if $line =~ m/^unused\d+:/;
5726 return if $line =~ m/^parent:/;
5727 return if $line =~ m/^template:/; # restored VM is never a template
5728
5729 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
5730 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5731 # try to convert old 1.X settings
5732 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5733 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
5734 my ($model, $macaddr) = split(/\=/, $devconfig);
5735 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
5736 my $net = {
5737 model => $model,
5738 bridge => "vmbr$ind",
5739 macaddr => $macaddr,
5740 };
5741 my $netstr = print_net($net);
5742
5743 print $outfd "net$cookie->{netcount}: $netstr\n";
5744 $cookie->{netcount}++;
5745 }
5746 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5747 my ($id, $netstr) = ($1, $2);
5748 my $net = parse_net($netstr);
5749 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
5750 $netstr = print_net($net);
5751 print $outfd "$id: $netstr\n";
5752 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5753 my $virtdev = $1;
5754 my $value = $3;
5755 my $di = parse_drive($virtdev, $value);
5756 if (defined($di->{backup}) && !$di->{backup}) {
5757 print $outfd "#$line";
5758 } elsif ($map->{$virtdev}) {
5759 delete $di->{format}; # format can change on restore
5760 $di->{file} = $map->{$virtdev};
5761 $value = print_drive($vmid, $di);
5762 print $outfd "$virtdev: $value\n";
5763 } else {
5764 print $outfd $line;
5765 }
5766 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5767 my $vmgenid = $1;
5768 if ($vmgenid ne '0') {
5769 # always generate a new vmgenid if there was a valid one setup
5770 $vmgenid = generate_uuid();
5771 }
5772 print $outfd "vmgenid: $vmgenid\n";
5773 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5774 my ($uuid, $uuid_str);
5775 UUID::generate($uuid);
5776 UUID::unparse($uuid, $uuid_str);
5777 my $smbios1 = parse_smbios1($2);
5778 $smbios1->{uuid} = $uuid_str;
5779 print $outfd $1.print_smbios1($smbios1)."\n";
5780 } else {
5781 print $outfd $line;
5782 }
5783 }
5784
5785 sub scan_volids {
5786 my ($cfg, $vmid) = @_;
5787
5788 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid);
5789
5790 my $volid_hash = {};
5791 foreach my $storeid (keys %$info) {
5792 foreach my $item (@{$info->{$storeid}}) {
5793 next if !($item->{volid} && $item->{size});
5794 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
5795 $volid_hash->{$item->{volid}} = $item;
5796 }
5797 }
5798
5799 return $volid_hash;
5800 }
5801
5802 sub is_volume_in_use {
5803 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5804
5805 my $path = PVE::Storage::path($storecfg, $volid);
5806
5807 my $scan_config = sub {
5808 my ($cref, $snapname) = @_;
5809
5810 foreach my $key (keys %$cref) {
5811 my $value = $cref->{$key};
5812 if (is_valid_drivename($key)) {
5813 next if $skip_drive && $key eq $skip_drive;
5814 my $drive = parse_drive($key, $value);
5815 next if !$drive || !$drive->{file} || drive_is_cdrom($drive);
5816 return 1 if $volid eq $drive->{file};
5817 if ($drive->{file} =~ m!^/!) {
5818 return 1 if $drive->{file} eq $path;
5819 } else {
5820 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
5821 next if !$storeid;
5822 my $scfg = PVE::Storage::storage_config($storecfg, $storeid, 1);
5823 next if !$scfg;
5824 return 1 if $path eq PVE::Storage::path($storecfg, $drive->{file}, $snapname);
5825 }
5826 }
5827 }
5828
5829 return 0;
5830 };
5831
5832 return 1 if &$scan_config($conf);
5833
5834 undef $skip_drive;
5835
5836 foreach my $snapname (keys %{$conf->{snapshots}}) {
5837 return 1 if &$scan_config($conf->{snapshots}->{$snapname}, $snapname);
5838 }
5839
5840 return 0;
5841 }
5842
5843 sub update_disksize {
5844 my ($vmid, $conf, $volid_hash) = @_;
5845
5846 my $changes;
5847 my $prefix = "VM $vmid:";
5848
5849 # used and unused disks
5850 my $referenced = {};
5851
5852 # Note: it is allowed to define multiple storages with same path (alias), so
5853 # we need to check both 'volid' and real 'path' (two different volid can point
5854 # to the same path).
5855
5856 my $referencedpath = {};
5857
5858 # update size info
5859 foreach my $opt (keys %$conf) {
5860 if (is_valid_drivename($opt)) {
5861 my $drive = parse_drive($opt, $conf->{$opt});
5862 my $volid = $drive->{file};
5863 next if !$volid;
5864
5865 $referenced->{$volid} = 1;
5866 if ($volid_hash->{$volid} &&
5867 (my $path = $volid_hash->{$volid}->{path})) {
5868 $referencedpath->{$path} = 1;
5869 }
5870
5871 next if drive_is_cdrom($drive);
5872 next if !$volid_hash->{$volid};
5873
5874 $drive->{size} = $volid_hash->{$volid}->{size};
5875 my $new = print_drive($vmid, $drive);
5876 if ($new ne $conf->{$opt}) {
5877 $changes = 1;
5878 $conf->{$opt} = $new;
5879 print "$prefix update disk '$opt' information.\n";
5880 }
5881 }
5882 }
5883
5884 # remove 'unusedX' entry if volume is used
5885 foreach my $opt (keys %$conf) {
5886 next if $opt !~ m/^unused\d+$/;
5887 my $volid = $conf->{$opt};
5888 my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
5889 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5890 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5891 $changes = 1;
5892 delete $conf->{$opt};
5893 }
5894
5895 $referenced->{$volid} = 1;
5896 $referencedpath->{$path} = 1 if $path;
5897 }
5898
5899 foreach my $volid (sort keys %$volid_hash) {
5900 next if $volid =~ m/vm-$vmid-state-/;
5901 next if $referenced->{$volid};
5902 my $path = $volid_hash->{$volid}->{path};
5903 next if !$path; # just to be sure
5904 next if $referencedpath->{$path};
5905 $changes = 1;
5906 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
5907 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5908 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5909 }
5910
5911 return $changes;
5912 }
5913
5914 sub rescan {
5915 my ($vmid, $nolock, $dryrun) = @_;
5916
5917 my $cfg = PVE::Storage::config();
5918
5919 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5920 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5921 foreach my $stor (keys %{$cfg->{ids}}) {
5922 delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
5923 }
5924
5925 print "rescan volumes...\n";
5926 my $volid_hash = scan_volids($cfg, $vmid);
5927
5928 my $updatefn = sub {
5929 my ($vmid) = @_;
5930
5931 my $conf = PVE::QemuConfig->load_config($vmid);
5932
5933 PVE::QemuConfig->check_lock($conf);
5934
5935 my $vm_volids = {};
5936 foreach my $volid (keys %$volid_hash) {
5937 my $info = $volid_hash->{$volid};
5938 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
5939 }
5940
5941 my $changes = update_disksize($vmid, $conf, $vm_volids);
5942
5943 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
5944 };
5945
5946 if (defined($vmid)) {
5947 if ($nolock) {
5948 &$updatefn($vmid);
5949 } else {
5950 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
5951 }
5952 } else {
5953 my $vmlist = config_list();
5954 foreach my $vmid (keys %$vmlist) {
5955 if ($nolock) {
5956 &$updatefn($vmid);
5957 } else {
5958 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
5959 }
5960 }
5961 }
5962 }
5963
5964 sub restore_vma_archive {
5965 my ($archive, $vmid, $user, $opts, $comp) = @_;
5966
5967 my $readfrom = $archive;
5968
5969 my $cfg = PVE::Storage::config();
5970 my $commands = [];
5971 my $bwlimit = $opts->{bwlimit};
5972
5973 my $dbg_cmdstring = '';
5974 my $add_pipe = sub {
5975 my ($cmd) = @_;
5976 push @$commands, $cmd;
5977 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5978 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
5979 $readfrom = '-';
5980 };
5981
5982 my $input = undef;
5983 if ($archive eq '-') {
5984 $input = '<&STDIN';
5985 } else {
5986 # If we use a backup from a PVE defined storage we also consider that
5987 # storage's rate limit:
5988 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
5989 if (defined($volid)) {
5990 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
5991 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
5992 if ($readlimit) {
5993 print STDERR "applying read rate limit: $readlimit\n";
5994 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5995 $add_pipe->($cstream);
5996 }
5997 }
5998 }
5999
6000 if ($comp) {
6001 my $cmd;
6002 if ($comp eq 'gzip') {
6003 $cmd = ['zcat', $readfrom];
6004 } elsif ($comp eq 'lzop') {
6005 $cmd = ['lzop', '-d', '-c', $readfrom];
6006 } else {
6007 die "unknown compression method '$comp'\n";
6008 }
6009 $add_pipe->($cmd);
6010 }
6011
6012 my $tmpdir = "/var/tmp/vzdumptmp$$";
6013 rmtree $tmpdir;
6014
6015 # disable interrupts (always do cleanups)
6016 local $SIG{INT} =
6017 local $SIG{TERM} =
6018 local $SIG{QUIT} =
6019 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
6020
6021 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6022 POSIX::mkfifo($mapfifo, 0600);
6023 my $fifofh;
6024
6025 my $openfifo = sub {
6026 open($fifofh, '>', $mapfifo) || die $!;
6027 };
6028
6029 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6030
6031 my $oldtimeout;
6032 my $timeout = 5;
6033
6034 my $devinfo = {};
6035
6036 my $rpcenv = PVE::RPCEnvironment::get();
6037
6038 my $conffile = PVE::QemuConfig->config_file($vmid);
6039 my $tmpfn = "$conffile.$$.tmp";
6040
6041 # Note: $oldconf is undef if VM does not exists
6042 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6043 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
6044
6045 my %storage_limits;
6046
6047 my $print_devmap = sub {
6048 my $virtdev_hash = {};
6049
6050 my $cfgfn = "$tmpdir/qemu-server.conf";
6051
6052 # we can read the config - that is already extracted
6053 my $fh = IO::File->new($cfgfn, "r") ||
6054 "unable to read qemu-server.conf - $!\n";
6055
6056 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6057 if (-f $fwcfgfn) {
6058 my $pve_firewall_dir = '/etc/pve/firewall';
6059 mkdir $pve_firewall_dir; # make sure the dir exists
6060 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6061 }
6062
6063 while (defined(my $line = <$fh>)) {
6064 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6065 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6066 die "archive does not contain data for drive '$virtdev'\n"
6067 if !$devinfo->{$devname};
6068 if (defined($opts->{storage})) {
6069 $storeid = $opts->{storage} || 'local';
6070 } elsif (!$storeid) {
6071 $storeid = 'local';
6072 }
6073 $format = 'raw' if !$format;
6074 $devinfo->{$devname}->{devname} = $devname;
6075 $devinfo->{$devname}->{virtdev} = $virtdev;
6076 $devinfo->{$devname}->{format} = $format;
6077 $devinfo->{$devname}->{storeid} = $storeid;
6078
6079 # check permission on storage
6080 my $pool = $opts->{pool}; # todo: do we need that?
6081 if ($user ne 'root@pam') {
6082 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6083 }
6084
6085 $storage_limits{$storeid} = $bwlimit;
6086
6087 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6088 }
6089 }
6090
6091 foreach my $key (keys %storage_limits) {
6092 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
6093 next if !$limit;
6094 print STDERR "rate limit for storage $key: $limit KiB/s\n";
6095 $storage_limits{$key} = $limit * 1024;
6096 }
6097
6098 foreach my $devname (keys %$devinfo) {
6099 die "found no device mapping information for device '$devname'\n"
6100 if !$devinfo->{$devname}->{virtdev};
6101 }
6102
6103 # create empty/temp config
6104 if ($oldconf) {
6105 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
6106 foreach_drive($oldconf, sub {
6107 my ($ds, $drive) = @_;
6108
6109 return if drive_is_cdrom($drive);
6110
6111 my $volid = $drive->{file};
6112
6113 return if !$volid || $volid =~ m|^/|;
6114
6115 my ($path, $owner) = PVE::Storage::path($cfg, $volid);
6116 return if !$path || !$owner || ($owner != $vmid);
6117
6118 # Note: only delete disk we want to restore
6119 # other volumes will become unused
6120 if ($virtdev_hash->{$ds}) {
6121 eval { PVE::Storage::vdisk_free($cfg, $volid); };
6122 if (my $err = $@) {
6123 warn $err;
6124 }
6125 }
6126 });
6127
6128 # delete vmstate files
6129 # since after the restore we have no snapshots anymore
6130 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
6131 my $snap = $oldconf->{snapshots}->{$snapname};
6132 if ($snap->{vmstate}) {
6133 eval { PVE::Storage::vdisk_free($cfg, $snap->{vmstate}); };
6134 if (my $err = $@) {
6135 warn $err;
6136 }
6137 }
6138 }
6139 }
6140
6141 my $map = {};
6142 foreach my $virtdev (sort keys %$virtdev_hash) {
6143 my $d = $virtdev_hash->{$virtdev};
6144 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
6145 my $storeid = $d->{storeid};
6146 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6147
6148 my $map_opts = '';
6149 if (my $limit = $storage_limits{$storeid}) {
6150 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6151 }
6152
6153 # test if requested format is supported
6154 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $storeid);
6155 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6156 $d->{format} = $defFormat if !$supported;
6157
6158 my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid,
6159 $d->{format}, undef, $alloc_size);
6160 print STDERR "new volume ID is '$volid'\n";
6161 $d->{volid} = $volid;
6162 my $path = PVE::Storage::path($cfg, $volid);
6163
6164 PVE::Storage::activate_volumes($cfg,[$volid]);
6165
6166 my $write_zeros = 1;
6167 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
6168 $write_zeros = 0;
6169 }
6170
6171 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6172
6173 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6174 $map->{$virtdev} = $volid;
6175 }
6176
6177 $fh->seek(0, 0) || die "seek failed - $!\n";
6178
6179 my $outfd = new IO::File ($tmpfn, "w") ||
6180 die "unable to write config for VM $vmid\n";
6181
6182 my $cookie = { netcount => 0 };
6183 while (defined(my $line = <$fh>)) {
6184 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
6185 }
6186
6187 $fh->close();
6188 $outfd->close();
6189 };
6190
6191 eval {
6192 # enable interrupts
6193 local $SIG{INT} =
6194 local $SIG{TERM} =
6195 local $SIG{QUIT} =
6196 local $SIG{HUP} =
6197 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
6198 local $SIG{ALRM} = sub { die "got timeout\n"; };
6199
6200 $oldtimeout = alarm($timeout);
6201
6202 my $parser = sub {
6203 my $line = shift;
6204
6205 print "$line\n";
6206
6207 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6208 my ($dev_id, $size, $devname) = ($1, $2, $3);
6209 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6210 } elsif ($line =~ m/^CTIME: /) {
6211 # we correctly received the vma config, so we can disable
6212 # the timeout now for disk allocation (set to 10 minutes, so
6213 # that we always timeout if something goes wrong)
6214 alarm(600);
6215 &$print_devmap();
6216 print $fifofh "done\n";
6217 my $tmp = $oldtimeout || 0;
6218 $oldtimeout = undef;
6219 alarm($tmp);
6220 close($fifofh);
6221 }
6222 };
6223
6224 print "restore vma archive: $dbg_cmdstring\n";
6225 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
6226 };
6227 my $err = $@;
6228
6229 alarm($oldtimeout) if $oldtimeout;
6230
6231 my $vollist = [];
6232 foreach my $devname (keys %$devinfo) {
6233 my $volid = $devinfo->{$devname}->{volid};
6234 push @$vollist, $volid if $volid;
6235 }
6236
6237 PVE::Storage::deactivate_volumes($cfg, $vollist);
6238
6239 unlink $mapfifo;
6240
6241 if ($err) {
6242 rmtree $tmpdir;
6243 unlink $tmpfn;
6244
6245 foreach my $devname (keys %$devinfo) {
6246 my $volid = $devinfo->{$devname}->{volid};
6247 next if !$volid;
6248 eval {
6249 if ($volid =~ m|^/|) {
6250 unlink $volid || die 'unlink failed\n';
6251 } else {
6252 PVE::Storage::vdisk_free($cfg, $volid);
6253 }
6254 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6255 };
6256 print STDERR "unable to cleanup '$volid' - $@" if $@;
6257 }
6258 die $err;
6259 }
6260
6261 rmtree $tmpdir;
6262
6263 rename($tmpfn, $conffile) ||
6264 die "unable to commit configuration file '$conffile'\n";
6265
6266 PVE::Cluster::cfs_update(); # make sure we read new file
6267
6268 eval { rescan($vmid, 1); };
6269 warn $@ if $@;
6270 }
6271
6272 sub restore_tar_archive {
6273 my ($archive, $vmid, $user, $opts) = @_;
6274
6275 if ($archive ne '-') {
6276 my $firstfile = tar_archive_read_firstfile($archive);
6277 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6278 if $firstfile ne 'qemu-server.conf';
6279 }
6280
6281 my $storecfg = PVE::Storage::config();
6282
6283 # destroy existing data - keep empty config
6284 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
6285 destroy_vm($storecfg, $vmid, 1) if -f $vmcfgfn;
6286
6287 my $tocmd = "/usr/lib/qemu-server/qmextract";
6288
6289 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
6290 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
6291 $tocmd .= ' --prealloc' if $opts->{prealloc};
6292 $tocmd .= ' --info' if $opts->{info};
6293
6294 # tar option "xf" does not autodetect compression when read from STDIN,
6295 # so we pipe to zcat
6296 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6297 PVE::Tools::shellquote("--to-command=$tocmd");
6298
6299 my $tmpdir = "/var/tmp/vzdumptmp$$";
6300 mkpath $tmpdir;
6301
6302 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6303 local $ENV{VZDUMP_VMID} = $vmid;
6304 local $ENV{VZDUMP_USER} = $user;
6305
6306 my $conffile = PVE::QemuConfig->config_file($vmid);
6307 my $tmpfn = "$conffile.$$.tmp";
6308
6309 # disable interrupts (always do cleanups)
6310 local $SIG{INT} =
6311 local $SIG{TERM} =
6312 local $SIG{QUIT} =
6313 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
6314
6315 eval {
6316 # enable interrupts
6317 local $SIG{INT} =
6318 local $SIG{TERM} =
6319 local $SIG{QUIT} =
6320 local $SIG{HUP} =
6321 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
6322
6323 if ($archive eq '-') {
6324 print "extracting archive from STDIN\n";
6325 run_command($cmd, input => "<&STDIN");
6326 } else {
6327 print "extracting archive '$archive'\n";
6328 run_command($cmd);
6329 }
6330
6331 return if $opts->{info};
6332
6333 # read new mapping
6334 my $map = {};
6335 my $statfile = "$tmpdir/qmrestore.stat";
6336 if (my $fd = IO::File->new($statfile, "r")) {
6337 while (defined (my $line = <$fd>)) {
6338 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6339 $map->{$1} = $2 if $1;
6340 } else {
6341 print STDERR "unable to parse line in statfile - $line\n";
6342 }
6343 }
6344 $fd->close();
6345 }
6346
6347 my $confsrc = "$tmpdir/qemu-server.conf";
6348
6349 my $srcfd = new IO::File($confsrc, "r") ||
6350 die "unable to open file '$confsrc'\n";
6351
6352 my $outfd = new IO::File ($tmpfn, "w") ||
6353 die "unable to write config for VM $vmid\n";
6354
6355 my $cookie = { netcount => 0 };
6356 while (defined (my $line = <$srcfd>)) {
6357 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
6358 }
6359
6360 $srcfd->close();
6361 $outfd->close();
6362 };
6363 my $err = $@;
6364
6365 if ($err) {
6366
6367 unlink $tmpfn;
6368
6369 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
6370
6371 die $err;
6372 }
6373
6374 rmtree $tmpdir;
6375
6376 rename $tmpfn, $conffile ||
6377 die "unable to commit configuration file '$conffile'\n";
6378
6379 PVE::Cluster::cfs_update(); # make sure we read new file
6380
6381 eval { rescan($vmid, 1); };
6382 warn $@ if $@;
6383 };
6384
6385 sub foreach_storage_used_by_vm {
6386 my ($conf, $func) = @_;
6387
6388 my $sidhash = {};
6389
6390 foreach_drive($conf, sub {
6391 my ($ds, $drive) = @_;
6392 return if drive_is_cdrom($drive);
6393
6394 my $volid = $drive->{file};
6395
6396 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
6397 $sidhash->{$sid} = $sid if $sid;
6398 });
6399
6400 foreach my $sid (sort keys %$sidhash) {
6401 &$func($sid);
6402 }
6403 }
6404
6405 sub do_snapshots_with_qemu {
6406 my ($storecfg, $volid) = @_;
6407
6408 my $storage_name = PVE::Storage::parse_volume_id($volid);
6409
6410 if ($qemu_snap_storage->{$storecfg->{ids}->{$storage_name}->{type}}
6411 && !$storecfg->{ids}->{$storage_name}->{krbd}){
6412 return 1;
6413 }
6414
6415 if ($volid =~ m/\.(qcow2|qed)$/){
6416 return 1;
6417 }
6418
6419 return undef;
6420 }
6421
6422 sub qga_check_running {
6423 my ($vmid, $nowarn) = @_;
6424
6425 eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
6426 if ($@) {
6427 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6428 return 0;
6429 }
6430 return 1;
6431 }
6432
6433 sub template_create {
6434 my ($vmid, $conf, $disk) = @_;
6435
6436 my $storecfg = PVE::Storage::config();
6437
6438 foreach_drive($conf, sub {
6439 my ($ds, $drive) = @_;
6440
6441 return if drive_is_cdrom($drive);
6442 return if $disk && $ds ne $disk;
6443
6444 my $volid = $drive->{file};
6445 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
6446
6447 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
6448 $drive->{file} = $voliddst;
6449 $conf->{$ds} = print_drive($vmid, $drive);
6450 PVE::QemuConfig->write_config($vmid, $conf);
6451 });
6452 }
6453
6454 sub qemu_img_convert {
6455 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6456
6457 my $storecfg = PVE::Storage::config();
6458 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
6459 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
6460
6461 if ($src_storeid && $dst_storeid) {
6462
6463 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
6464
6465 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
6466 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6467
6468 my $src_format = qemu_img_format($src_scfg, $src_volname);
6469 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
6470
6471 my $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
6472 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6473
6474 my $cmd = [];
6475 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6476 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6477 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
6478 push @$cmd, '-T', 'none' if $src_scfg->{type} eq 'zfspool';
6479 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6480 if ($is_zero_initialized) {
6481 push @$cmd, "zeroinit:$dst_path";
6482 } else {
6483 push @$cmd, $dst_path;
6484 }
6485
6486 my $parser = sub {
6487 my $line = shift;
6488 if($line =~ m/\((\S+)\/100\%\)/){
6489 my $percent = $1;
6490 my $transferred = int($size * $percent / 100);
6491 my $remaining = $size - $transferred;
6492
6493 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6494 }
6495
6496 };
6497
6498 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
6499 my $err = $@;
6500 die "copy failed: $err" if $err;
6501 }
6502 }
6503
6504 sub qemu_img_format {
6505 my ($scfg, $volname) = @_;
6506
6507 if ($scfg->{path} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6508 return $1;
6509 } else {
6510 return "raw";
6511 }
6512 }
6513
6514 sub qemu_drive_mirror {
6515 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6516
6517 $jobs = {} if !$jobs;
6518
6519 my $qemu_target;
6520 my $format;
6521 $jobs->{"drive-$drive"} = {};
6522
6523 if ($dst_volid =~ /^nbd:/) {
6524 $qemu_target = $dst_volid;
6525 $format = "nbd";
6526 } else {
6527 my $storecfg = PVE::Storage::config();
6528 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
6529
6530 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6531
6532 $format = qemu_img_format($dst_scfg, $dst_volname);
6533
6534 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6535
6536 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
6537 }
6538
6539 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
6540 $opts->{format} = $format if $format;
6541
6542 print "drive mirror is starting for drive-$drive\n";
6543
6544 eval { vm_mon_cmd($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6545
6546 if (my $err = $@) {
6547 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6548 die "mirroring error: $err";
6549 }
6550
6551 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6552 }
6553
6554 sub qemu_drive_mirror_monitor {
6555 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6556
6557 eval {
6558 my $err_complete = 0;
6559
6560 while (1) {
6561 die "storage migration timed out\n" if $err_complete > 300;
6562
6563 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
6564
6565 my $running_mirror_jobs = {};
6566 foreach my $stat (@$stats) {
6567 next if $stat->{type} ne 'mirror';
6568 $running_mirror_jobs->{$stat->{device}} = $stat;
6569 }
6570
6571 my $readycounter = 0;
6572
6573 foreach my $job (keys %$jobs) {
6574
6575 if(defined($jobs->{$job}->{complete}) && !defined($running_mirror_jobs->{$job})) {
6576 print "$job : finished\n";
6577 delete $jobs->{$job};
6578 next;
6579 }
6580
6581 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6582
6583 my $busy = $running_mirror_jobs->{$job}->{busy};
6584 my $ready = $running_mirror_jobs->{$job}->{ready};
6585 if (my $total = $running_mirror_jobs->{$job}->{len}) {
6586 my $transferred = $running_mirror_jobs->{$job}->{offset} || 0;
6587 my $remaining = $total - $transferred;
6588 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6589
6590 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6591 }
6592
6593 $readycounter++ if $running_mirror_jobs->{$job}->{ready};
6594 }
6595
6596 last if scalar(keys %$jobs) == 0;
6597
6598 if ($readycounter == scalar(keys %$jobs)) {
6599 print "all mirroring jobs are ready \n";
6600 last if $skipcomplete; #do the complete later
6601
6602 if ($vmiddst && $vmiddst != $vmid) {
6603 my $agent_running = $qga && qga_check_running($vmid);
6604 if ($agent_running) {
6605 print "freeze filesystem\n";
6606 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-freeze"); };
6607 } else {
6608 print "suspend vm\n";
6609 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
6610 }
6611
6612 # if we clone a disk for a new target vm, we don't switch the disk
6613 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
6614
6615 if ($agent_running) {
6616 print "unfreeze filesystem\n";
6617 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-thaw"); };
6618 } else {
6619 print "resume vm\n";
6620 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
6621 }
6622
6623 last;
6624 } else {
6625
6626 foreach my $job (keys %$jobs) {
6627 # try to switch the disk if source and destination are on the same guest
6628 print "$job: Completing block job...\n";
6629
6630 eval { vm_mon_cmd($vmid, "block-job-complete", device => $job) };
6631 if ($@ =~ m/cannot be completed/) {
6632 print "$job: Block job cannot be completed, try again.\n";
6633 $err_complete++;
6634 }else {
6635 print "$job: Completed successfully.\n";
6636 $jobs->{$job}->{complete} = 1;
6637 }
6638 }
6639 }
6640 }
6641 sleep 1;
6642 }
6643 };
6644 my $err = $@;
6645
6646 if ($err) {
6647 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6648 die "mirroring error: $err";
6649 }
6650
6651 }
6652
6653 sub qemu_blockjobs_cancel {
6654 my ($vmid, $jobs) = @_;
6655
6656 foreach my $job (keys %$jobs) {
6657 print "$job: Cancelling block job\n";
6658 eval { vm_mon_cmd($vmid, "block-job-cancel", device => $job); };
6659 $jobs->{$job}->{cancel} = 1;
6660 }
6661
6662 while (1) {
6663 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
6664
6665 my $running_jobs = {};
6666 foreach my $stat (@$stats) {
6667 $running_jobs->{$stat->{device}} = $stat;
6668 }
6669
6670 foreach my $job (keys %$jobs) {
6671
6672 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
6673 print "$job: Done.\n";
6674 delete $jobs->{$job};
6675 }
6676 }
6677
6678 last if scalar(keys %$jobs) == 0;
6679
6680 sleep 1;
6681 }
6682 }
6683
6684 sub clone_disk {
6685 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6686 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6687
6688 my $newvolid;
6689
6690 if (!$full) {
6691 print "create linked clone of drive $drivename ($drive->{file})\n";
6692 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
6693 push @$newvollist, $newvolid;
6694 } else {
6695
6696 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
6697 $storeid = $storage if $storage;
6698
6699 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
6700 my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
6701
6702 print "create full clone of drive $drivename ($drive->{file})\n";
6703 my $name = undef;
6704 if (drive_is_cloudinit($drive)) {
6705 $name = "vm-$newvmid-cloudinit";
6706 # cloudinit only supports raw and qcow2 atm:
6707 if ($dst_format eq 'qcow2') {
6708 $name .= '.qcow2';
6709 } elsif ($dst_format ne 'raw') {
6710 die "clone: unhandled format for cloudinit image\n";
6711 }
6712 }
6713 $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6714 push @$newvollist, $newvolid;
6715
6716 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
6717
6718 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
6719 if (!$running || $snapname) {
6720 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
6721 } else {
6722
6723 my $kvmver = get_running_qemu_version ($vmid);
6724 if (!qemu_machine_feature_enabled (undef, $kvmver, 2, 7)) {
6725 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6726 if $drive->{iothread};
6727 }
6728
6729 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6730 }
6731 }
6732
6733 my ($size) = PVE::Storage::volume_size_info($storecfg, $newvolid, 3);
6734
6735 my $disk = $drive;
6736 $disk->{format} = undef;
6737 $disk->{file} = $newvolid;
6738 $disk->{size} = $size;
6739
6740 return $disk;
6741 }
6742
6743 # this only works if VM is running
6744 sub get_current_qemu_machine {
6745 my ($vmid) = @_;
6746
6747 my $cmd = { execute => 'query-machines', arguments => {} };
6748 my $res = vm_qmp_command($vmid, $cmd);
6749
6750 my ($current, $default);
6751 foreach my $e (@$res) {
6752 $default = $e->{name} if $e->{'is-default'};
6753 $current = $e->{name} if $e->{'is-current'};
6754 }
6755
6756 # fallback to the default machine if current is not supported by qemu
6757 return $current || $default || 'pc';
6758 }
6759
6760 sub get_running_qemu_version {
6761 my ($vmid) = @_;
6762 my $cmd = { execute => 'query-version', arguments => {} };
6763 my $res = vm_qmp_command($vmid, $cmd);
6764 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6765 }
6766
6767 sub qemu_machine_feature_enabled {
6768 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6769
6770 my $current_major;
6771 my $current_minor;
6772
6773 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6774
6775 $current_major = $3;
6776 $current_minor = $4;
6777
6778 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6779
6780 $current_major = $1;
6781 $current_minor = $2;
6782 }
6783
6784 return 1 if $current_major > $version_major ||
6785 ($current_major == $version_major &&
6786 $current_minor >= $version_minor);
6787 }
6788
6789 sub qemu_machine_pxe {
6790 my ($vmid, $conf, $machine) = @_;
6791
6792 $machine = PVE::QemuServer::get_current_qemu_machine($vmid) if !$machine;
6793
6794 if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
6795 $machine .= '.pxe';
6796 }
6797
6798 return $machine;
6799 }
6800
6801 sub qemu_use_old_bios_files {
6802 my ($machine_type) = @_;
6803
6804 return if !$machine_type;
6805
6806 my $use_old_bios_files = undef;
6807
6808 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6809 $machine_type = $1;
6810 $use_old_bios_files = 1;
6811 } else {
6812 my $kvmver = kvm_user_version();
6813 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6814 # load new efi bios files on migration. So this hack is required to allow
6815 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6816 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6817 $use_old_bios_files = !qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 4);
6818 }
6819
6820 return ($use_old_bios_files, $machine_type);
6821 }
6822
6823 sub create_efidisk($$$$$) {
6824 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6825
6826 my (undef, $ovmf_vars) = get_ovmf_files($arch);
6827 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
6828
6829 my $vars_size = PVE::Tools::convert_size(-s $ovmf_vars, 'b' => 'kb');
6830 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6831 PVE::Storage::activate_volumes($storecfg, [$volid]);
6832
6833 my $path = PVE::Storage::path($storecfg, $volid);
6834 eval {
6835 run_command(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6836 };
6837 die "Copying EFI vars image failed: $@" if $@;
6838
6839 return ($volid, $vars_size);
6840 }
6841
6842 sub lspci {
6843
6844 my $devices = {};
6845
6846 dir_glob_foreach("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6847 my (undef, $id, $function) = @_;
6848 my $res = { id => $id, function => $function};
6849 push @{$devices->{$id}}, $res;
6850 });
6851
6852 # Entries should be sorted by functions.
6853 foreach my $id (keys %$devices) {
6854 my $dev = $devices->{$id};
6855 $devices->{$id} = [ sort { $a->{function} <=> $b->{function} } @$dev ];
6856 }
6857
6858 return $devices;
6859 }
6860
6861 sub vm_iothreads_list {
6862 my ($vmid) = @_;
6863
6864 my $res = vm_mon_cmd($vmid, 'query-iothreads');
6865
6866 my $iothreads = {};
6867 foreach my $iothread (@$res) {
6868 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
6869 }
6870
6871 return $iothreads;
6872 }
6873
6874 sub scsihw_infos {
6875 my ($conf, $drive) = @_;
6876
6877 my $maxdev = 0;
6878
6879 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
6880 $maxdev = 7;
6881 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
6882 $maxdev = 1;
6883 } else {
6884 $maxdev = 256;
6885 }
6886
6887 my $controller = int($drive->{index} / $maxdev);
6888 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
6889
6890 return ($maxdev, $controller, $controller_prefix);
6891 }
6892
6893 sub add_hyperv_enlightenments {
6894 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6895
6896 return if $winversion < 6;
6897 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6898
6899 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6900
6901 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
6902 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6903 push @$cpuFlags , 'hv_vapic';
6904 push @$cpuFlags , 'hv_time';
6905 } else {
6906 push @$cpuFlags , 'hv_spinlocks=0xffff';
6907 }
6908
6909 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 6)) {
6910 push @$cpuFlags , 'hv_reset';
6911 push @$cpuFlags , 'hv_vpindex';
6912 push @$cpuFlags , 'hv_runtime';
6913 }
6914
6915 if ($winversion >= 7) {
6916 push @$cpuFlags , 'hv_relaxed';
6917
6918 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 12)) {
6919 push @$cpuFlags , 'hv_synic';
6920 push @$cpuFlags , 'hv_stimer';
6921 }
6922 }
6923 }
6924
6925 sub windows_version {
6926 my ($ostype) = @_;
6927
6928 return 0 if !$ostype;
6929
6930 my $winversion = 0;
6931
6932 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6933 $winversion = 5;
6934 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6935 $winversion = 6;
6936 } elsif ($ostype =~ m/^win(\d+)$/) {
6937 $winversion = $1;
6938 }
6939
6940 return $winversion;
6941 }
6942
6943 sub resolve_dst_disk_format {
6944 my ($storecfg, $storeid, $src_volname, $format) = @_;
6945 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
6946
6947 if (!$format) {
6948 # if no target format is specified, use the source disk format as hint
6949 if ($src_volname) {
6950 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6951 $format = qemu_img_format($scfg, $src_volname);
6952 } else {
6953 return $defFormat;
6954 }
6955 }
6956
6957 # test if requested format is supported - else use default
6958 my $supported = grep { $_ eq $format } @$validFormats;
6959 $format = $defFormat if !$supported;
6960 return $format;
6961 }
6962
6963 sub resolve_first_disk {
6964 my $conf = shift;
6965 my @disks = PVE::QemuServer::valid_drive_names();
6966 my $firstdisk;
6967 foreach my $ds (reverse @disks) {
6968 next if !$conf->{$ds};
6969 my $disk = PVE::QemuServer::parse_drive($ds, $conf->{$ds});
6970 next if PVE::QemuServer::drive_is_cdrom($disk);
6971 $firstdisk = $ds;
6972 }
6973 return $firstdisk;
6974 }
6975
6976 sub generate_uuid {
6977 my ($uuid, $uuid_str);
6978 UUID::generate($uuid);
6979 UUID::unparse($uuid, $uuid_str);
6980 return $uuid_str;
6981 }
6982
6983 sub generate_smbios1_uuid {
6984 return "uuid=".generate_uuid();
6985 }
6986
6987 sub nbd_stop {
6988 my ($vmid) = @_;
6989
6990 vm_mon_cmd($vmid, 'nbd-server-stop');
6991 }
6992
6993 # bash completion helper
6994
6995 sub complete_backup_archives {
6996 my ($cmdname, $pname, $cvalue) = @_;
6997
6998 my $cfg = PVE::Storage::config();
6999
7000 my $storeid;
7001
7002 if ($cvalue =~ m/^([^:]+):/) {
7003 $storeid = $1;
7004 }
7005
7006 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
7007
7008 my $res = [];
7009 foreach my $id (keys %$data) {
7010 foreach my $item (@{$data->{$id}}) {
7011 next if $item->{format} !~ m/^vma\.(gz|lzo)$/;
7012 push @$res, $item->{volid} if defined($item->{volid});
7013 }
7014 }
7015
7016 return $res;
7017 }
7018
7019 my $complete_vmid_full = sub {
7020 my ($running) = @_;
7021
7022 my $idlist = vmstatus();
7023
7024 my $res = [];
7025
7026 foreach my $id (keys %$idlist) {
7027 my $d = $idlist->{$id};
7028 if (defined($running)) {
7029 next if $d->{template};
7030 next if $running && $d->{status} ne 'running';
7031 next if !$running && $d->{status} eq 'running';
7032 }
7033 push @$res, $id;
7034
7035 }
7036 return $res;
7037 };
7038
7039 sub complete_vmid {
7040 return &$complete_vmid_full();
7041 }
7042
7043 sub complete_vmid_stopped {
7044 return &$complete_vmid_full(0);
7045 }
7046
7047 sub complete_vmid_running {
7048 return &$complete_vmid_full(1);
7049 }
7050
7051 sub complete_storage {
7052
7053 my $cfg = PVE::Storage::config();
7054 my $ids = $cfg->{ids};
7055
7056 my $res = [];
7057 foreach my $sid (keys %$ids) {
7058 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
7059 next if !$ids->{$sid}->{content}->{images};
7060 push @$res, $sid;
7061 }
7062
7063 return $res;
7064 }
7065
7066 1;