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