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