1 package PVE
::QemuServer
;
11 use File
::Copy
qw(copy);
24 use Storable
qw(dclone);
25 use Time
::HiRes
qw(gettimeofday);
29 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
30 use PVE
::DataCenterConfig
;
31 use PVE
::Exception
qw(raise raise_param_exc);
32 use PVE
::GuestHelpers
qw(safe_string_ne safe_num_ne safe_boolean_ne);
34 use PVE
::JSONSchema
qw(get_standard_option);
36 use PVE
::RPCEnvironment
;
40 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
44 use PVE
::QemuServer
::Helpers
qw(min_version config_aware_timeout);
45 use PVE
::QemuServer
::Cloudinit
;
46 use PVE
::QemuServer
::CPUConfig
qw(print_cpu_device get_cpu_options);
47 use PVE
::QemuServer
::Drive
qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom parse_drive print_drive foreach_drive foreach_volid);
48 use PVE
::QemuServer
::Machine
;
49 use PVE
::QemuServer
::Memory
;
50 use PVE
::QemuServer
::Monitor
qw(mon_cmd);
51 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr print_pcie_root_port);
52 use PVE
::QemuServer
::USB
qw(parse_usb_device);
56 require PVE
::Network
::SDN
::Zones
;
60 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
63 "$EDK2_FW_BASE/OVMF_CODE.fd",
64 "$EDK2_FW_BASE/OVMF_VARS.fd"
67 "$EDK2_FW_BASE/AAVMF_CODE.fd",
68 "$EDK2_FW_BASE/AAVMF_VARS.fd"
72 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
74 # Note about locking: we use flock on the config file protect
75 # against concurent actions.
76 # Aditionaly, we have a 'lock' setting in the config file. This
77 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
78 # allowed when such lock is set. But you can ignore this kind of
79 # lock with the --skiplock flag.
81 cfs_register_file
('/qemu-server/',
85 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
86 description
=> "Some command save/restore state from this location.",
92 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
93 description
=> "Specifies the Qemu machine type.",
95 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
100 #no warnings 'redefine';
103 my ($controller, $vmid, $option, $value) = @_;
105 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
106 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
112 $nodename_cache //= PVE
::INotify
::nodename
();
113 return $nodename_cache;
120 enum
=> [qw(i6300esb ib700)],
121 description
=> "Watchdog type to emulate.",
122 default => 'i6300esb',
127 enum
=> [qw(reset shutdown poweroff pause debug none)],
128 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
132 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
136 description
=> "Enable/disable Qemu GuestAgent.",
141 fstrim_cloned_disks
=> {
142 description
=> "Run fstrim after cloning/moving a disk.",
148 description
=> "Select the agent type",
152 enum
=> [qw(virtio isa)],
158 description
=> "Select the VGA type.",
163 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
166 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
178 description
=> "The size of the file in MB.",
182 pattern
=> '[a-zA-Z0-9\-]+',
184 format_description
=> 'string',
185 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
192 enum
=> [qw(ich9-intel-hda intel-hda AC97)],
193 description
=> "Configure an audio device."
200 description
=> "Driver backend for the audio device."
204 my $spice_enhancements_fmt = {
209 description
=> "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
213 enum
=> ['off', 'all', 'filter'],
216 description
=> "Enable video streaming. Uses compression for detected video streams."
223 enum
=> ['/dev/urandom', '/dev/random', '/dev/hwrng'],
225 description
=> "The file on the host to gather entropy from. In most"
226 . " cases /dev/urandom should be preferred over /dev/random"
227 . " to avoid entropy-starvation issues on the host. Using"
228 . " urandom does *not* decrease security in any meaningful"
229 . " way, as it's still seeded from real entropy, and the"
230 . " bytes provided will most likely be mixed with real"
231 . " entropy on the guest as well. /dev/hwrng can be used"
232 . " to pass through a hardware RNG from the host.",
236 description
=> "Maximum bytes of entropy injected into the guest every"
237 . " 'period' milliseconds. Prefer a lower value when using"
238 . " /dev/random as source. Use 0 to disable limiting"
239 . " (potentially dangerous!).",
242 # default is 1 KiB/s, provides enough entropy to the guest to avoid
243 # boot-starvation issues (e.g. systemd etc...) while allowing no chance
244 # of overwhelming the host, provided we're reading from /dev/urandom
249 description
=> "Every 'period' milliseconds the entropy-injection quota"
250 . " is reset, allowing the guest to retrieve another"
251 . " 'max_bytes' of entropy.",
261 description
=> "Specifies whether a VM will be started during system bootup.",
267 description
=> "Automatic restart after crash (currently ignored).",
272 type
=> 'string', format
=> 'pve-hotplug-features',
273 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'.",
274 default => 'network,disk,usb',
279 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
285 description
=> "Lock/unlock the VM.",
286 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
291 description
=> "Limit of CPU usage.",
292 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.",
300 description
=> "CPU weight for a VM.",
301 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.",
309 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
316 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
322 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
330 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
331 "It should not be necessary to set it.",
332 enum
=> PVE
::Tools
::kvmkeymaplist
(),
337 type
=> 'string', format
=> 'dns-name',
338 description
=> "Set a name for the VM. Only used on the configuration web interface.",
343 description
=> "SCSI controller model",
344 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
350 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
355 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
356 description
=> "Specify guest operating system.",
357 verbose_description
=> <<EODESC,
358 Specify guest operating system. This is used to enable special
359 optimization/features for specific operating systems:
362 other;; unspecified OS
363 wxp;; Microsoft Windows XP
364 w2k;; Microsoft Windows 2000
365 w2k3;; Microsoft Windows 2003
366 w2k8;; Microsoft Windows 2008
367 wvista;; Microsoft Windows Vista
368 win7;; Microsoft Windows 7
369 win8;; Microsoft Windows 8/2012/2012r2
370 win10;; Microsoft Windows 10/2016
371 l24;; Linux 2.4 Kernel
372 l26;; Linux 2.6 - 5.X Kernel
373 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
379 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
380 pattern
=> '[acdn]{1,4}',
385 type
=> 'string', format
=> 'pve-qm-bootdisk',
386 description
=> "Enable booting from specified disk.",
387 pattern
=> '(ide|sata|scsi|virtio)\d+',
392 description
=> "The number of CPUs. Please use option -sockets instead.",
399 description
=> "The number of CPU sockets.",
406 description
=> "The number of cores per socket.",
413 description
=> "Enable/disable NUMA.",
419 description
=> "Enable/disable hugepages memory.",
420 enum
=> [qw(any 2 1024)],
425 description
=> "Number of hotplugged vcpus.",
432 description
=> "Enable/disable ACPI.",
437 description
=> "Enable/disable Qemu GuestAgent and its properties.",
439 format
=> $agent_fmt,
444 description
=> "Enable/disable KVM hardware virtualization.",
450 description
=> "Enable/disable time drift fix.",
456 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
461 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
465 type
=> 'string', format
=> $vga_fmt,
466 description
=> "Configure the VGA hardware.",
467 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
468 "high resolution modes (>= 1280x1024x16) you may need to increase " .
469 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
470 "is 'std' for all OS types besides some Windows versions (XP and " .
471 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
472 "display server. For win* OS you can select how many independent " .
473 "displays you want, Linux guests can add displays them self.\n".
474 "You can also run without any graphic card, using a serial device as terminal.",
478 type
=> 'string', format
=> 'pve-qm-watchdog',
479 description
=> "Create a virtual hardware watchdog device.",
480 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
481 " (by a guest action), the watchdog must be periodically polled " .
482 "by an agent inside the guest or else the watchdog will reset " .
483 "the guest (or execute the respective action specified)",
488 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
489 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'.",
490 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
493 startup
=> get_standard_option
('pve-startup-order'),
497 description
=> "Enable/disable Template.",
503 description
=> "Arbitrary arguments passed to kvm.",
504 verbose_description
=> <<EODESCR,
505 Arbitrary arguments passed to kvm, for example:
507 args: -no-reboot -no-hpet
509 NOTE: this option is for experts only.
516 description
=> "Enable/disable the USB tablet device.",
517 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
518 "usually needed to allow absolute mouse positioning with VNC. " .
519 "Else the mouse runs out of sync with normal VNC clients. " .
520 "If you're running lots of console-only guests on one host, " .
521 "you may consider disabling this to save some context switches. " .
522 "This is turned off by default if you use spice (-vga=qxl).",
527 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
531 migrate_downtime
=> {
534 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
540 type
=> 'string', format
=> 'pve-qm-ide',
541 typetext
=> '<volume>',
542 description
=> "This is an alias for option -ide2",
546 description
=> "Emulated CPU type.",
548 format
=> 'pve-vm-cpu-conf',
550 parent
=> get_standard_option
('pve-snapshot-name', {
552 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
556 description
=> "Timestamp for snapshots.",
562 type
=> 'string', format
=> 'pve-volume-id',
563 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
565 vmstatestorage
=> get_standard_option
('pve-storage-id', {
566 description
=> "Default storage for VM state volumes/files.",
569 runningmachine
=> get_standard_option
('pve-qemu-machine', {
570 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
572 machine
=> get_standard_option
('pve-qemu-machine'),
574 description
=> "Virtual processor architecture. Defaults to the host.",
577 enum
=> [qw(x86_64 aarch64)],
580 description
=> "Specify SMBIOS type 1 fields.",
581 type
=> 'string', format
=> 'pve-qm-smbios1',
588 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
594 enum
=> [ qw(seabios ovmf) ],
595 description
=> "Select BIOS implementation.",
596 default => 'seabios',
600 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
601 format_description
=> 'UUID',
602 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
603 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
604 " 128-bit integer value identifier to the guest OS. This allows to".
605 " notify the guest operating system when the virtual machine is".
606 " executed with a different configuration (e.g. snapshot execution".
607 " or creation from a template). The guest operating system notices".
608 " the change, and is then able to react as appropriate by marking".
609 " its copies of distributed databases as dirty, re-initializing its".
610 " random number generator, etc.\n".
611 "Note that auto-creation only works when done throug API/CLI create".
612 " or update methods, but not when manually editing the config file.",
613 default => "1 (autogenerated)",
618 format
=> 'pve-volume-id',
620 description
=> "Script that will be executed during various steps in the vms lifetime.",
624 format
=> $ivshmem_fmt,
625 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
630 format
=> $audio_fmt,
631 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
634 spice_enhancements
=> {
636 format
=> $spice_enhancements_fmt,
637 description
=> "Configure additional enhancements for SPICE.",
641 type
=> 'string', format
=> 'pve-tag-list',
642 description
=> 'Tags of the VM. This is only meta information.',
648 description
=> "Configure a VirtIO-based Random Number Generator.",
657 description
=> 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
658 format
=> 'pve-volume-id',
659 format_description
=> 'volume',
664 description
=> 'Specify a custom file containing all network data passed to the VM via cloud-init.',
665 format
=> 'pve-volume-id',
666 format_description
=> 'volume',
671 description
=> 'Specify a custom file containing all user data passed to the VM via cloud-init.',
672 format
=> 'pve-volume-id',
673 format_description
=> 'volume',
676 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
678 my $confdesc_cloudinit = {
682 description
=> 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
683 enum
=> ['configdrive2', 'nocloud'],
688 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
693 description
=> 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
698 description
=> 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
699 format
=> 'pve-qm-cicustom',
704 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.",
708 type
=> 'string', format
=> 'address-list',
709 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.",
714 format
=> 'urlencoded',
715 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
719 # what about other qemu settings ?
721 #machine => 'string',
734 ##soundhw => 'string',
736 while (my ($k, $v) = each %$confdesc) {
737 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
740 my $MAX_USB_DEVICES = 5;
742 my $MAX_HOSTPCI_DEVICES = 16;
743 my $MAX_SERIAL_PORTS = 4;
744 my $MAX_PARALLEL_PORTS = 3;
750 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
751 description
=> "CPUs accessing this NUMA node.",
752 format_description
=> "id[-id];...",
756 description
=> "Amount of memory this NUMA node provides.",
761 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
762 description
=> "Host NUMA nodes to use.",
763 format_description
=> "id[-id];...",
768 enum
=> [qw(preferred bind interleave)],
769 description
=> "NUMA allocation policy.",
773 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
776 type
=> 'string', format
=> $numa_fmt,
777 description
=> "NUMA topology.",
779 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
781 for (my $i = 0; $i < $MAX_NUMA; $i++) {
782 $confdesc->{"numa$i"} = $numadesc;
785 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
786 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
787 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
788 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
790 my $net_fmt_bridge_descr = <<__EOD__;
791 Bridge to attach the network device to. The Proxmox VE standard bridge
794 If you do not specify a bridge, we create a kvm user (NATed) network
795 device, which provides DHCP and DNS services. The following addresses
802 The DHCP server assign addresses to the guest starting from 10.0.2.15.
806 macaddr
=> get_standard_option
('mac-addr', {
807 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
811 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'.",
812 enum
=> $nic_model_list,
815 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
818 description
=> $net_fmt_bridge_descr,
819 format_description
=> 'bridge',
824 minimum
=> 0, maximum
=> 16,
825 description
=> 'Number of packet queues to be used on the device.',
831 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
836 minimum
=> 1, maximum
=> 4094,
837 description
=> 'VLAN tag to apply to packets on this interface.',
842 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
843 description
=> 'VLAN trunks to pass through this interface.',
844 format_description
=> 'vlanid[;vlanid...]',
849 description
=> 'Whether this interface should be protected by the firewall.',
854 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
861 type
=> 'string', format
=> $net_fmt,
862 description
=> "Specify network devices.",
865 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
870 format
=> 'pve-ipv4-config',
871 format_description
=> 'IPv4Format/CIDR',
872 description
=> 'IPv4 address in CIDR format.',
879 format_description
=> 'GatewayIPv4',
880 description
=> 'Default gateway for IPv4 traffic.',
886 format
=> 'pve-ipv6-config',
887 format_description
=> 'IPv6Format/CIDR',
888 description
=> 'IPv6 address in CIDR format.',
895 format_description
=> 'GatewayIPv6',
896 description
=> 'Default gateway for IPv6 traffic.',
901 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
904 type
=> 'string', format
=> 'pve-qm-ipconfig',
905 description
=> <<'EODESCR',
906 cloud-init: Specify IP addresses and gateways for the corresponding interface.
908 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
910 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
911 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
913 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
916 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
918 for (my $i = 0; $i < $MAX_NETS; $i++) {
919 $confdesc->{"net$i"} = $netdesc;
920 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
923 foreach my $key (keys %$confdesc_cloudinit) {
924 $confdesc->{$key} = $confdesc_cloudinit->{$key};
927 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
928 sub verify_volume_id_or_qm_path
{
929 my ($volid, $noerr) = @_;
931 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
935 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
936 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
938 return undef if $noerr;
947 type
=> 'string', format
=> 'pve-qm-usb-device',
948 format_description
=> 'HOSTUSBDEVICE|spice',
949 description
=> <<EODESCR,
950 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
952 'bus-port(.port)*' (decimal numbers) or
953 'vendor_id:product_id' (hexadeciaml numbers) or
956 You can use the 'lsusb -t' command to list existing usb devices.
958 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
960 The value 'spice' can be used to add a usb redirection devices for spice.
966 description
=> "Specifies whether if given host option is a USB3 device or port.",
973 type
=> 'string', format
=> $usb_fmt,
974 description
=> "Configure an USB device (n is 0 to 4).",
976 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
978 my $PCIRE = qr/([a-f0-9]{4}:)?[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
983 pattern
=> qr/$PCIRE(;$PCIRE)*/,
984 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
985 description
=> <<EODESCR,
986 Host PCI device pass through. The PCI ID of a host's PCI device or a list
987 of PCI virtual functions of the host. HOSTPCIID syntax is:
989 'bus:dev.func' (hexadecimal numbers)
991 You can us the 'lspci' command to list existing PCI devices.
996 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1002 pattern
=> '[^,;]+',
1003 format_description
=> 'string',
1004 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1009 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1015 description
=> "Enable vfio-vga device support.",
1021 format_description
=> 'string',
1022 pattern
=> '[^/\.:]+',
1024 description
=> <<EODESCR
1025 The type of mediated device to use.
1026 An instance of this type will be created on startup of the VM and
1027 will be cleaned up when the VM stops.
1031 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1035 type
=> 'string', format
=> 'pve-qm-hostpci',
1036 description
=> "Map host PCI devices into guest.",
1037 verbose_description
=> <<EODESCR,
1038 Map host PCI devices into guest.
1040 NOTE: This option allows direct access to host hardware. So it is no longer
1041 possible to migrate such machines - use with special care.
1043 CAUTION: Experimental! User reported problems with this option.
1046 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1051 pattern
=> '(/dev/.+|socket)',
1052 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1053 verbose_description
=> <<EODESCR,
1054 Create a serial device inside the VM (n is 0 to 3), and pass through a
1055 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1056 host side (use 'qm terminal' to open a terminal connection).
1058 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1060 CAUTION: Experimental! User reported problems with this option.
1067 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1068 description
=> "Map host parallel devices (n is 0 to 2).",
1069 verbose_description
=> <<EODESCR,
1070 Map host parallel devices (n is 0 to 2).
1072 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1074 CAUTION: Experimental! User reported problems with this option.
1078 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1079 $confdesc->{"parallel$i"} = $paralleldesc;
1082 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1083 $confdesc->{"serial$i"} = $serialdesc;
1086 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1087 $confdesc->{"hostpci$i"} = $hostpcidesc;
1090 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1091 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1094 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1095 $confdesc->{"usb$i"} = $usbdesc;
1098 my $kvm_api_version = 0;
1101 return $kvm_api_version if $kvm_api_version;
1103 open my $fh, '<', '/dev/kvm'
1106 # 0xae00 => KVM_GET_API_VERSION
1107 $kvm_api_version = ioctl($fh, 0xae00, 0);
1109 return $kvm_api_version;
1112 my $kvm_user_version = {};
1115 sub kvm_user_version
{
1118 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1119 my $st = stat($binary);
1121 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1122 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1123 $cachedmtime == $st->mtime;
1125 $kvm_user_version->{$binary} = 'unknown';
1126 $kvm_mtime->{$binary} = $st->mtime;
1130 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1131 $kvm_user_version->{$binary} = $2;
1135 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1138 return $kvm_user_version->{$binary};
1142 sub kernel_has_vhost_net
{
1143 return -c
'/dev/vhost-net';
1148 return defined($confdesc->{$key});
1152 sub get_cdrom_path
{
1154 return $cdrom_path if $cdrom_path;
1156 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1157 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1158 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1162 my ($storecfg, $vmid, $cdrom) = @_;
1164 if ($cdrom eq 'cdrom') {
1165 return get_cdrom_path
();
1166 } elsif ($cdrom eq 'none') {
1168 } elsif ($cdrom =~ m
|^/|) {
1171 return PVE
::Storage
::path
($storecfg, $cdrom);
1175 # try to convert old style file names to volume IDs
1176 sub filename_to_volume_id
{
1177 my ($vmid, $file, $media) = @_;
1179 if (!($file eq 'none' || $file eq 'cdrom' ||
1180 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1182 return undef if $file =~ m
|/|;
1184 if ($media && $media eq 'cdrom') {
1185 $file = "local:iso/$file";
1187 $file = "local:$vmid/$file";
1194 sub verify_media_type
{
1195 my ($opt, $vtype, $media) = @_;
1200 if ($media eq 'disk') {
1202 } elsif ($media eq 'cdrom') {
1205 die "internal error";
1208 return if ($vtype eq $etype);
1210 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1213 sub cleanup_drive_path
{
1214 my ($opt, $storecfg, $drive) = @_;
1216 # try to convert filesystem paths to volume IDs
1218 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1219 ($drive->{file
} !~ m
|^/dev/.+|) &&
1220 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1221 ($drive->{file
} !~ m/^\d+$/)) {
1222 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1223 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1224 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1225 verify_media_type
($opt, $vtype, $drive->{media
});
1226 $drive->{file
} = $volid;
1229 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1232 sub parse_hotplug_features
{
1237 return $res if $data eq '0';
1239 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1241 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1242 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1245 die "invalid hotplug feature '$feature'\n";
1251 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1252 sub pve_verify_hotplug_features
{
1253 my ($value, $noerr) = @_;
1255 return $value if parse_hotplug_features
($value);
1257 return undef if $noerr;
1259 die "unable to parse hotplug option\n";
1263 my($fh, $noerr) = @_;
1266 my $SG_GET_VERSION_NUM = 0x2282;
1268 my $versionbuf = "\x00" x
8;
1269 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1271 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1274 my $version = unpack("I", $versionbuf);
1275 if ($version < 30000) {
1276 die "scsi generic interface too old\n" if !$noerr;
1280 my $buf = "\x00" x
36;
1281 my $sensebuf = "\x00" x
8;
1282 my $cmd = pack("C x3 C x1", 0x12, 36);
1284 # see /usr/include/scsi/sg.h
1285 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";
1287 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1288 length($sensebuf), 0, length($buf), $buf,
1289 $cmd, $sensebuf, 6000);
1291 $ret = ioctl($fh, $SG_IO, $packet);
1293 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1297 my @res = unpack($sg_io_hdr_t, $packet);
1298 if ($res[17] || $res[18]) {
1299 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1304 (my $byte0, my $byte1, $res->{vendor
},
1305 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1307 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1308 $res->{type
} = $byte0 & 31;
1316 my $fh = IO
::File-
>new("+<$path") || return undef;
1317 my $res = scsi_inquiry
($fh, 1);
1323 sub print_tabletdevice_full
{
1324 my ($conf, $arch) = @_;
1326 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1328 # we use uhci for old VMs because tablet driver was buggy in older qemu
1330 if (PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1336 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1339 sub print_keyboarddevice_full
{
1340 my ($conf, $arch, $machine) = @_;
1342 return undef if $arch ne 'aarch64';
1344 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1347 sub print_drivedevice_full
{
1348 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1353 if ($drive->{interface
} eq 'virtio') {
1354 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1355 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1356 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1357 } elsif ($drive->{interface
} eq 'scsi') {
1359 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1360 my $unit = $drive->{index} % $maxdev;
1361 my $devicetype = 'hd';
1363 if (drive_is_cdrom
($drive)) {
1366 if ($drive->{file
} =~ m
|^/|) {
1367 $path = $drive->{file
};
1368 if (my $info = path_is_scsi
($path)) {
1369 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1370 $devicetype = 'block';
1371 } elsif ($info->{type
} == 1) { # tape
1372 $devicetype = 'generic';
1376 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1379 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1380 my $version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, kvm_user_version
());
1381 if ($path =~ m/^iscsi\:\/\
// &&
1382 !min_version
($version, 4, 1)) {
1383 $devicetype = 'generic';
1387 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1388 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1390 $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}";
1393 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1394 $device .= ",rotation_rate=1";
1396 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1398 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1399 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1400 my $controller = int($drive->{index} / $maxdev);
1401 my $unit = $drive->{index} % $maxdev;
1402 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1404 $device = "ide-$devicetype";
1405 if ($drive->{interface
} eq 'ide') {
1406 $device .= ",bus=ide.$controller,unit=$unit";
1408 $device .= ",bus=ahci$controller.$unit";
1410 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1412 if ($devicetype eq 'hd') {
1413 if (my $model = $drive->{model
}) {
1414 $model = URI
::Escape
::uri_unescape
($model);
1415 $device .= ",model=$model";
1417 if ($drive->{ssd
}) {
1418 $device .= ",rotation_rate=1";
1421 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1422 } elsif ($drive->{interface
} eq 'usb') {
1424 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1426 die "unsupported interface type";
1429 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1431 if (my $serial = $drive->{serial
}) {
1432 $serial = URI
::Escape
::uri_unescape
($serial);
1433 $device .= ",serial=$serial";
1440 sub get_initiator_name
{
1443 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1444 while (defined(my $line = <$fh>)) {
1445 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1454 sub print_drive_commandline_full
{
1455 my ($storecfg, $vmid, $drive) = @_;
1458 my $volid = $drive->{file
};
1461 if (drive_is_cdrom
($drive)) {
1462 $path = get_iso_path
($storecfg, $vmid, $volid);
1464 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1466 $path = PVE
::Storage
::path
($storecfg, $volid);
1467 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1468 $format = qemu_img_format
($scfg, $volname);
1476 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1477 foreach my $o (@qemu_drive_options) {
1478 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1481 # snapshot only accepts on|off
1482 if (defined($drive->{snapshot
})) {
1483 my $v = $drive->{snapshot
} ?
'on' : 'off';
1484 $opts .= ",snapshot=$v";
1487 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1488 my ($dir, $qmpname) = @$type;
1489 if (my $v = $drive->{"mbps$dir"}) {
1490 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1492 if (my $v = $drive->{"mbps${dir}_max"}) {
1493 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1495 if (my $v = $drive->{"bps${dir}_max_length"}) {
1496 $opts .= ",throttling.bps$qmpname-max-length=$v";
1498 if (my $v = $drive->{"iops${dir}"}) {
1499 $opts .= ",throttling.iops$qmpname=$v";
1501 if (my $v = $drive->{"iops${dir}_max"}) {
1502 $opts .= ",throttling.iops$qmpname-max=$v";
1504 if (my $v = $drive->{"iops${dir}_max_length"}) {
1505 $opts .= ",throttling.iops$qmpname-max-length=$v";
1509 $opts .= ",format=$format" if $format && !$drive->{format
};
1511 my $cache_direct = 0;
1513 if (my $cache = $drive->{cache
}) {
1514 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1515 } elsif (!drive_is_cdrom
($drive)) {
1516 $opts .= ",cache=none";
1520 # aio native works only with O_DIRECT
1521 if (!$drive->{aio
}) {
1523 $opts .= ",aio=native";
1525 $opts .= ",aio=threads";
1529 if (!drive_is_cdrom
($drive)) {
1531 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1532 $detectzeroes = 'off';
1533 } elsif ($drive->{discard
}) {
1534 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1536 # This used to be our default with discard not being specified:
1537 $detectzeroes = 'on';
1539 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1542 my $pathinfo = $path ?
"file=$path," : '';
1544 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1547 sub print_netdevice_full
{
1548 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1550 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1552 my $device = $net->{model
};
1553 if ($net->{model
} eq 'virtio') {
1554 $device = 'virtio-net-pci';
1557 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1558 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1559 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1560 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1561 my $vectors = $net->{queues
} * 2 + 2;
1562 $tmpstr .= ",vectors=$vectors,mq=on";
1564 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1566 if ($use_old_bios_files) {
1568 if ($device eq 'virtio-net-pci') {
1569 $romfile = 'pxe-virtio.rom';
1570 } elsif ($device eq 'e1000') {
1571 $romfile = 'pxe-e1000.rom';
1572 } elsif ($device eq 'ne2k') {
1573 $romfile = 'pxe-ne2k_pci.rom';
1574 } elsif ($device eq 'pcnet') {
1575 $romfile = 'pxe-pcnet.rom';
1576 } elsif ($device eq 'rtl8139') {
1577 $romfile = 'pxe-rtl8139.rom';
1579 $tmpstr .= ",romfile=$romfile" if $romfile;
1585 sub print_netdev_full
{
1586 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1589 if ($netid =~ m/^net(\d+)$/) {
1593 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1595 my $ifname = "tap${vmid}i$i";
1597 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1598 die "interface name '$ifname' is too long (max 15 character)\n"
1599 if length($ifname) >= 16;
1601 my $vhostparam = '';
1602 if (is_native
($arch)) {
1603 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1606 my $vmname = $conf->{name
} || "vm$vmid";
1609 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1611 if ($net->{bridge
}) {
1612 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1614 $netdev = "type=user,id=$netid,hostname=$vmname";
1617 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1623 'cirrus' => 'cirrus-vga',
1625 'vmware' => 'vmware-svga',
1626 'virtio' => 'virtio-vga',
1629 sub print_vga_device
{
1630 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1632 my $type = $vga_map->{$vga->{type
}};
1633 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1634 $type = 'virtio-gpu';
1636 my $vgamem_mb = $vga->{memory
};
1638 my $max_outputs = '';
1640 $type = $id ?
'qxl' : 'qxl-vga';
1642 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1643 # set max outputs so linux can have up to 4 qxl displays with one device
1644 if (min_version
($machine_version, 4, 1)) {
1645 $max_outputs = ",max_outputs=4";
1650 die "no devicetype for $vga->{type}\n" if !$type;
1654 if ($vga->{type
} eq 'virtio') {
1655 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1656 $memory = ",max_hostmem=$bytes";
1658 # from https://www.spice-space.org/multiple-monitors.html
1659 $memory = ",vgamem_mb=$vga->{memory}";
1660 my $ram = $vgamem_mb * 4;
1661 my $vram = $vgamem_mb * 2;
1662 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1664 $memory = ",vgamem_mb=$vga->{memory}";
1666 } elsif ($qxlnum && $id) {
1667 $memory = ",ram_size=67108864,vram_size=33554432";
1670 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1671 my $vgaid = "vga" . ($id // '');
1674 if ($q35 && $vgaid eq 'vga') {
1675 # the first display uses pcie.0 bus on q35 machines
1676 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1678 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1681 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}";
1684 sub parse_number_sets
{
1687 foreach my $part (split(/;/, $set)) {
1688 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1689 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1690 push @$res, [ $1, $2 ];
1692 die "invalid range: $part\n";
1701 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1702 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1703 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1710 return undef if !$value;
1712 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1714 my @idlist = split(/;/, $res->{host
});
1715 delete $res->{host
};
1716 foreach my $id (@idlist) {
1717 my $devs = PVE
::SysFSTools
::lspci
($id);
1718 die "no PCI device found for '$id'\n" if !scalar(@$devs);
1719 push @{$res->{pciid
}}, @$devs;
1724 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1728 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1733 if (!defined($res->{macaddr
})) {
1734 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1735 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1740 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1741 sub parse_ipconfig
{
1744 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1750 if ($res->{gw
} && !$res->{ip
}) {
1751 warn 'gateway specified without specifying an IP address';
1754 if ($res->{gw6
} && !$res->{ip6
}) {
1755 warn 'IPv6 gateway specified without specifying an IPv6 address';
1758 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1759 warn 'gateway specified together with DHCP';
1762 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1764 warn "IPv6 gateway specified together with $res->{ip6} address";
1768 if (!$res->{ip
} && !$res->{ip6
}) {
1769 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1778 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1781 sub add_random_macs
{
1782 my ($settings) = @_;
1784 foreach my $opt (keys %$settings) {
1785 next if $opt !~ m/^net(\d+)$/;
1786 my $net = parse_net
($settings->{$opt});
1788 $settings->{$opt} = print_net
($net);
1792 sub vm_is_volid_owner
{
1793 my ($storecfg, $vmid, $volid) = @_;
1795 if ($volid !~ m
|^/|) {
1797 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1798 if ($owner && ($owner == $vmid)) {
1806 sub vmconfig_register_unused_drive
{
1807 my ($storecfg, $vmid, $conf, $drive) = @_;
1809 if (drive_is_cloudinit
($drive)) {
1810 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
1812 } elsif (!drive_is_cdrom
($drive)) {
1813 my $volid = $drive->{file
};
1814 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1815 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1820 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
1824 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1825 format_description
=> 'UUID',
1826 description
=> "Set SMBIOS1 UUID.",
1831 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1832 format_description
=> 'Base64 encoded string',
1833 description
=> "Set SMBIOS1 version.",
1838 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1839 format_description
=> 'Base64 encoded string',
1840 description
=> "Set SMBIOS1 serial number.",
1845 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1846 format_description
=> 'Base64 encoded string',
1847 description
=> "Set SMBIOS1 manufacturer.",
1852 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1853 format_description
=> 'Base64 encoded string',
1854 description
=> "Set SMBIOS1 product ID.",
1859 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1860 format_description
=> 'Base64 encoded string',
1861 description
=> "Set SMBIOS1 SKU string.",
1866 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1867 format_description
=> 'Base64 encoded string',
1868 description
=> "Set SMBIOS1 family string.",
1873 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
1881 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
1888 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
1891 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
1893 sub parse_watchdog
{
1896 return undef if !$value;
1898 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
1903 sub parse_guest_agent
{
1906 return {} if !defined($value->{agent
});
1908 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
1911 # if the agent is disabled ignore the other potentially set properties
1912 return {} if !$res->{enabled
};
1919 return {} if !$value;
1920 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
1928 return undef if !$value;
1930 my $res = eval { PVE
::JSONSchema
::parse_property_string
($rng_fmt, $value) };
1935 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1936 sub verify_usb_device
{
1937 my ($value, $noerr) = @_;
1939 return $value if parse_usb_device
($value);
1941 return undef if $noerr;
1943 die "unable to parse usb device\n";
1946 # add JSON properties for create and set function
1947 sub json_config_properties
{
1950 foreach my $opt (keys %$confdesc) {
1951 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
1952 $prop->{$opt} = $confdesc->{$opt};
1958 # return copy of $confdesc_cloudinit to generate documentation
1959 sub cloudinit_config_properties
{
1961 return dclone
($confdesc_cloudinit);
1965 my ($key, $value) = @_;
1967 die "unknown setting '$key'\n" if !$confdesc->{$key};
1969 my $type = $confdesc->{$key}->{type
};
1971 if (!defined($value)) {
1972 die "got undefined value\n";
1975 if ($value =~ m/[\n\r]/) {
1976 die "property contains a line feed\n";
1979 if ($type eq 'boolean') {
1980 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
1981 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
1982 die "type check ('boolean') failed - got '$value'\n";
1983 } elsif ($type eq 'integer') {
1984 return int($1) if $value =~ m/^(\d+)$/;
1985 die "type check ('integer') failed - got '$value'\n";
1986 } elsif ($type eq 'number') {
1987 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
1988 die "type check ('number') failed - got '$value'\n";
1989 } elsif ($type eq 'string') {
1990 if (my $fmt = $confdesc->{$key}->{format
}) {
1991 PVE
::JSONSchema
::check_format
($fmt, $value);
1994 $value =~ s/^\"(.*)\"$/$1/;
1997 die "internal error"
2002 my ($storecfg, $vmid, $skiplock, $replacement_conf) = @_;
2004 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2006 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2008 if ($conf->{template
}) {
2009 # check if any base image is still used by a linked clone
2010 foreach_drive
($conf, sub {
2011 my ($ds, $drive) = @_;
2012 return if drive_is_cdrom
($drive);
2014 my $volid = $drive->{file
};
2015 return if !$volid || $volid =~ m
|^/|;
2017 die "base volume '$volid' is still in use by linked cloned\n"
2018 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2023 # only remove disks owned by this VM
2024 foreach_drive
($conf, sub {
2025 my ($ds, $drive) = @_;
2026 return if drive_is_cdrom
($drive, 1);
2028 my $volid = $drive->{file
};
2029 return if !$volid || $volid =~ m
|^/|;
2031 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2032 return if !$path || !$owner || ($owner != $vmid);
2034 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2035 warn "Could not remove disk '$volid', check manually: $@" if $@;
2038 # also remove unused disk
2039 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2040 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2041 my ($volid, $sid, $volname, $d) = @_;
2042 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2046 if (defined $replacement_conf) {
2047 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2049 PVE
::QemuConfig-
>destroy_config($vmid);
2053 sub parse_vm_config
{
2054 my ($filename, $raw) = @_;
2056 return undef if !defined($raw);
2059 digest
=> Digest
::SHA
::sha1_hex
($raw),
2064 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2065 || die "got strange filename '$filename'";
2073 my @lines = split(/\n/, $raw);
2074 foreach my $line (@lines) {
2075 next if $line =~ m/^\s*$/;
2077 if ($line =~ m/^\[PENDING\]\s*$/i) {
2078 $section = 'pending';
2079 if (defined($descr)) {
2081 $conf->{description
} = $descr;
2084 $conf = $res->{$section} = {};
2087 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2089 if (defined($descr)) {
2091 $conf->{description
} = $descr;
2094 $conf = $res->{snapshots
}->{$section} = {};
2098 if ($line =~ m/^\#(.*)\s*$/) {
2099 $descr = '' if !defined($descr);
2100 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2104 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2105 $descr = '' if !defined($descr);
2106 $descr .= PVE
::Tools
::decode_text
($2);
2107 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2108 $conf->{snapstate
} = $1;
2109 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2112 $conf->{$key} = $value;
2113 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2115 if ($section eq 'pending') {
2116 $conf->{delete} = $value; # we parse this later
2118 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2120 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2123 eval { $value = check_type
($key, $value); };
2125 warn "vm $vmid - unable to parse value of '$key' - $@";
2127 $key = 'ide2' if $key eq 'cdrom';
2128 my $fmt = $confdesc->{$key}->{format
};
2129 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2130 my $v = parse_drive
($key, $value);
2131 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2132 $v->{file
} = $volid;
2133 $value = print_drive
($v);
2135 warn "vm $vmid - unable to parse value of '$key'\n";
2140 $conf->{$key} = $value;
2145 if (defined($descr)) {
2147 $conf->{description
} = $descr;
2149 delete $res->{snapstate
}; # just to be sure
2154 sub write_vm_config
{
2155 my ($filename, $conf) = @_;
2157 delete $conf->{snapstate
}; # just to be sure
2159 if ($conf->{cdrom
}) {
2160 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2161 $conf->{ide2
} = $conf->{cdrom
};
2162 delete $conf->{cdrom
};
2165 # we do not use 'smp' any longer
2166 if ($conf->{sockets
}) {
2167 delete $conf->{smp
};
2168 } elsif ($conf->{smp
}) {
2169 $conf->{sockets
} = $conf->{smp
};
2170 delete $conf->{cores
};
2171 delete $conf->{smp
};
2174 my $used_volids = {};
2176 my $cleanup_config = sub {
2177 my ($cref, $pending, $snapname) = @_;
2179 foreach my $key (keys %$cref) {
2180 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2181 $key eq 'snapstate' || $key eq 'pending';
2182 my $value = $cref->{$key};
2183 if ($key eq 'delete') {
2184 die "propertry 'delete' is only allowed in [PENDING]\n"
2186 # fixme: check syntax?
2189 eval { $value = check_type
($key, $value); };
2190 die "unable to parse value of '$key' - $@" if $@;
2192 $cref->{$key} = $value;
2194 if (!$snapname && is_valid_drivename
($key)) {
2195 my $drive = parse_drive
($key, $value);
2196 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2201 &$cleanup_config($conf);
2203 &$cleanup_config($conf->{pending
}, 1);
2205 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2206 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2207 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2210 # remove 'unusedX' settings if we re-add a volume
2211 foreach my $key (keys %$conf) {
2212 my $value = $conf->{$key};
2213 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2214 delete $conf->{$key};
2218 my $generate_raw_config = sub {
2219 my ($conf, $pending) = @_;
2223 # add description as comment to top of file
2224 if (defined(my $descr = $conf->{description
})) {
2226 foreach my $cl (split(/\n/, $descr)) {
2227 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2230 $raw .= "#\n" if $pending;
2234 foreach my $key (sort keys %$conf) {
2235 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2236 $raw .= "$key: $conf->{$key}\n";
2241 my $raw = &$generate_raw_config($conf);
2243 if (scalar(keys %{$conf->{pending
}})){
2244 $raw .= "\n[PENDING]\n";
2245 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2248 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2249 $raw .= "\n[$snapname]\n";
2250 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2260 # we use static defaults from our JSON schema configuration
2261 foreach my $key (keys %$confdesc) {
2262 if (defined(my $default = $confdesc->{$key}->{default})) {
2263 $res->{$key} = $default;
2271 my $vmlist = PVE
::Cluster
::get_vmlist
();
2273 return $res if !$vmlist || !$vmlist->{ids
};
2274 my $ids = $vmlist->{ids
};
2275 my $nodename = nodename
();
2277 foreach my $vmid (keys %$ids) {
2278 my $d = $ids->{$vmid};
2279 next if !$d->{node
} || $d->{node
} ne $nodename;
2280 next if !$d->{type
} || $d->{type
} ne 'qemu';
2281 $res->{$vmid}->{exists} = 1;
2286 # test if VM uses local resources (to prevent migration)
2287 sub check_local_resources
{
2288 my ($conf, $noerr) = @_;
2292 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2293 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2295 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2297 foreach my $k (keys %$conf) {
2298 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2299 # sockets are safe: they will recreated be on the target side post-migrate
2300 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2301 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2304 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2309 # check if used storages are available on all nodes (use by migrate)
2310 sub check_storage_availability
{
2311 my ($storecfg, $conf, $node) = @_;
2313 foreach_drive
($conf, sub {
2314 my ($ds, $drive) = @_;
2316 my $volid = $drive->{file
};
2319 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2322 # check if storage is available on both nodes
2323 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2324 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2328 # list nodes where all VM images are available (used by has_feature API)
2330 my ($conf, $storecfg) = @_;
2332 my $nodelist = PVE
::Cluster
::get_nodelist
();
2333 my $nodehash = { map { $_ => 1 } @$nodelist };
2334 my $nodename = nodename
();
2336 foreach_drive
($conf, sub {
2337 my ($ds, $drive) = @_;
2339 my $volid = $drive->{file
};
2342 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2344 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2345 if ($scfg->{disable
}) {
2347 } elsif (my $avail = $scfg->{nodes
}) {
2348 foreach my $node (keys %$nodehash) {
2349 delete $nodehash->{$node} if !$avail->{$node};
2351 } elsif (!$scfg->{shared
}) {
2352 foreach my $node (keys %$nodehash) {
2353 delete $nodehash->{$node} if $node ne $nodename
2362 sub check_local_storage_availability
{
2363 my ($conf, $storecfg) = @_;
2365 my $nodelist = PVE
::Cluster
::get_nodelist
();
2366 my $nodehash = { map { $_ => {} } @$nodelist };
2368 foreach_drive
($conf, sub {
2369 my ($ds, $drive) = @_;
2371 my $volid = $drive->{file
};
2374 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2376 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2378 if ($scfg->{disable
}) {
2379 foreach my $node (keys %$nodehash) {
2380 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2382 } elsif (my $avail = $scfg->{nodes
}) {
2383 foreach my $node (keys %$nodehash) {
2384 if (!$avail->{$node}) {
2385 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2392 foreach my $node (values %$nodehash) {
2393 if (my $unavail = $node->{unavailable_storages
}) {
2394 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2401 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2403 my ($vmid, $nocheck, $node) = @_;
2405 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2406 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2411 my $vzlist = config_list
();
2413 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2415 while (defined(my $de = $fd->read)) {
2416 next if $de !~ m/^(\d+)\.pid$/;
2418 next if !defined($vzlist->{$vmid});
2419 if (my $pid = check_running
($vmid)) {
2420 $vzlist->{$vmid}->{pid
} = $pid;
2427 our $vmstatus_return_properties = {
2428 vmid
=> get_standard_option
('pve-vmid'),
2430 description
=> "Qemu process status.",
2432 enum
=> ['stopped', 'running'],
2435 description
=> "Maximum memory in bytes.",
2438 renderer
=> 'bytes',
2441 description
=> "Root disk size in bytes.",
2444 renderer
=> 'bytes',
2447 description
=> "VM name.",
2452 description
=> "Qemu QMP agent status.",
2457 description
=> "PID of running qemu process.",
2462 description
=> "Uptime.",
2465 renderer
=> 'duration',
2468 description
=> "Maximum usable CPUs.",
2473 description
=> "The current config lock, if any.",
2478 description
=> "The current configured tags, if any",
2484 my $last_proc_pid_stat;
2486 # get VM status information
2487 # This must be fast and should not block ($full == false)
2488 # We only query KVM using QMP if $full == true (this can be slow)
2490 my ($opt_vmid, $full) = @_;
2494 my $storecfg = PVE
::Storage
::config
();
2496 my $list = vzlist
();
2497 my $defaults = load_defaults
();
2499 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2501 my $cpucount = $cpuinfo->{cpus
} || 1;
2503 foreach my $vmid (keys %$list) {
2504 next if $opt_vmid && ($vmid ne $opt_vmid);
2506 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2508 my $d = { vmid
=> $vmid };
2509 $d->{pid
} = $list->{$vmid}->{pid
};
2511 # fixme: better status?
2512 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2514 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2515 if (defined($size)) {
2516 $d->{disk
} = 0; # no info available
2517 $d->{maxdisk
} = $size;
2523 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2524 * ($conf->{cores
} || $defaults->{cores
});
2525 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2526 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2528 $d->{name
} = $conf->{name
} || "VM $vmid";
2529 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2530 : $defaults->{memory
}*(1024*1024);
2532 if ($conf->{balloon
}) {
2533 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2534 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2535 : $defaults->{shares
};
2546 $d->{diskwrite
} = 0;
2548 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2550 $d->{serial
} = 1 if conf_has_serial
($conf);
2551 $d->{lock} = $conf->{lock} if $conf->{lock};
2552 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2557 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2558 foreach my $dev (keys %$netdev) {
2559 next if $dev !~ m/^tap([1-9]\d*)i/;
2561 my $d = $res->{$vmid};
2564 $d->{netout
} += $netdev->{$dev}->{receive
};
2565 $d->{netin
} += $netdev->{$dev}->{transmit
};
2568 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2569 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2574 my $ctime = gettimeofday
;
2576 foreach my $vmid (keys %$list) {
2578 my $d = $res->{$vmid};
2579 my $pid = $d->{pid
};
2582 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2583 next if !$pstat; # not running
2585 my $used = $pstat->{utime} + $pstat->{stime
};
2587 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2589 if ($pstat->{vsize
}) {
2590 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2593 my $old = $last_proc_pid_stat->{$pid};
2595 $last_proc_pid_stat->{$pid} = {
2603 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2605 if ($dtime > 1000) {
2606 my $dutime = $used - $old->{used
};
2608 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2609 $last_proc_pid_stat->{$pid} = {
2615 $d->{cpu
} = $old->{cpu
};
2619 return $res if !$full;
2621 my $qmpclient = PVE
::QMPClient-
>new();
2623 my $ballooncb = sub {
2624 my ($vmid, $resp) = @_;
2626 my $info = $resp->{'return'};
2627 return if !$info->{max_mem
};
2629 my $d = $res->{$vmid};
2631 # use memory assigned to VM
2632 $d->{maxmem
} = $info->{max_mem
};
2633 $d->{balloon
} = $info->{actual
};
2635 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2636 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2637 $d->{freemem
} = $info->{free_mem
};
2640 $d->{ballooninfo
} = $info;
2643 my $blockstatscb = sub {
2644 my ($vmid, $resp) = @_;
2645 my $data = $resp->{'return'} || [];
2646 my $totalrdbytes = 0;
2647 my $totalwrbytes = 0;
2649 for my $blockstat (@$data) {
2650 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2651 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2653 $blockstat->{device
} =~ s/drive-//;
2654 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2656 $res->{$vmid}->{diskread
} = $totalrdbytes;
2657 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2660 my $statuscb = sub {
2661 my ($vmid, $resp) = @_;
2663 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2664 # this fails if ballon driver is not loaded, so this must be
2665 # the last commnand (following command are aborted if this fails).
2666 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2668 my $status = 'unknown';
2669 if (!defined($status = $resp->{'return'}->{status
})) {
2670 warn "unable to get VM status\n";
2674 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2677 foreach my $vmid (keys %$list) {
2678 next if $opt_vmid && ($vmid ne $opt_vmid);
2679 next if !$res->{$vmid}->{pid
}; # not running
2680 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2683 $qmpclient->queue_execute(undef, 2);
2685 foreach my $vmid (keys %$list) {
2686 next if $opt_vmid && ($vmid ne $opt_vmid);
2687 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2693 sub conf_has_serial
{
2696 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2697 if ($conf->{"serial$i"}) {
2705 sub conf_has_audio
{
2706 my ($conf, $id) = @_;
2709 my $audio = $conf->{"audio$id"};
2710 return undef if !defined($audio);
2712 my $audioproperties = PVE
::JSONSchema
::parse_property_string
($audio_fmt, $audio);
2713 my $audiodriver = $audioproperties->{driver
} // 'spice';
2716 dev
=> $audioproperties->{device
},
2717 dev_id
=> "audiodev$id",
2718 backend
=> $audiodriver,
2719 backend_id
=> "$audiodriver-backend${id}",
2723 sub vga_conf_has_spice
{
2726 my $vgaconf = parse_vga
($vga);
2727 my $vgatype = $vgaconf->{type
};
2728 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
2735 return get_host_arch
() eq $arch;
2740 return $conf->{arch
} // get_host_arch
();
2743 my $default_machines = {
2748 sub get_vm_machine
{
2749 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
2751 my $machine = $forcemachine || $conf->{machine
};
2753 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
2755 $machine ||= $default_machines->{$arch};
2756 if ($add_pve_version) {
2757 $kvmversion //= kvm_user_version
();
2758 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
2759 $machine .= "+pve$pvever";
2763 if ($add_pve_version && $machine !~ m/\+pve\d+$/) {
2764 # for version-pinned machines that do not include a pve-version (e.g.
2765 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
2766 $machine .= '+pve0';
2772 sub get_ovmf_files
($) {
2775 my $ovmf = $OVMF->{$arch}
2776 or die "no OVMF images known for architecture '$arch'\n";
2782 aarch64
=> '/usr/bin/qemu-system-aarch64',
2783 x86_64
=> '/usr/bin/qemu-system-x86_64',
2785 sub get_command_for_arch
($) {
2787 return '/usr/bin/kvm' if is_native
($arch);
2789 my $cmd = $Arch2Qemu->{$arch}
2790 or die "don't know how to emulate architecture '$arch'\n";
2794 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
2795 # to use in a QEMU command line (-cpu element), first array_intersect the result
2796 # of query_supported_ with query_understood_. This is necessary because:
2798 # a) query_understood_ returns flags the host cannot use and
2799 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
2800 # flags, but CPU settings - with most of them being flags. Those settings
2801 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
2803 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
2804 # expensive. If you need the value returned from this, you can get it much
2805 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
2806 # $accel being 'kvm' or 'tcg'.
2808 # pvestatd calls this function on startup and whenever the QEMU/KVM version
2809 # changes, automatically populating pmxcfs.
2811 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
2812 # since kvm and tcg machines support different flags
2814 sub query_supported_cpu_flags
{
2817 $arch //= get_host_arch
();
2818 my $default_machine = $default_machines->{$arch};
2822 # FIXME: Once this is merged, the code below should work for ARM as well:
2823 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
2824 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
2827 my $kvm_supported = defined(kvm_version
());
2828 my $qemu_cmd = get_command_for_arch
($arch);
2830 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
2832 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
2833 my $query_supported_run_qemu = sub {
2839 '-machine', $default_machine,
2841 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server,nowait",
2842 '-mon', 'chardev=qmp,mode=control',
2843 '-pidfile', $pidfile,
2848 push @$cmd, '-accel', 'tcg';
2851 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
2852 die "QEMU flag querying VM exited with code " . $rc if $rc;
2855 my $cmd_result = mon_cmd
(
2857 'query-cpu-model-expansion',
2859 model
=> { name
=> 'host' }
2862 my $props = $cmd_result->{model
}->{props
};
2863 foreach my $prop (keys %$props) {
2864 next if $props->{$prop} ne '1';
2865 # QEMU returns some flags multiple times, with '_', '.' or '-'
2866 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
2867 # We only keep those with underscores, to match /proc/cpuinfo
2868 $prop =~ s/\.|-/_/g;
2869 $flags->{$prop} = 1;
2874 # force stop with 10 sec timeout and 'nocheck'
2875 # always stop, even if QMP failed
2876 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
2880 return [ sort keys %$flags ];
2883 # We need to query QEMU twice, since KVM and TCG have different supported flags
2884 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
2885 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
2886 warn "warning: failed querying supported tcg flags: $@\n" if $@;
2888 if ($kvm_supported) {
2889 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
2890 warn "warning: failed querying supported kvm flags: $@\n" if $@;
2897 # Understood CPU flags are written to a file at 'pve-qemu' compile time
2898 my $understood_cpu_flag_dir = "/usr/share/kvm";
2899 sub query_understood_cpu_flags
{
2900 my $arch = get_host_arch
();
2901 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
2903 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
2906 my $raw = file_get_contents
($filepath);
2907 $raw =~ s/^\s+|\s+$//g;
2908 my @flags = split(/\s+/, $raw);
2913 sub config_to_command
{
2914 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2917 my $globalFlags = [];
2918 my $machineFlags = [];
2923 my $ostype = $conf->{ostype
};
2924 my $winversion = windows_version
($ostype);
2925 my $kvm = $conf->{kvm
};
2926 my $nodename = nodename
();
2928 my $arch = get_vm_arch
($conf);
2929 my $kvm_binary = get_command_for_arch
($arch);
2930 my $kvmver = kvm_user_version
($kvm_binary);
2932 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
2933 $kvmver //= "undefined";
2934 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
2937 my $add_pve_version = min_version
($kvmver, 4, 1);
2939 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
2940 my $machine_version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, $kvmver);
2941 $kvm //= 1 if is_native
($arch);
2943 $machine_version =~ m/(\d+)\.(\d+)/;
2944 my ($machine_major, $machine_minor) = ($1, $2);
2945 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type', please upgrade node '$nodename'\n"
2946 if !PVE
::QemuServer
::min_version
($kvmver, $machine_major, $machine_minor);
2948 if (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
2949 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
2950 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is pve$max_pve_version)"
2951 . " is too old to run machine type '$machine_type', please upgrade node '$nodename'\n";
2954 # if a specific +pve version is required for a feature, use $version_guard
2955 # instead of min_version to allow machines to be run with the minimum
2957 my $required_pve_version = 0;
2958 my $version_guard = sub {
2959 my ($major, $minor, $pve) = @_;
2960 return 0 if !min_version
($machine_version, $major, $minor, $pve);
2961 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
2962 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
2963 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
2968 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
2969 if !defined kvm_version
();
2972 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
2973 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2974 my $use_old_bios_files = undef;
2975 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2977 my $cpuunits = defined($conf->{cpuunits
}) ?
2978 $conf->{cpuunits
} : $defaults->{cpuunits
};
2980 push @$cmd, $kvm_binary;
2982 push @$cmd, '-id', $vmid;
2984 my $vmname = $conf->{name
} || "vm$vmid";
2986 push @$cmd, '-name', $vmname;
2990 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
2991 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
2992 push @$cmd, '-mon', "chardev=qmp,mode=control";
2994 if (min_version
($machine_version, 2, 12)) {
2995 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
2996 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
2999 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3001 push @$cmd, '-daemonize';
3003 if ($conf->{smbios1
}) {
3004 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3005 if ($smbios_conf->{base64
}) {
3006 # Do not pass base64 flag to qemu
3007 delete $smbios_conf->{base64
};
3008 my $smbios_string = "";
3009 foreach my $key (keys %$smbios_conf) {
3011 if ($key eq "uuid") {
3012 $value = $smbios_conf->{uuid
}
3014 $value = decode_base64
($smbios_conf->{$key});
3016 # qemu accepts any binary data, only commas need escaping by double comma
3018 $smbios_string .= "," . $key . "=" . $value if $value;
3020 push @$cmd, '-smbios', "type=1" . $smbios_string;
3022 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3026 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3027 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3028 die "uefi base image not found\n" if ! -f
$ovmf_code;
3032 if (my $efidisk = $conf->{efidisk0
}) {
3033 my $d = parse_drive
('efidisk0', $efidisk);
3034 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3035 $format = $d->{format
};
3037 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3038 if (!defined($format)) {
3039 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3040 $format = qemu_img_format
($scfg, $volname);
3044 die "efidisk format must be specified\n"
3045 if !defined($format);
3048 warn "no efidisk configured! Using temporary efivars disk.\n";
3049 $path = "/tmp/$vmid-ovmf.fd";
3050 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3056 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3057 $size_str = ",size=" . (-s
$ovmf_vars);
3060 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3061 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0$size_str,file=$path";
3066 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3067 if (min_version
($machine_version, 4, 0)) {
3068 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3070 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3074 if ($conf->{vmgenid
}) {
3075 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3078 # add usb controllers
3079 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3080 push @$devices, @usbcontrollers if @usbcontrollers;
3081 my $vga = parse_vga
($conf->{vga
});
3083 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3084 $vga->{type
} = 'qxl' if $qxlnum;
3086 if (!$vga->{type
}) {
3087 if ($arch eq 'aarch64') {
3088 $vga->{type
} = 'virtio';
3089 } elsif (min_version
($machine_version, 2, 9)) {
3090 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3092 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3096 # enable absolute mouse coordinates (needed by vnc)
3098 if (defined($conf->{tablet
})) {
3099 $tablet = $conf->{tablet
};
3101 $tablet = $defaults->{tablet
};
3102 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3103 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3107 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3108 my $kbd = print_keyboarddevice_full
($conf, $arch);
3109 push @$devices, '-device', $kbd if defined($kbd);
3113 my $gpu_passthrough;
3116 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3117 my $id = "hostpci$i";
3118 my $d = parse_hostpci
($conf->{$id});
3121 if (my $pcie = $d->{pcie
}) {
3122 die "q35 machine model is not enabled" if !$q35;
3123 # win7 wants to have the pcie devices directly on the pcie bus
3124 # instead of in the root port
3125 if ($winversion == 7) {
3126 $pciaddr = print_pcie_addr
("${id}bus0");
3128 # add more root ports if needed, 4 are present by default
3129 # by pve-q35 cfgs, rest added here on demand.
3131 push @$devices, '-device', print_pcie_root_port
($i);
3133 $pciaddr = print_pcie_addr
($id);
3136 $pciaddr = print_pci_addr
($id, $bridges, $arch, $machine_type);
3140 if ($d->{'x-vga'}) {
3141 $xvga = ',x-vga=on' if !($conf->{bios
} && $conf->{bios
} eq 'ovmf');
3143 $vga->{type
} = 'none' if !defined($conf->{vga
});
3144 $gpu_passthrough = 1;
3147 my $pcidevices = $d->{pciid
};
3148 my $multifunction = 1 if @$pcidevices > 1;
3151 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3152 my $pci_id = $pcidevices->[0]->{id
};
3153 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3154 $sysfspath = "/sys/bus/pci/devices/$pci_id/$uuid";
3155 } elsif ($d->{mdev
}) {
3156 warn "ignoring mediated device '$id' with multifunction device\n";
3160 foreach my $pcidevice (@$pcidevices) {
3161 my $devicestr = "vfio-pci";
3164 $devicestr .= ",sysfsdev=$sysfspath";
3166 $devicestr .= ",host=$pcidevice->{id}";
3169 my $mf_addr = $multifunction ?
".$j" : '';
3170 $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
3173 $devicestr .= ',rombar=0' if defined($d->{rombar
}) && !$d->{rombar
};
3174 $devicestr .= "$xvga";
3175 $devicestr .= ",multifunction=on" if $multifunction;
3176 $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile
};
3179 push @$devices, '-device', $devicestr;
3185 my $usb_dev_features = {};
3186 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3188 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features);
3189 push @$devices, @usbdevices if @usbdevices;
3191 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3192 if (my $path = $conf->{"serial$i"}) {
3193 if ($path eq 'socket') {
3194 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3195 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3196 # On aarch64, serial0 is the UART device. Qemu only allows
3197 # connecting UART devices via the '-serial' command line, as
3198 # the device has a fixed slot on the hardware...
3199 if ($arch eq 'aarch64' && $i == 0) {
3200 push @$devices, '-serial', "chardev:serial$i";
3202 push @$devices, '-device', "isa-serial,chardev=serial$i";
3205 die "no such serial device\n" if ! -c
$path;
3206 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3207 push @$devices, '-device', "isa-serial,chardev=serial$i";
3213 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3214 if (my $path = $conf->{"parallel$i"}) {
3215 die "no such parallel device\n" if ! -c
$path;
3216 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3217 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3218 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3222 if (my $audio = conf_has_audio
($conf)) {
3224 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3226 my $id = $audio->{dev_id
};
3227 if ($audio->{dev
} eq 'AC97') {
3228 push @$devices, '-device', "AC97,id=${id}${audiopciaddr}";
3229 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
3230 push @$devices, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3231 push @$devices, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0";
3232 push @$devices, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1";
3234 die "unkown audio device '$audio->{dev}', implement me!";
3237 push @$devices, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
3241 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3242 $sockets = $conf->{sockets
} if $conf->{sockets
};
3244 my $cores = $conf->{cores
} || 1;
3246 my $maxcpus = $sockets * $cores;
3248 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3250 my $allowed_vcpus = $cpuinfo->{cpus
};
3252 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3253 if ($allowed_vcpus < $maxcpus);
3255 if($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3257 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3258 for (my $i = 2; $i <= $vcpus; $i++) {
3259 my $cpustr = print_cpu_device
($conf,$i);
3260 push @$cmd, '-device', $cpustr;
3265 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3267 push @$cmd, '-nodefaults';
3269 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3271 my $bootindex_hash = {};
3273 foreach my $o (split(//, $bootorder)) {
3274 $bootindex_hash->{$o} = $i*100;
3278 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3280 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3282 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3284 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3285 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3286 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3287 push @$cmd, '-vnc', "unix:$socket,password";
3289 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3290 push @$cmd, '-nographic';
3294 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3296 my $useLocaltime = $conf->{localtime};
3298 if ($winversion >= 5) { # windows
3299 $useLocaltime = 1 if !defined($conf->{localtime});
3301 # use time drift fix when acpi is enabled
3302 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3303 $tdf = 1 if !defined($conf->{tdf
});
3307 if ($winversion >= 6) {
3308 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3309 push @$cmd, '-no-hpet';
3312 push @$rtcFlags, 'driftfix=slew' if $tdf;
3314 if (($conf->{startdate
}) && ($conf->{startdate
} ne 'now')) {
3315 push @$rtcFlags, "base=$conf->{startdate}";
3316 } elsif ($useLocaltime) {
3317 push @$rtcFlags, 'base=localtime';
3320 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3322 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3324 push @$cmd, '-S' if $conf->{freeze
};
3326 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3328 my $guest_agent = parse_guest_agent
($conf);
3330 if ($guest_agent->{enabled
}) {
3331 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3332 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3334 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3335 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3336 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3337 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3338 } elsif ($guest_agent->{type
} eq 'isa') {
3339 push @$devices, '-device', "isa-serial,chardev=qga0";
3343 my $rng = parse_rng
($conf->{rng0
}) if $conf->{rng0
};
3344 if ($rng && &$version_guard(4, 1, 2)) {
3345 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3346 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3348 my $limiter_str = "";
3350 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3353 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3354 die "cannot create VirtIO RNG device: source file '$rng->{source}' doesn't exist\n"
3355 if ! -e
$rng->{source
};
3357 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3359 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3360 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3368 for(my $i = 1; $i < $qxlnum; $i++){
3369 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3372 # assume other OS works like Linux
3373 my ($ram, $vram) = ("134217728", "67108864");
3374 if ($vga->{memory
}) {
3375 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3376 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3378 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3379 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3383 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3385 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3386 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3387 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3389 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3390 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3391 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3393 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3394 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3396 my $spice_enhancement = PVE
::JSONSchema
::parse_property_string
($spice_enhancements_fmt, $conf->{spice_enhancements
} // '');
3397 if ($spice_enhancement->{foldersharing
}) {
3398 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3399 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3402 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3403 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming
};
3404 push @$devices, '-spice', "$spice_opts";
3407 # enable balloon by default, unless explicitly disabled
3408 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3409 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3410 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3413 if ($conf->{watchdog
}) {
3414 my $wdopts = parse_watchdog
($conf->{watchdog
});
3415 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3416 my $watchdog = $wdopts->{model
} || 'i6300esb';
3417 push @$devices, '-device', "$watchdog$pciaddr";
3418 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3422 my $scsicontroller = {};
3423 my $ahcicontroller = {};
3424 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3426 # Add iscsi initiator name if available
3427 if (my $initiator = get_initiator_name
()) {
3428 push @$devices, '-iscsi', "initiator-name=$initiator";
3431 foreach_drive
($conf, sub {
3432 my ($ds, $drive) = @_;
3434 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3435 push @$vollist, $drive->{file
};
3438 # ignore efidisk here, already added in bios/fw handling code above
3439 return if $drive->{interface
} eq 'efidisk';
3441 $use_virtio = 1 if $ds =~ m/^virtio/;
3443 if (drive_is_cdrom
($drive)) {
3444 if ($bootindex_hash->{d
}) {
3445 $drive->{bootindex
} = $bootindex_hash->{d
};
3446 $bootindex_hash->{d
} += 1;
3449 if ($bootindex_hash->{c
}) {
3450 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3451 $bootindex_hash->{c
} += 1;
3455 if($drive->{interface
} eq 'virtio'){
3456 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3459 if ($drive->{interface
} eq 'scsi') {
3461 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3463 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3464 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3466 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3467 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3470 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3471 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3472 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3473 } elsif ($drive->{iothread
}) {
3474 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3478 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3479 $queues = ",num_queues=$drive->{queues}";
3482 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3483 $scsicontroller->{$controller}=1;
3486 if ($drive->{interface
} eq 'sata') {
3487 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
3488 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3489 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3490 $ahcicontroller->{$controller}=1;
3493 my $drive_cmd = print_drive_commandline_full
($storecfg, $vmid, $drive);
3494 push @$devices, '-drive',$drive_cmd;
3495 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3498 for (my $i = 0; $i < $MAX_NETS; $i++) {
3499 next if !$conf->{"net$i"};
3500 my $d = parse_net
($conf->{"net$i"});
3503 $use_virtio = 1 if $d->{model
} eq 'virtio';
3505 if ($bootindex_hash->{n
}) {
3506 $d->{bootindex
} = $bootindex_hash->{n
};
3507 $bootindex_hash->{n
} += 1;
3510 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3511 push @$devices, '-netdev', $netdevfull;
3513 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3514 push @$devices, '-device', $netdevicefull;
3517 if ($conf->{ivshmem
}) {
3518 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3522 $bus = print_pcie_addr
("ivshmem");
3524 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3527 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3528 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3530 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3531 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
3534 # pci.4 is nested in pci.1
3535 $bridges->{1} = 1 if $bridges->{4};
3539 if (min_version
($machine_version, 2, 3)) {
3544 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3548 for my $k (sort {$b cmp $a} keys %$bridges) {
3549 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3550 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3551 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3553 # add after -readconfig pve-q35.cfg
3554 splice @$devices, 2, 0, '-device', $devstr;
3556 unshift @$devices, '-device', $devstr if $k > 0;
3561 push @$machineFlags, 'accel=tcg';
3564 my $machine_type_min = $machine_type;
3565 if ($add_pve_version) {
3566 $machine_type_min =~ s/\+pve\d+$//;
3567 $machine_type_min .= "+pve$required_pve_version";
3569 push @$machineFlags, "type=${machine_type_min}";
3571 push @$cmd, @$devices;
3572 push @$cmd, '-rtc', join(',', @$rtcFlags)
3573 if scalar(@$rtcFlags);
3574 push @$cmd, '-machine', join(',', @$machineFlags)
3575 if scalar(@$machineFlags);
3576 push @$cmd, '-global', join(',', @$globalFlags)
3577 if scalar(@$globalFlags);
3579 if (my $vmstate = $conf->{vmstate
}) {
3580 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
3581 push @$vollist, $vmstate;
3582 push @$cmd, '-loadstate', $statepath;
3583 print "activating and using '$vmstate' as vmstate\n";
3587 if ($conf->{args
}) {
3588 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3592 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3598 my $res = mon_cmd
($vmid, 'query-spice');
3600 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3603 sub vm_devices_list
{
3606 my $res = mon_cmd
($vmid, 'query-pci');
3607 my $devices_to_check = [];
3609 foreach my $pcibus (@$res) {
3610 push @$devices_to_check, @{$pcibus->{devices
}},
3613 while (@$devices_to_check) {
3615 for my $d (@$devices_to_check) {
3616 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3617 next if !$d->{'pci_bridge'};
3619 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3620 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3622 $devices_to_check = $to_check;
3625 my $resblock = mon_cmd
($vmid, 'query-block');
3626 foreach my $block (@$resblock) {
3627 if($block->{device
} =~ m/^drive-(\S+)/){
3632 my $resmice = mon_cmd
($vmid, 'query-mice');
3633 foreach my $mice (@$resmice) {
3634 if ($mice->{name
} eq 'QEMU HID Tablet') {
3635 $devices->{tablet
} = 1;
3640 # for usb devices there is no query-usb
3641 # but we can iterate over the entries in
3642 # qom-list path=/machine/peripheral
3643 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3644 foreach my $per (@$resperipheral) {
3645 if ($per->{name
} =~ m/^usb\d+$/) {
3646 $devices->{$per->{name
}} = 1;
3654 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3656 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3658 my $devices_list = vm_devices_list
($vmid);
3659 return 1 if defined($devices_list->{$deviceid});
3661 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
3663 if ($deviceid eq 'tablet') {
3665 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3667 } elsif ($deviceid eq 'keyboard') {
3669 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3671 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3673 die "usb hotplug currently not reliable\n";
3674 # since we can't reliably hot unplug all added usb devices
3675 # and usb passthrough disables live migration
3676 # we disable usb hotplugging for now
3677 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3679 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3681 qemu_iothread_add
($vmid, $deviceid, $device);
3683 qemu_driveadd
($storecfg, $vmid, $device);
3684 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3686 qemu_deviceadd
($vmid, $devicefull);
3687 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3689 eval { qemu_drivedel
($vmid, $deviceid); };
3694 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3697 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3698 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3699 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3701 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3703 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3704 qemu_iothread_add
($vmid, $deviceid, $device);
3705 $devicefull .= ",iothread=iothread-$deviceid";
3708 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3709 $devicefull .= ",num_queues=$device->{queues}";
3712 qemu_deviceadd
($vmid, $devicefull);
3713 qemu_deviceaddverify
($vmid, $deviceid);
3715 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3717 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
3718 qemu_driveadd
($storecfg, $vmid, $device);
3720 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3721 eval { qemu_deviceadd
($vmid, $devicefull); };
3723 eval { qemu_drivedel
($vmid, $deviceid); };
3728 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3730 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
3732 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
3733 my $use_old_bios_files = undef;
3734 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3736 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
3737 qemu_deviceadd
($vmid, $netdevicefull);
3739 qemu_deviceaddverify
($vmid, $deviceid);
3740 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
3743 eval { qemu_netdevdel
($vmid, $deviceid); };
3748 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3751 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3752 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3754 qemu_deviceadd
($vmid, $devicefull);
3755 qemu_deviceaddverify
($vmid, $deviceid);
3758 die "can't hotplug device '$deviceid'\n";
3764 # fixme: this should raise exceptions on error!
3765 sub vm_deviceunplug
{
3766 my ($vmid, $conf, $deviceid) = @_;
3768 my $devices_list = vm_devices_list
($vmid);
3769 return 1 if !defined($devices_list->{$deviceid});
3771 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3773 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
3775 qemu_devicedel
($vmid, $deviceid);
3777 } elsif ($deviceid =~ m/^usb\d+$/) {
3779 die "usb hotplug currently not reliable\n";
3780 # when unplugging usb devices this way,
3781 # there may be remaining usb controllers/hubs
3782 # so we disable it for now
3783 qemu_devicedel
($vmid, $deviceid);
3784 qemu_devicedelverify
($vmid, $deviceid);
3786 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3788 qemu_devicedel
($vmid, $deviceid);
3789 qemu_devicedelverify
($vmid, $deviceid);
3790 qemu_drivedel
($vmid, $deviceid);
3791 qemu_iothread_del
($conf, $vmid, $deviceid);
3793 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3795 qemu_devicedel
($vmid, $deviceid);
3796 qemu_devicedelverify
($vmid, $deviceid);
3797 qemu_iothread_del
($conf, $vmid, $deviceid);
3799 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3801 qemu_devicedel
($vmid, $deviceid);
3802 qemu_drivedel
($vmid, $deviceid);
3803 qemu_deletescsihw
($conf, $vmid, $deviceid);
3805 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3807 qemu_devicedel
($vmid, $deviceid);
3808 qemu_devicedelverify
($vmid, $deviceid);
3809 qemu_netdevdel
($vmid, $deviceid);
3812 die "can't unplug device '$deviceid'\n";
3818 sub qemu_deviceadd
{
3819 my ($vmid, $devicefull) = @_;
3821 $devicefull = "driver=".$devicefull;
3822 my %options = split(/[=,]/, $devicefull);
3824 mon_cmd
($vmid, "device_add" , %options);
3827 sub qemu_devicedel
{
3828 my ($vmid, $deviceid) = @_;
3830 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
3833 sub qemu_iothread_add
{
3834 my($vmid, $deviceid, $device) = @_;
3836 if ($device->{iothread
}) {
3837 my $iothreads = vm_iothreads_list
($vmid);
3838 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3842 sub qemu_iothread_del
{
3843 my($conf, $vmid, $deviceid) = @_;
3845 my $confid = $deviceid;
3846 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
3847 $confid = 'scsi' . $1;
3849 my $device = parse_drive
($confid, $conf->{$confid});
3850 if ($device->{iothread
}) {
3851 my $iothreads = vm_iothreads_list
($vmid);
3852 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3856 sub qemu_objectadd
{
3857 my($vmid, $objectid, $qomtype) = @_;
3859 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3864 sub qemu_objectdel
{
3865 my($vmid, $objectid) = @_;
3867 mon_cmd
($vmid, "object-del", id
=> $objectid);
3873 my ($storecfg, $vmid, $device) = @_;
3875 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device);
3876 $drive =~ s/\\/\\\\/g;
3877 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
3879 # If the command succeeds qemu prints: "OK
"
3880 return 1 if $ret =~ m/OK/s;
3882 die "adding drive failed
: $ret\n";
3886 my($vmid, $deviceid) = @_;
3888 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
3891 return 1 if $ret eq "";
3893 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3894 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3896 die "deleting drive
$deviceid failed
: $ret\n";
3899 sub qemu_deviceaddverify {
3900 my ($vmid, $deviceid) = @_;
3902 for (my $i = 0; $i <= 5; $i++) {
3903 my $devices_list = vm_devices_list($vmid);
3904 return 1 if defined($devices_list->{$deviceid});
3908 die "error on hotplug device
'$deviceid'\n";
3912 sub qemu_devicedelverify {
3913 my ($vmid, $deviceid) = @_;
3915 # need to verify that the device is correctly removed as device_del
3916 # is async and empty return is not reliable
3918 for (my $i = 0; $i <= 5; $i++) {
3919 my $devices_list = vm_devices_list($vmid);
3920 return 1 if !defined($devices_list->{$deviceid});
3924 die "error on hot-unplugging device
'$deviceid'\n";
3927 sub qemu_findorcreatescsihw {
3928 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
3930 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3932 my $scsihwid="$controller_prefix$controller";
3933 my $devices_list = vm_devices_list($vmid);
3935 if(!defined($devices_list->{$scsihwid})) {
3936 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
3942 sub qemu_deletescsihw {
3943 my ($conf, $vmid, $opt) = @_;
3945 my $device = parse_drive($opt, $conf->{$opt});
3947 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3948 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3952 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3954 my $devices_list = vm_devices_list($vmid);
3955 foreach my $opt (keys %{$devices_list}) {
3956 if (is_valid_drivename($opt)) {
3957 my $drive = parse_drive($opt, $conf->{$opt});
3958 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3964 my $scsihwid="scsihw
$controller";
3966 vm_deviceunplug($vmid, $conf, $scsihwid);
3971 sub qemu_add_pci_bridge {
3972 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
3978 print_pci_addr($device, $bridges, $arch, $machine_type);
3980 while (my ($k, $v) = each %$bridges) {
3983 return 1 if !defined($bridgeid) || $bridgeid < 1;
3985 my $bridge = "pci
.$bridgeid";
3986 my $devices_list = vm_devices_list($vmid);
3988 if (!defined($devices_list->{$bridge})) {
3989 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
3995 sub qemu_set_link_status {
3996 my ($vmid, $device, $up) = @_;
3998 mon_cmd($vmid, "set_link
", name => $device,
3999 up => $up ? JSON::true : JSON::false);
4002 sub qemu_netdevadd {
4003 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4005 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4006 my %options = split(/[=,]/, $netdev);
4008 mon_cmd($vmid, "netdev_add
", %options);
4012 sub qemu_netdevdel {
4013 my ($vmid, $deviceid) = @_;
4015 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4018 sub qemu_usb_hotplug {
4019 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4023 # remove the old one first
4024 vm_deviceunplug($vmid, $conf, $deviceid);
4026 # check if xhci controller is necessary and available
4027 if ($device->{usb3}) {
4029 my $devicelist = vm_devices_list($vmid);
4031 if (!$devicelist->{xhci}) {
4032 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4033 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4036 my $d = parse_usb_device($device->{host});
4037 $d->{usb3} = $device->{usb3};
4040 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4043 sub qemu_cpu_hotplug {
4044 my ($vmid, $conf, $vcpus) = @_;
4046 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4049 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4050 $sockets = $conf->{sockets} if $conf->{sockets};
4051 my $cores = $conf->{cores} || 1;
4052 my $maxcpus = $sockets * $cores;
4054 $vcpus = $maxcpus if !$vcpus;
4056 die "you can
't add more vcpus than maxcpus\n"
4057 if $vcpus > $maxcpus;
4059 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4061 if ($vcpus < $currentvcpus) {
4063 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4065 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4066 qemu_devicedel($vmid, "cpu$i");
4068 my $currentrunningvcpus = undef;
4070 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4071 last if scalar(@{$currentrunningvcpus}) == $i-1;
4072 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4076 #update conf after each succesfull cpu unplug
4077 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4078 PVE::QemuConfig->write_config($vmid, $conf);
4081 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4087 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4088 die "vcpus in running vm does not match its configuration\n"
4089 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4091 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4093 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4094 my $cpustr = print_cpu_device($conf, $i);
4095 qemu_deviceadd($vmid, $cpustr);
4098 my $currentrunningvcpus = undef;
4100 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4101 last if scalar(@{$currentrunningvcpus}) == $i;
4102 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4106 #update conf after each succesfull cpu hotplug
4107 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4108 PVE::QemuConfig->write_config($vmid, $conf);
4112 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4113 mon_cmd($vmid, "cpu-add", id => int($i));
4118 sub qemu_block_set_io_throttle {
4119 my ($vmid, $deviceid,
4120 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4121 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4122 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4123 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4125 return if !check_running($vmid) ;
4127 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4129 bps_rd => int($bps_rd),
4130 bps_wr => int($bps_wr),
4132 iops_rd => int($iops_rd),
4133 iops_wr => int($iops_wr),
4134 bps_max => int($bps_max),
4135 bps_rd_max => int($bps_rd_max),
4136 bps_wr_max => int($bps_wr_max),
4137 iops_max => int($iops_max),
4138 iops_rd_max => int($iops_rd_max),
4139 iops_wr_max => int($iops_wr_max),
4140 bps_max_length => int($bps_max_length),
4141 bps_rd_max_length => int($bps_rd_max_length),
4142 bps_wr_max_length => int($bps_wr_max_length),
4143 iops_max_length => int($iops_max_length),
4144 iops_rd_max_length => int($iops_rd_max_length),
4145 iops_wr_max_length => int($iops_wr_max_length),
4150 # old code, only used to shutdown old VM after update
4152 my ($fh, $timeout) = @_;
4154 my $sel = new IO::Select;
4161 while (scalar (@ready = $sel->can_read($timeout))) {
4163 if ($count = $fh->sysread($buf, 8192)) {
4164 if ($buf =~ /^(.*)\(qemu\) $/s) {
4171 if (!defined($count)) {
4178 die "monitor read timeout\n" if !scalar(@ready);
4183 sub qemu_block_resize {
4184 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4186 my $running = check_running($vmid);
4188 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4190 return if !$running;
4192 my $padding = (1024 - $size % 1024) % 1024;
4193 $size = $size + $padding;
4195 mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4199 sub qemu_volume_snapshot {
4200 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4202 my $running = check_running($vmid);
4204 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4205 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4207 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4211 sub qemu_volume_snapshot_delete {
4212 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4214 my $running = check_running($vmid);
4219 my $conf = PVE::QemuConfig->load_config($vmid);
4220 foreach_drive($conf, sub {
4221 my ($ds, $drive) = @_;
4222 $running = 1 if $drive->{file} eq $volid;
4226 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4227 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4229 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4233 sub set_migration_caps {
4239 "auto-converge" => 1,
4241 "x-rdma-pin-all" => 0,
4246 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4248 for my $supported_capability (@$supported_capabilities) {
4250 capability => $supported_capability->{capability},
4251 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4255 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4258 my $fast_plug_option = {
4266 'vmstatestorage
' => 1,
4271 # hotplug changes in [PENDING]
4272 # $selection hash can be used to only apply specified options, for
4273 # example: { cores => 1 } (only apply changed 'cores
')
4274 # $errors ref is used to return error messages
4275 sub vmconfig_hotplug_pending {
4276 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4278 my $defaults = load_defaults();
4279 my $arch = get_vm_arch($conf);
4280 my $machine_type = get_vm_machine($conf, undef, $arch);
4282 # commit values which do not have any impact on running VM first
4283 # Note: those option cannot raise errors, we we do not care about
4284 # $selection and always apply them.
4286 my $add_error = sub {
4287 my ($opt, $msg) = @_;
4288 $errors->{$opt} = "hotplug problem - $msg";
4292 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4293 if ($fast_plug_option->{$opt}) {
4294 $conf->{$opt} = $conf->{pending}->{$opt};
4295 delete $conf->{pending}->{$opt};
4301 PVE::QemuConfig->write_config($vmid, $conf);
4304 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4306 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4307 foreach my $opt (sort keys %$pending_delete_hash) {
4308 next if $selection && !$selection->{$opt};
4309 my $force = $pending_delete_hash->{$opt}->{force};
4311 if ($opt eq 'hotplug
') {
4312 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4313 } elsif ($opt eq 'tablet
') {
4314 die "skip\n" if !$hotplug_features->{usb};
4315 if ($defaults->{tablet}) {
4316 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4317 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4318 if $arch eq 'aarch64
';
4320 vm_deviceunplug($vmid, $conf, 'tablet
');
4321 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4323 } elsif ($opt =~ m/^usb\d+/) {
4325 # since we cannot reliably hot unplug usb devices
4326 # we are disabling it
4327 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4328 vm_deviceunplug($vmid, $conf, $opt);
4329 } elsif ($opt eq 'vcpus
') {
4330 die "skip\n" if !$hotplug_features->{cpu};
4331 qemu_cpu_hotplug($vmid, $conf, undef);
4332 } elsif ($opt eq 'balloon
') {
4333 # enable balloon device is not hotpluggable
4334 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4335 # here we reset the ballooning value to memory
4336 my $balloon = $conf->{memory} || $defaults->{memory};
4337 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4338 } elsif ($fast_plug_option->{$opt}) {
4340 } elsif ($opt =~ m/^net(\d+)$/) {
4341 die "skip\n" if !$hotplug_features->{network};
4342 vm_deviceunplug($vmid, $conf, $opt);
4343 } elsif (is_valid_drivename($opt)) {
4344 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4345 vm_deviceunplug($vmid, $conf, $opt);
4346 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4347 } elsif ($opt =~ m/^memory$/) {
4348 die "skip\n" if !$hotplug_features->{memory};
4349 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4350 } elsif ($opt eq 'cpuunits
') {
4351 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4352 } elsif ($opt eq 'cpulimit
') {
4353 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4359 &$add_error($opt, $err) if $err ne "skip\n";
4361 delete $conf->{$opt};
4362 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4366 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4367 $apply_pending_cloudinit = sub {
4368 return if $apply_pending_cloudinit_done; # once is enough
4369 $apply_pending_cloudinit_done = 1; # once is enough
4371 my ($key, $value) = @_;
4373 my @cloudinit_opts = keys %$confdesc_cloudinit;
4374 foreach my $opt (keys %{$conf->{pending}}) {
4375 next if !grep { $_ eq $opt } @cloudinit_opts;
4376 $conf->{$opt} = delete $conf->{pending}->{$opt};
4379 my $new_conf = { %$conf };
4380 $new_conf->{$key} = $value;
4381 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4384 foreach my $opt (keys %{$conf->{pending}}) {
4385 next if $selection && !$selection->{$opt};
4386 my $value = $conf->{pending}->{$opt};
4388 if ($opt eq 'hotplug
') {
4389 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4390 } elsif ($opt eq 'tablet
') {
4391 die "skip\n" if !$hotplug_features->{usb};
4393 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4394 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4395 if $arch eq 'aarch64
';
4396 } elsif ($value == 0) {
4397 vm_deviceunplug($vmid, $conf, 'tablet
');
4398 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4400 } elsif ($opt =~ m/^usb\d+$/) {
4402 # since we cannot reliably hot unplug usb devices
4403 # we are disabling it
4404 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4405 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4406 die "skip\n" if !$d;
4407 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4408 } elsif ($opt eq 'vcpus
') {
4409 die "skip\n" if !$hotplug_features->{cpu};
4410 qemu_cpu_hotplug($vmid, $conf, $value);
4411 } elsif ($opt eq 'balloon
') {
4412 # enable/disable balloning device is not hotpluggable
4413 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4414 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4415 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4417 # allow manual ballooning if shares is set to zero
4418 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4419 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4420 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4422 } elsif ($opt =~ m/^net(\d+)$/) {
4423 # some changes can be done without hotplug
4424 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4425 $vmid, $opt, $value, $arch, $machine_type);
4426 } elsif (is_valid_drivename($opt)) {
4427 die "skip\n" if $opt eq 'efidisk0
';
4428 # some changes can be done without hotplug
4429 my $drive = parse_drive($opt, $value);
4430 if (drive_is_cloudinit($drive)) {
4431 &$apply_pending_cloudinit($opt, $value);
4433 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4434 $vmid, $opt, $value, $arch, $machine_type);
4435 } elsif ($opt =~ m/^memory$/) { #dimms
4436 die "skip\n" if !$hotplug_features->{memory};
4437 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4438 } elsif ($opt eq 'cpuunits
') {
4439 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4440 } elsif ($opt eq 'cpulimit
') {
4441 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4442 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4444 die "skip\n"; # skip non-hot-pluggable options
4448 &$add_error($opt, $err) if $err ne "skip\n";
4450 $conf->{$opt} = $value;
4451 delete $conf->{pending}->{$opt};
4455 PVE::QemuConfig->write_config($vmid, $conf);
4458 sub try_deallocate_drive {
4459 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4461 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4462 my $volid = $drive->{file};
4463 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4464 my $sid = PVE::Storage::parse_volume_id($volid);
4465 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4467 # check if the disk is really unused
4468 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4469 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
4470 PVE::Storage::vdisk_free($storecfg, $volid);
4473 # If vm is not owner of this disk remove from config
4481 sub vmconfig_delete_or_detach_drive {
4482 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4484 my $drive = parse_drive($opt, $conf->{$opt});
4486 my $rpcenv = PVE::RPCEnvironment::get();
4487 my $authuser = $rpcenv->get_user();
4490 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4491 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4493 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4499 sub vmconfig_apply_pending {
4500 my ($vmid, $conf, $storecfg, $errors) = @_;
4502 my $add_apply_error = sub {
4503 my ($opt, $msg) = @_;
4504 my $err_msg = "unable to apply pending change $opt : $msg";
4505 $errors->{$opt} = $err_msg;
4511 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4512 foreach my $opt (sort keys %$pending_delete_hash) {
4513 my $force = $pending_delete_hash->{$opt}->{force};
4515 if ($opt =~ m/^unused/) {
4516 die "internal error";
4517 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4518 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4522 $add_apply_error->($opt, $err);
4524 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4525 delete $conf->{$opt};
4529 PVE::QemuConfig->cleanup_pending($conf);
4531 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4532 next if $opt eq 'delete'; # just to be sure
4534 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4535 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4539 $add_apply_error->($opt, $err);
4541 $conf->{$opt} = delete $conf->{pending}->{$opt};
4545 # write all changes at once to avoid unnecessary i/o
4546 PVE::QemuConfig->write_config($vmid, $conf);
4549 sub vmconfig_update_net {
4550 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4552 my $newnet = parse_net($value);
4554 if ($conf->{$opt}) {
4555 my $oldnet = parse_net($conf->{$opt});
4557 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4558 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4559 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4560 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4562 # for non online change, we try to hot-unplug
4563 die "skip\n" if !$hotplug;
4564 vm_deviceunplug($vmid, $conf, $opt);
4567 die "internal error" if $opt !~ m/net(\d+)/;
4568 my $iface = "tap${vmid}i$1";
4570 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4571 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4572 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4573 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4574 PVE::Network::tap_unplug($iface);
4577 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4579 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4581 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4582 # Rate can be applied on its own but any change above needs to
4583 # include the rate in tap_plug since OVS resets everything.
4584 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4587 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4588 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4596 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4602 sub vmconfig_update_disk {
4603 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4605 my $drive = parse_drive($opt, $value);
4607 if ($conf->{$opt}) {
4609 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4611 my $media = $drive->{media} || 'disk
';
4612 my $oldmedia = $old_drive->{media} || 'disk
';
4613 die "unable to change media type\n" if $media ne $oldmedia;
4615 if (!drive_is_cdrom($old_drive)) {
4617 if ($drive->{file} ne $old_drive->{file}) {
4619 die "skip\n" if !$hotplug;
4621 # unplug and register as unused
4622 vm_deviceunplug($vmid, $conf, $opt);
4623 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4626 # update existing disk
4628 # skip non hotpluggable value
4629 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4630 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4631 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4632 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
4633 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
4638 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4639 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4640 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4641 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4642 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4643 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4644 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4645 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4646 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4647 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4648 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4649 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4650 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4651 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4652 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4653 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4654 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4655 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4657 qemu_block_set_io_throttle($vmid,"drive-$opt",
4658 ($drive->{mbps} || 0)*1024*1024,
4659 ($drive->{mbps_rd} || 0)*1024*1024,
4660 ($drive->{mbps_wr} || 0)*1024*1024,
4661 $drive->{iops} || 0,
4662 $drive->{iops_rd} || 0,
4663 $drive->{iops_wr} || 0,
4664 ($drive->{mbps_max} || 0)*1024*1024,
4665 ($drive->{mbps_rd_max} || 0)*1024*1024,
4666 ($drive->{mbps_wr_max} || 0)*1024*1024,
4667 $drive->{iops_max} || 0,
4668 $drive->{iops_rd_max} || 0,
4669 $drive->{iops_wr_max} || 0,
4670 $drive->{bps_max_length} || 1,
4671 $drive->{bps_rd_max_length} || 1,
4672 $drive->{bps_wr_max_length} || 1,
4673 $drive->{iops_max_length} || 1,
4674 $drive->{iops_rd_max_length} || 1,
4675 $drive->{iops_wr_max_length} || 1);
4684 if ($drive->{file} eq 'none
') {
4685 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4686 if (drive_is_cloudinit($old_drive)) {
4687 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4690 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4692 # force eject if locked
4693 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4696 mon_cmd($vmid, "blockdev-change-medium",
4697 id => "$opt", filename => "$path");
4706 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4708 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4709 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
4713 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4714 $forcemachine, $spice_ticket, $migration_network, $migration_type,
4715 $targetstorage, $timeout, $nbd_protocol_version, $replicated_volumes) = @_;
4717 PVE::QemuConfig->lock_config($vmid, sub {
4718 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4720 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4722 my $is_suspended = PVE::QemuConfig->has_lock($conf, 'suspended
');
4724 PVE::QemuConfig->check_lock($conf)
4725 if !($skiplock || $is_suspended);
4727 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4729 # clean up leftover reboot request files
4730 eval { clear_reboot_request($vmid); };
4733 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4734 vmconfig_apply_pending($vmid, $conf, $storecfg);
4735 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4738 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4740 my $defaults = load_defaults();
4742 # set environment variable useful inside network script
4743 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4745 my $local_volumes = {};
4747 if ($targetstorage) {
4748 foreach_drive($conf, sub {
4749 my ($ds, $drive) = @_;
4751 return if drive_is_cdrom($drive);
4753 my $volid = $drive->{file};
4757 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4759 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4760 return if $scfg->{shared};
4761 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4766 foreach my $opt (sort keys %$local_volumes) {
4768 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4769 if ($replicated_volumes->{$volid}) {
4770 # re-use existing, replicated volume with bitmap on source side
4771 $local_volumes->{$opt} = $conf->{${opt}};
4772 print "re-using replicated volume: $opt - $volid\n";
4775 my $drive = parse_drive($opt, $conf->{$opt});
4777 # If a remote storage is specified and the format of the original
4778 # volume is not available there, fall back to the default format.
4779 # Otherwise use the same format as the original.
4780 if ($targetstorage && $targetstorage ne "1") {
4781 $storeid = $targetstorage;
4782 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4783 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4784 my $fileFormat = qemu_img_format($scfg, $volname);
4785 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
4787 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4788 $format = qemu_img_format($scfg, $volname);
4791 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4792 my $newdrive = $drive;
4793 $newdrive->{format} = $format;
4794 $newdrive->{file} = $newvolid;
4795 my $drivestr = print_drive($newdrive);
4796 $local_volumes->{$opt} = $drivestr;
4797 #pass drive to conf for command line
4798 $conf->{$opt} = $drivestr;
4802 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
4804 if ($is_suspended) {
4805 # enforce machine type on suspended vm to ensure HW compatibility
4806 $forcemachine = $conf->{runningmachine};
4807 print "Resuming suspended VM\n";
4810 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4813 my $get_migration_ip = sub {
4814 my ($cidr, $nodename) = @_;
4816 return $migration_ip if defined($migration_ip);
4818 if (!defined($cidr)) {
4819 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4820 $cidr = $dc_conf->{migration}->{network};
4823 if (defined($cidr)) {
4824 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
4826 die "could not get IP: no address configured on local " .
4827 "node for network '$cidr'\n" if scalar(@$ips) == 0;
4829 die "could not get IP: multiple addresses configured on local " .
4830 "node for network '$cidr'\n" if scalar(@$ips) > 1;
4832 $migration_ip = @$ips[0];
4835 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
4836 if !defined($migration_ip);
4838 return $migration_ip;
4843 if ($statefile eq 'tcp
') {
4844 my $localip = "localhost";
4845 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4846 my $nodename = nodename();
4848 if (!defined($migration_type)) {
4849 if (defined($datacenterconf->{migration}->{type})) {
4850 $migration_type = $datacenterconf->{migration}->{type};
4852 $migration_type = 'secure
';
4856 if ($migration_type eq 'insecure
') {
4857 $localip = $get_migration_ip->($migration_network, $nodename);
4858 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4861 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4862 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4863 $migrate_uri = "tcp:${localip}:${migrate_port}";
4864 push @$cmd, '-incoming
', $migrate_uri;
4867 } elsif ($statefile eq 'unix
') {
4868 # should be default for secure migrations as a ssh TCP forward
4869 # tunnel is not deterministic reliable ready and fails regurarly
4870 # to set up in time, so use UNIX socket forwards
4871 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4872 unlink $socket_addr;
4874 $migrate_uri = "unix:$socket_addr";
4876 push @$cmd, '-incoming
', $migrate_uri;
4879 } elsif (-e $statefile) {
4880 push @$cmd, '-loadstate
', $statefile;
4882 my $statepath = PVE::Storage::path($storecfg, $statefile);
4883 push @$vollist, $statefile;
4884 push @$cmd, '-loadstate
', $statepath;
4891 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4892 my $d = parse_hostpci($conf->{"hostpci$i"});
4894 my $pcidevices = $d->{pciid};
4895 foreach my $pcidevice (@$pcidevices) {
4896 my $pciid = $pcidevice->{id};
4898 my $info = PVE::SysFSTools::pci_device_info("$pciid");
4899 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
4900 die "no pci device info for device '$pciid'\n" if !$info;
4903 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
4904 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
4906 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
4907 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
4908 die "can
't reset pci device '$pciid'\n"
4909 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
4914 PVE::Storage::activate_volumes($storecfg, $vollist);
4917 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4918 outfunc => sub {}, errfunc => sub {});
4920 # Issues with the above 'stop
' not being fully completed are extremely rare, a very low
4921 # timeout should be more than enough here...
4922 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
4924 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4925 : $defaults->{cpuunits};
4927 my $start_timeout = $timeout // config_aware_timeout($conf, $is_suspended);
4929 timeout => $statefile ? undef : $start_timeout,
4934 # when migrating, prefix QEMU output so other side can pick up any
4935 # errors that might occur and show the user
4936 if ($migratedfrom) {
4937 $run_params{quiet} = 1;
4938 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
4942 Slice => 'qemu
.slice
',
4944 CPUShares => $cpuunits
4947 if (my $cpulimit = $conf->{cpulimit}) {
4948 $properties{CPUQuota} = int($cpulimit * 100);
4950 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4952 my $run_qemu = sub {
4953 PVE::Tools::run_fork sub {
4954 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4956 my $exitcode = run_command($cmd, %run_params);
4957 die "QEMU exited with code $exitcode\n" if $exitcode;
4961 if ($conf->{hugepages}) {
4964 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4965 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4967 PVE::QemuServer::Memory::hugepages_mount();
4968 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4970 eval { $run_qemu->() };
4972 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4976 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4978 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4981 eval { $run_qemu->() };
4985 # deactivate volumes if start fails
4986 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4987 die "start failed: $err";
4990 print "migration listens on $migrate_uri\n" if $migrate_uri;
4992 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4993 eval { mon_cmd($vmid, "cont"); };
4997 #start nbd server for storage migration
4998 if ($targetstorage) {
4999 $nbd_protocol_version //= 0;
5001 my $migrate_storage_uri;
5002 # nbd_protocol_version > 0 for unix socket support
5003 if ($nbd_protocol_version > 0 && $migration_type eq 'secure
') {
5004 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5005 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix
', data => { path => $socket_path } } );
5006 $migrate_storage_uri = "nbd:unix:$socket_path";
5008 my $nodename = nodename();
5009 my $localip = $get_migration_ip->($migration_network, $nodename);
5010 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5011 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5013 mon_cmd($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${storage_migrate_port}" } } );
5014 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5015 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5018 foreach my $opt (sort keys %$local_volumes) {
5019 my $drivestr = $local_volumes->{$opt};
5020 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5021 print "storage migration listens on $migrate_storage_uri:exportname=drive-$opt volume:$drivestr\n";
5025 if ($migratedfrom) {
5027 set_migration_caps($vmid);
5032 print "spice listens on port $spice_port\n";
5033 if ($spice_ticket) {
5034 mon_cmd($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5035 mon_cmd($vmid, "expire_password", protocol => 'spice
', time => "+30");
5040 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5041 if !$statefile && $conf->{balloon};
5043 foreach my $opt (keys %$conf) {
5044 next if $opt !~ m/^net\d+$/;
5045 my $nicconf = parse_net($conf->{$opt});
5046 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5050 mon_cmd($vmid, 'qom-set
',
5051 path => "machine/peripheral/balloon0",
5052 property => "guest-stats-polling-interval",
5053 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5055 if ($is_suspended) {
5056 print "Resumed VM, removing state\n";
5057 if (my $vmstate = $conf->{vmstate}) {
5058 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5059 PVE::Storage::vdisk_free($storecfg, $vmstate);
5061 delete $conf->@{qw(lock vmstate runningmachine)};
5062 PVE
::QemuConfig-
>write_config($vmid, $conf);
5065 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5069 sub vm_commandline
{
5070 my ($storecfg, $vmid, $snapname) = @_;
5072 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5076 my $snapshot = $conf->{snapshots
}->{$snapname};
5077 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5079 # check for a 'runningmachine' in snapshot
5080 $forcemachine = $snapshot->{runningmachine
} if $snapshot->{runningmachine
};
5082 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5087 my $defaults = load_defaults
();
5089 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults, $forcemachine);
5091 return PVE
::Tools
::cmd2string
($cmd);
5095 my ($vmid, $skiplock) = @_;
5097 PVE
::QemuConfig-
>lock_config($vmid, sub {
5099 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5101 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5103 mon_cmd
($vmid, "system_reset");
5107 sub get_vm_volumes
{
5111 foreach_volid
($conf, sub {
5112 my ($volid, $attr) = @_;
5114 return if $volid =~ m
|^/|;
5116 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5119 push @$vollist, $volid;
5125 sub vm_stop_cleanup
{
5126 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5131 my $vollist = get_vm_volumes
($conf);
5132 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5135 foreach my $ext (qw(mon qmp pid vnc qga)) {
5136 unlink "/var/run/qemu-server/${vmid}.$ext";
5139 if ($conf->{ivshmem
}) {
5140 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5141 # just delete it for now, VMs which have this already open do not
5142 # are affected, but new VMs will get a separated one. If this
5143 # becomes an issue we either add some sort of ref-counting or just
5144 # add a "don't delete on stop" flag to the ivshmem format.
5145 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5148 foreach my $key (keys %$conf) {
5149 next if $key !~ m/^hostpci(\d+)$/;
5150 my $hostpciindex = $1;
5151 my $d = parse_hostpci
($conf->{$key});
5152 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5154 foreach my $pci (@{$d->{pciid
}}) {
5155 my $pciid = $pci->{id
};
5156 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5160 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5162 warn $@ if $@; # avoid errors - just warn
5165 # call only in locked context
5167 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5169 my $pid = check_running
($vmid, $nocheck);
5174 $conf = PVE
::QemuConfig-
>load_config($vmid);
5175 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5176 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5177 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5178 $timeout = $opts->{down
} if $opts->{down
};
5180 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5185 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5186 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5188 mon_cmd
($vmid, "system_powerdown");
5191 mon_cmd
($vmid, "quit");
5197 $timeout = 60 if !defined($timeout);
5200 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5205 if ($count >= $timeout) {
5207 warn "VM still running - terminating now with SIGTERM\n";
5210 die "VM quit/powerdown failed - got timeout\n";
5213 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5218 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5221 die "VM quit/powerdown failed\n";
5229 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5234 if ($count >= $timeout) {
5235 warn "VM still running - terminating now with SIGKILL\n";
5240 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5243 # Note: use $nocheck to skip tests if VM configuration file exists.
5244 # We need that when migration VMs to other nodes (files already moved)
5245 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5247 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5249 $force = 1 if !defined($force) && !$shutdown;
5252 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5253 kill 15, $pid if $pid;
5254 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5255 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5259 PVE
::QemuConfig-
>lock_config($vmid, sub {
5260 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
5265 my ($vmid, $timeout) = @_;
5267 PVE
::QemuConfig-
>lock_config($vmid, sub {
5270 # only reboot if running, as qmeventd starts it again on a stop event
5271 return if !check_running
($vmid);
5273 create_reboot_request
($vmid);
5275 my $storecfg = PVE
::Storage
::config
();
5276 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
5280 # avoid that the next normal shutdown will be confused for a reboot
5281 clear_reboot_request
($vmid);
5287 # note: if using the statestorage parameter, the caller has to check privileges
5289 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5296 PVE
::QemuConfig-
>lock_config($vmid, sub {
5298 $conf = PVE
::QemuConfig-
>load_config($vmid);
5300 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5301 PVE
::QemuConfig-
>check_lock($conf)
5302 if !($skiplock || $is_backing_up);
5304 die "cannot suspend to disk during backup\n"
5305 if $is_backing_up && $includestate;
5307 if ($includestate) {
5308 $conf->{lock} = 'suspending';
5309 my $date = strftime
("%Y-%m-%d", localtime(time()));
5310 $storecfg = PVE
::Storage
::config
();
5311 if (!$statestorage) {
5312 $statestorage = find_vmstate_storage
($conf, $storecfg);
5313 # check permissions for the storage
5314 my $rpcenv = PVE
::RPCEnvironment
::get
();
5315 if ($rpcenv->{type
} ne 'cli') {
5316 my $authuser = $rpcenv->get_user();
5317 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5322 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5323 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5324 PVE
::QemuConfig-
>write_config($vmid, $conf);
5326 mon_cmd
($vmid, "stop");
5330 if ($includestate) {
5332 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5335 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5337 my $state = mon_cmd
($vmid, "query-savevm");
5338 if (!$state->{status
}) {
5339 die "savevm not active\n";
5340 } elsif ($state->{status
} eq 'active') {
5343 } elsif ($state->{status
} eq 'completed') {
5344 print "State saved, quitting\n";
5346 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5347 die "query-savevm failed with error '$state->{error}'\n"
5349 die "query-savevm returned status '$state->{status}'\n";
5355 PVE
::QemuConfig-
>lock_config($vmid, sub {
5356 $conf = PVE
::QemuConfig-
>load_config($vmid);
5358 # cleanup, but leave suspending lock, to indicate something went wrong
5360 mon_cmd
($vmid, "savevm-end");
5361 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5362 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5363 delete $conf->@{qw(vmstate runningmachine)};
5364 PVE
::QemuConfig-
>write_config($vmid, $conf);
5370 die "lock changed unexpectedly\n"
5371 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5373 mon_cmd
($vmid, "quit");
5374 $conf->{lock} = 'suspended';
5375 PVE
::QemuConfig-
>write_config($vmid, $conf);
5381 my ($vmid, $skiplock, $nocheck) = @_;
5383 PVE
::QemuConfig-
>lock_config($vmid, sub {
5384 my $res = mon_cmd
($vmid, 'query-status');
5385 my $resume_cmd = 'cont';
5387 if ($res->{status
} && $res->{status
} eq 'suspended') {
5388 $resume_cmd = 'system_wakeup';
5393 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5395 PVE
::QemuConfig-
>check_lock($conf)
5396 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5399 mon_cmd
($vmid, $resume_cmd);
5404 my ($vmid, $skiplock, $key) = @_;
5406 PVE
::QemuConfig-
>lock_config($vmid, sub {
5408 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5410 # there is no qmp command, so we use the human monitor command
5411 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
5412 die $res if $res ne '';
5416 # vzdump restore implementaion
5418 sub tar_archive_read_firstfile
{
5419 my $archive = shift;
5421 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5423 # try to detect archive type first
5424 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5425 die "unable to open file '$archive'\n";
5426 my $firstfile = <$fh>;
5430 die "ERROR: archive contaions no data\n" if !$firstfile;
5436 sub tar_restore_cleanup
{
5437 my ($storecfg, $statfile) = @_;
5439 print STDERR
"starting cleanup\n";
5441 if (my $fd = IO
::File-
>new($statfile, "r")) {
5442 while (defined(my $line = <$fd>)) {
5443 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5446 if ($volid =~ m
|^/|) {
5447 unlink $volid || die 'unlink failed\n';
5449 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5451 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5453 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5455 print STDERR
"unable to parse line in statfile - $line";
5462 sub restore_file_archive
{
5463 my ($archive, $vmid, $user, $opts) = @_;
5465 my $format = $opts->{format
};
5468 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5469 $format = 'tar' if !$format;
5471 } elsif ($archive =~ m/\.tar$/) {
5472 $format = 'tar' if !$format;
5473 } elsif ($archive =~ m/.tar.lzo$/) {
5474 $format = 'tar' if !$format;
5476 } elsif ($archive =~ m/\.vma$/) {
5477 $format = 'vma' if !$format;
5478 } elsif ($archive =~ m/\.vma\.gz$/) {
5479 $format = 'vma' if !$format;
5481 } elsif ($archive =~ m/\.vma\.lzo$/) {
5482 $format = 'vma' if !$format;
5485 $format = 'vma' if !$format; # default
5488 # try to detect archive format
5489 if ($format eq 'tar') {
5490 return restore_tar_archive
($archive, $vmid, $user, $opts);
5492 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5496 # hepler to remove disks that will not be used after restore
5497 my $restore_cleanup_oldconf = sub {
5498 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
5500 foreach_drive
($oldconf, sub {
5501 my ($ds, $drive) = @_;
5503 return if drive_is_cdrom
($drive, 1);
5505 my $volid = $drive->{file
};
5506 return if !$volid || $volid =~ m
|^/|;
5508 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
5509 return if !$path || !$owner || ($owner != $vmid);
5511 # Note: only delete disk we want to restore
5512 # other volumes will become unused
5513 if ($virtdev_hash->{$ds}) {
5514 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
5521 # delete vmstate files, after the restore we have no snapshots anymore
5522 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5523 my $snap = $oldconf->{snapshots
}->{$snapname};
5524 if ($snap->{vmstate
}) {
5525 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
5533 # Helper to parse vzdump backup device hints
5535 # $rpcenv: Environment, used to ckeck storage permissions
5536 # $user: User ID, to check storage permissions
5537 # $storecfg: Storage configuration
5538 # $fh: the file handle for reading the configuration
5539 # $devinfo: should contain device sizes for all backu-up'ed devices
5540 # $options: backup options (pool, default storage)
5542 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
5543 my $parse_backup_hints = sub {
5544 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
5546 my $virtdev_hash = {};
5548 while (defined(my $line = <$fh>)) {
5549 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5550 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5551 die "archive does not contain data for drive '$virtdev'\n"
5552 if !$devinfo->{$devname};
5554 if (defined($options->{storage
})) {
5555 $storeid = $options->{storage
} || 'local';
5556 } elsif (!$storeid) {
5559 $format = 'raw' if !$format;
5560 $devinfo->{$devname}->{devname
} = $devname;
5561 $devinfo->{$devname}->{virtdev
} = $virtdev;
5562 $devinfo->{$devname}->{format
} = $format;
5563 $devinfo->{$devname}->{storeid
} = $storeid;
5565 # check permission on storage
5566 my $pool = $options->{pool
}; # todo: do we need that?
5567 if ($user ne 'root@pam') {
5568 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5571 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5572 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
5574 my $drive = parse_drive
($virtdev, $2);
5575 if (drive_is_cloudinit
($drive)) {
5576 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5577 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5578 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
5580 $virtdev_hash->{$virtdev} = {
5582 storeid
=> $options->{storage
} // $storeid,
5583 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
5590 return $virtdev_hash;
5593 # Helper to allocate and activate all volumes required for a restore
5595 # $storecfg: Storage configuration
5596 # $virtdev_hash: as returned by parse_backup_hints()
5598 # Returns: { $virtdev => $volid }
5599 my $restore_allocate_devices = sub {
5600 my ($storecfg, $virtdev_hash, $vmid) = @_;
5603 foreach my $virtdev (sort keys %$virtdev_hash) {
5604 my $d = $virtdev_hash->{$virtdev};
5605 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5606 my $storeid = $d->{storeid
};
5607 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5609 # test if requested format is supported
5610 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5611 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5612 $d->{format
} = $defFormat if !$supported;
5615 if ($d->{is_cloudinit
}) {
5616 $name = "vm-$vmid-cloudinit";
5617 $name .= ".$d->{format}" if $d->{format
} ne 'raw';
5620 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
5622 print STDERR
"new volume ID is '$volid'\n";
5623 $d->{volid
} = $volid;
5625 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
5627 $map->{$virtdev} = $volid;
5633 my $restore_update_config_line = sub {
5634 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5636 return if $line =~ m/^\#qmdump\#/;
5637 return if $line =~ m/^\#vzdump\#/;
5638 return if $line =~ m/^lock:/;
5639 return if $line =~ m/^unused\d+:/;
5640 return if $line =~ m/^parent:/;
5642 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5643 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5644 # try to convert old 1.X settings
5645 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5646 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5647 my ($model, $macaddr) = split(/\=/, $devconfig);
5648 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5651 bridge
=> "vmbr$ind",
5652 macaddr
=> $macaddr,
5654 my $netstr = print_net
($net);
5656 print $outfd "net$cookie->{netcount}: $netstr\n";
5657 $cookie->{netcount
}++;
5659 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5660 my ($id, $netstr) = ($1, $2);
5661 my $net = parse_net
($netstr);
5662 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5663 $netstr = print_net
($net);
5664 print $outfd "$id: $netstr\n";
5665 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5668 my $di = parse_drive
($virtdev, $value);
5669 if (defined($di->{backup
}) && !$di->{backup
}) {
5670 print $outfd "#$line";
5671 } elsif ($map->{$virtdev}) {
5672 delete $di->{format
}; # format can change on restore
5673 $di->{file
} = $map->{$virtdev};
5674 $value = print_drive
($di);
5675 print $outfd "$virtdev: $value\n";
5679 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5681 if ($vmgenid ne '0') {
5682 # always generate a new vmgenid if there was a valid one setup
5683 $vmgenid = generate_uuid
();
5685 print $outfd "vmgenid: $vmgenid\n";
5686 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5687 my ($uuid, $uuid_str);
5688 UUID
::generate
($uuid);
5689 UUID
::unparse
($uuid, $uuid_str);
5690 my $smbios1 = parse_smbios1
($2);
5691 $smbios1->{uuid
} = $uuid_str;
5692 print $outfd $1.print_smbios1
($smbios1)."\n";
5698 my $restore_deactivate_volumes = sub {
5699 my ($storecfg, $devinfo) = @_;
5702 foreach my $devname (keys %$devinfo) {
5703 my $volid = $devinfo->{$devname}->{volid
};
5704 push @$vollist, $volid if $volid;
5707 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5710 my $restore_destroy_volumes = sub {
5711 my ($storecfg, $devinfo) = @_;
5713 foreach my $devname (keys %$devinfo) {
5714 my $volid = $devinfo->{$devname}->{volid
};
5717 if ($volid =~ m
|^/|) {
5718 unlink $volid || die 'unlink failed\n';
5720 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5722 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5724 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5729 my ($cfg, $vmid) = @_;
5731 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5733 my $volid_hash = {};
5734 foreach my $storeid (keys %$info) {
5735 foreach my $item (@{$info->{$storeid}}) {
5736 next if !($item->{volid
} && $item->{size
});
5737 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5738 $volid_hash->{$item->{volid
}} = $item;
5745 sub update_disk_config
{
5746 my ($vmid, $conf, $volid_hash) = @_;
5749 my $prefix = "VM $vmid:";
5751 # used and unused disks
5752 my $referenced = {};
5754 # Note: it is allowed to define multiple storages with same path (alias), so
5755 # we need to check both 'volid' and real 'path' (two different volid can point
5756 # to the same path).
5758 my $referencedpath = {};
5761 PVE
::QemuConfig-
>foreach_volume($conf, sub {
5762 my ($opt, $drive) = @_;
5764 my $volid = $drive->{file
};
5767 # mark volid as "in-use" for next step
5768 $referenced->{$volid} = 1;
5769 if ($volid_hash->{$volid} &&
5770 (my $path = $volid_hash->{$volid}->{path
})) {
5771 $referencedpath->{$path} = 1;
5774 return if drive_is_cdrom
($drive);
5775 return if !$volid_hash->{$volid};
5777 my ($updated, $old_size, $new_size) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volid_hash);
5778 if (defined($updated)) {
5780 $conf->{$opt} = print_drive
($updated);
5781 print "$prefix size of disk '$volid' ($opt) updated from $old_size to $new_size\n";
5785 # remove 'unusedX' entry if volume is used
5786 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
5787 my ($opt, $drive) = @_;
5789 my $volid = $drive->{file
};
5792 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5793 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5794 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5796 delete $conf->{$opt};
5799 $referenced->{$volid} = 1;
5800 $referencedpath->{$path} = 1 if $path;
5803 foreach my $volid (sort keys %$volid_hash) {
5804 next if $volid =~ m/vm-$vmid-state-/;
5805 next if $referenced->{$volid};
5806 my $path = $volid_hash->{$volid}->{path
};
5807 next if !$path; # just to be sure
5808 next if $referencedpath->{$path};
5810 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5811 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
5812 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5819 my ($vmid, $nolock, $dryrun) = @_;
5821 my $cfg = PVE
::Storage
::config
();
5823 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5824 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5825 foreach my $stor (keys %{$cfg->{ids
}}) {
5826 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5829 print "rescan volumes...\n";
5830 my $volid_hash = scan_volids
($cfg, $vmid);
5832 my $updatefn = sub {
5835 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5837 PVE
::QemuConfig-
>check_lock($conf);
5840 foreach my $volid (keys %$volid_hash) {
5841 my $info = $volid_hash->{$volid};
5842 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5845 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
5847 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5850 if (defined($vmid)) {
5854 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5857 my $vmlist = config_list
();
5858 foreach my $vmid (keys %$vmlist) {
5862 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5868 sub restore_proxmox_backup_archive
{
5869 my ($archive, $vmid, $user, $options) = @_;
5871 my $storecfg = PVE
::Storage
::config
();
5873 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
5874 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5876 my $server = $scfg->{server
};
5877 my $datastore = $scfg->{datastore
};
5878 my $username = $scfg->{username
} // 'root@pam';
5879 my $fingerprint = $scfg->{fingerprint
};
5881 my $repo = "$username\@$server:$datastore";
5882 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
5883 local $ENV{PBS_PASSWORD
} = $password;
5884 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
5886 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
5887 PVE
::Storage
::parse_volname
($storecfg, $archive);
5889 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
5891 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
5893 my $tmpdir = "/var/tmp/vzdumptmp$$";
5897 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5898 my $tmpfn = "$conffile.$$.tmp";
5899 # disable interrupts (always do cleanups)
5903 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
5905 # Note: $oldconf is undef if VM does not exists
5906 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5907 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5909 my $rpcenv = PVE
::RPCEnvironment
::get
();
5918 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5920 my $cfgfn = "$tmpdir/qemu-server.conf";
5921 my $firewall_config_fn = "$tmpdir/fw.conf";
5922 my $index_fn = "$tmpdir/index.json";
5924 my $cmd = "restore";
5926 my $param = [$pbs_backup_name, "index.json", $index_fn];
5927 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
5928 my $index = PVE
::Tools
::file_get_contents
($index_fn);
5929 $index = decode_json
($index);
5931 # print Dumper($index);
5932 foreach my $info (@{$index->{files
}}) {
5933 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
5935 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
5936 $devinfo->{$devname}->{size
} = $1;
5938 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
5943 my $is_qemu_server_backup = scalar(grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}});
5944 if (!$is_qemu_server_backup) {
5945 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
5947 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
5949 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
5950 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
5952 if ($has_firewall_config) {
5953 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
5954 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
5956 my $pve_firewall_dir = '/etc/pve/firewall';
5957 mkdir $pve_firewall_dir; # make sure the dir exists
5958 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
5961 my $fh = IO
::File-
>new($cfgfn, "r") ||
5962 "unable to read qemu-server.conf - $!\n";
5964 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
5966 # fixme: rate limit?
5968 # create empty/temp config
5969 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
5971 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
5974 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
5976 foreach my $virtdev (sort keys %$virtdev_hash) {
5977 my $d = $virtdev_hash->{$virtdev};
5978 next if $d->{is_cloudinit
}; # no need to restore cloudinit
5980 my $volid = $d->{volid
};
5982 my $path = PVE
::Storage
::path
($storecfg, $volid);
5984 my $pbs_restore_cmd = [
5985 '/usr/bin/pbs-restore',
5986 '--repository', $repo,
5988 "$d->{devname}.img.fidx",
5993 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
5994 push @$pbs_restore_cmd, '--skip-zero';
5997 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
5998 print "restore proxmox backup image: $dbg_cmdstring\n";
5999 run_command
($pbs_restore_cmd);
6002 $fh->seek(0, 0) || die "seek failed - $!\n";
6004 my $outfd = new IO
::File
($tmpfn, "w") ||
6005 die "unable to write config for VM $vmid\n";
6007 my $cookie = { netcount
=> 0 };
6008 while (defined(my $line = <$fh>)) {
6009 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $options->{unique
});
6017 $restore_deactivate_volumes->($storecfg, $devinfo);
6023 $restore_destroy_volumes->($storecfg, $devinfo);
6027 rename($tmpfn, $conffile) ||
6028 die "unable to commit configuration file '$conffile'\n";
6030 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6032 eval { rescan
($vmid, 1); };
6036 sub restore_vma_archive
{
6037 my ($archive, $vmid, $user, $opts, $comp) = @_;
6039 my $readfrom = $archive;
6041 my $cfg = PVE
::Storage
::config
();
6043 my $bwlimit = $opts->{bwlimit
};
6045 my $dbg_cmdstring = '';
6046 my $add_pipe = sub {
6048 push @$commands, $cmd;
6049 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6050 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6055 if ($archive eq '-') {
6058 # If we use a backup from a PVE defined storage we also consider that
6059 # storage's rate limit:
6060 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6061 if (defined($volid)) {
6062 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6063 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6065 print STDERR
"applying read rate limit: $readlimit\n";
6066 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6067 $add_pipe->($cstream);
6074 if ($comp eq 'gzip') {
6075 $cmd = ['zcat', $readfrom];
6076 } elsif ($comp eq 'lzop') {
6077 $cmd = ['lzop', '-d', '-c', $readfrom];
6079 die "unknown compression method '$comp'\n";
6084 my $tmpdir = "/var/tmp/vzdumptmp$$";
6087 # disable interrupts (always do cleanups)
6091 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6093 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6094 POSIX
::mkfifo
($mapfifo, 0600);
6097 my $openfifo = sub {
6098 open($fifofh, '>', $mapfifo) || die $!;
6101 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6108 my $rpcenv = PVE
::RPCEnvironment
::get
();
6110 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6111 my $tmpfn = "$conffile.$$.tmp";
6113 # Note: $oldconf is undef if VM does not exist
6114 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6115 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6119 my $print_devmap = sub {
6120 my $cfgfn = "$tmpdir/qemu-server.conf";
6122 # we can read the config - that is already extracted
6123 my $fh = IO
::File-
>new($cfgfn, "r") ||
6124 "unable to read qemu-server.conf - $!\n";
6126 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6128 my $pve_firewall_dir = '/etc/pve/firewall';
6129 mkdir $pve_firewall_dir; # make sure the dir exists
6130 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6133 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
6135 foreach my $key (keys %storage_limits) {
6136 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6138 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6139 $storage_limits{$key} = $limit * 1024;
6142 foreach my $devname (keys %$devinfo) {
6143 die "found no device mapping information for device '$devname'\n"
6144 if !$devinfo->{$devname}->{virtdev
};
6147 # create empty/temp config
6149 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6150 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
6154 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6156 # print restore information to $fifofh
6157 foreach my $virtdev (sort keys %$virtdev_hash) {
6158 my $d = $virtdev_hash->{$virtdev};
6159 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6161 my $storeid = $d->{storeid
};
6162 my $volid = $d->{volid
};
6165 if (my $limit = $storage_limits{$storeid}) {
6166 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6169 my $write_zeros = 1;
6170 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6174 my $path = PVE
::Storage
::path
($cfg, $volid);
6176 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6178 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6181 $fh->seek(0, 0) || die "seek failed - $!\n";
6183 my $outfd = new IO
::File
($tmpfn, "w") ||
6184 die "unable to write config for VM $vmid\n";
6186 my $cookie = { netcount
=> 0 };
6187 while (defined(my $line = <$fh>)) {
6188 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6201 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6202 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6204 $oldtimeout = alarm($timeout);
6211 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6212 my ($dev_id, $size, $devname) = ($1, $2, $3);
6213 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6214 } elsif ($line =~ m/^CTIME: /) {
6215 # we correctly received the vma config, so we can disable
6216 # the timeout now for disk allocation (set to 10 minutes, so
6217 # that we always timeout if something goes wrong)
6220 print $fifofh "done\n";
6221 my $tmp = $oldtimeout || 0;
6222 $oldtimeout = undef;
6228 print "restore vma archive: $dbg_cmdstring\n";
6229 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6233 alarm($oldtimeout) if $oldtimeout;
6235 $restore_deactivate_volumes->($cfg, $devinfo);
6242 $restore_destroy_volumes->($cfg, $devinfo);
6246 rename($tmpfn, $conffile) ||
6247 die "unable to commit configuration file '$conffile'\n";
6249 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6251 eval { rescan
($vmid, 1); };
6255 sub restore_tar_archive
{
6256 my ($archive, $vmid, $user, $opts) = @_;
6258 if ($archive ne '-') {
6259 my $firstfile = tar_archive_read_firstfile
($archive);
6260 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6261 if $firstfile ne 'qemu-server.conf';
6264 my $storecfg = PVE
::Storage
::config
();
6266 # avoid zombie disks when restoring over an existing VM -> cleanup first
6267 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6268 # skiplock=1 because qmrestore has set the 'create' lock itself already
6269 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6270 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
6272 my $tocmd = "/usr/lib/qemu-server/qmextract";
6274 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6275 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6276 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6277 $tocmd .= ' --info' if $opts->{info
};
6279 # tar option "xf" does not autodetect compression when read from STDIN,
6280 # so we pipe to zcat
6281 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6282 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6284 my $tmpdir = "/var/tmp/vzdumptmp$$";
6287 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6288 local $ENV{VZDUMP_VMID
} = $vmid;
6289 local $ENV{VZDUMP_USER
} = $user;
6291 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6292 my $tmpfn = "$conffile.$$.tmp";
6294 # disable interrupts (always do cleanups)
6298 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6306 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6308 if ($archive eq '-') {
6309 print "extracting archive from STDIN\n";
6310 run_command
($cmd, input
=> "<&STDIN");
6312 print "extracting archive '$archive'\n";
6316 return if $opts->{info
};
6320 my $statfile = "$tmpdir/qmrestore.stat";
6321 if (my $fd = IO
::File-
>new($statfile, "r")) {
6322 while (defined (my $line = <$fd>)) {
6323 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6324 $map->{$1} = $2 if $1;
6326 print STDERR
"unable to parse line in statfile - $line\n";
6332 my $confsrc = "$tmpdir/qemu-server.conf";
6334 my $srcfd = new IO
::File
($confsrc, "r") ||
6335 die "unable to open file '$confsrc'\n";
6337 my $outfd = new IO
::File
($tmpfn, "w") ||
6338 die "unable to write config for VM $vmid\n";
6340 my $cookie = { netcount
=> 0 };
6341 while (defined (my $line = <$srcfd>)) {
6342 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6350 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6356 rename $tmpfn, $conffile ||
6357 die "unable to commit configuration file '$conffile'\n";
6359 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6361 eval { rescan
($vmid, 1); };
6365 sub foreach_storage_used_by_vm
{
6366 my ($conf, $func) = @_;
6370 foreach_drive
($conf, sub {
6371 my ($ds, $drive) = @_;
6372 return if drive_is_cdrom
($drive);
6374 my $volid = $drive->{file
};
6376 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6377 $sidhash->{$sid} = $sid if $sid;
6380 foreach my $sid (sort keys %$sidhash) {
6385 my $qemu_snap_storage = {
6388 sub do_snapshots_with_qemu
{
6389 my ($storecfg, $volid) = @_;
6391 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6392 my $scfg = $storecfg->{ids
}->{$storage_name};
6394 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
6398 if ($volid =~ m/\.(qcow2|qed)$/){
6405 sub qga_check_running
{
6406 my ($vmid, $nowarn) = @_;
6408 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6410 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6416 sub template_create
{
6417 my ($vmid, $conf, $disk) = @_;
6419 my $storecfg = PVE
::Storage
::config
();
6421 foreach_drive
($conf, sub {
6422 my ($ds, $drive) = @_;
6424 return if drive_is_cdrom
($drive);
6425 return if $disk && $ds ne $disk;
6427 my $volid = $drive->{file
};
6428 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6430 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6431 $drive->{file
} = $voliddst;
6432 $conf->{$ds} = print_drive
($drive);
6433 PVE
::QemuConfig-
>write_config($vmid, $conf);
6437 sub convert_iscsi_path
{
6440 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6445 my $initiator_name = get_initiator_name
();
6447 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6448 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6451 die "cannot convert iscsi path '$path', unkown format\n";
6454 sub qemu_img_convert
{
6455 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6457 my $storecfg = PVE
::Storage
::config
();
6458 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6459 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6461 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6465 my $src_is_iscsi = 0;
6469 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6470 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6471 $src_format = qemu_img_format
($src_scfg, $src_volname);
6472 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6473 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6474 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
6475 } elsif (-f
$src_volid) {
6476 $src_path = $src_volid;
6477 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6482 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
6484 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6485 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6486 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6487 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
6490 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6491 push @$cmd, '-l', "snapshot.name=$snapname"
6492 if $snapname && $src_format && $src_format eq "qcow2";
6493 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6494 push @$cmd, '-T', $cachemode if defined($cachemode);
6496 if ($src_is_iscsi) {
6497 push @$cmd, '--image-opts';
6498 $src_path = convert_iscsi_path
($src_path);
6499 } elsif ($src_format) {
6500 push @$cmd, '-f', $src_format;
6503 if ($dst_is_iscsi) {
6504 push @$cmd, '--target-image-opts';
6505 $dst_path = convert_iscsi_path
($dst_path);
6507 push @$cmd, '-O', $dst_format;
6510 push @$cmd, $src_path;
6512 if (!$dst_is_iscsi && $is_zero_initialized) {
6513 push @$cmd, "zeroinit:$dst_path";
6515 push @$cmd, $dst_path;
6520 if($line =~ m/\((\S+)\/100\
%\)/){
6522 my $transferred = int($size * $percent / 100);
6523 my $remaining = $size - $transferred;
6525 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6530 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6532 die "copy failed: $err" if $err;
6535 sub qemu_img_format
{
6536 my ($scfg, $volname) = @_;
6538 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6545 sub qemu_drive_mirror
{
6546 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
6548 $jobs = {} if !$jobs;
6552 $jobs->{"drive-$drive"} = {};
6554 if ($dst_volid =~ /^nbd:/) {
6555 $qemu_target = $dst_volid;
6558 my $storecfg = PVE
::Storage
::config
();
6559 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6561 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6563 $format = qemu_img_format
($dst_scfg, $dst_volname);
6565 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6567 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6570 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6571 $opts->{format
} = $format if $format;
6573 if (defined($src_bitmap)) {
6574 $opts->{sync
} = 'incremental';
6575 $opts->{bitmap
} = $src_bitmap;
6576 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
6579 if (defined($bwlimit)) {
6580 $opts->{speed
} = $bwlimit * 1024;
6581 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
6583 print "drive mirror is starting for drive-$drive\n";
6586 # if a job already runs for this device we get an error, catch it for cleanup
6587 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
6589 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6591 die "mirroring error: $err\n";
6594 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
6597 # $completion can be either
6598 # 'complete': wait until all jobs are ready, block-job-complete them (default)
6599 # 'cancel': wait until all jobs are ready, block-job-cancel them
6600 # 'skip': wait until all jobs are ready, return with block jobs in ready state
6601 sub qemu_drive_mirror_monitor
{
6602 my ($vmid, $vmiddst, $jobs, $completion, $qga) = @_;
6604 $completion //= 'complete';
6607 my $err_complete = 0;
6610 die "storage migration timed out\n" if $err_complete > 300;
6612 my $stats = mon_cmd
($vmid, "query-block-jobs");
6614 my $running_mirror_jobs = {};
6615 foreach my $stat (@$stats) {
6616 next if $stat->{type
} ne 'mirror';
6617 $running_mirror_jobs->{$stat->{device
}} = $stat;
6620 my $readycounter = 0;
6622 foreach my $job (keys %$jobs) {
6624 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6625 print "$job : finished\n";
6626 delete $jobs->{$job};
6630 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6632 my $busy = $running_mirror_jobs->{$job}->{busy
};
6633 my $ready = $running_mirror_jobs->{$job}->{ready
};
6634 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6635 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6636 my $remaining = $total - $transferred;
6637 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6639 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6642 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6645 last if scalar(keys %$jobs) == 0;
6647 if ($readycounter == scalar(keys %$jobs)) {
6648 print "all mirroring jobs are ready \n";
6649 last if $completion eq 'skip'; #do the complete later
6651 if ($vmiddst && $vmiddst != $vmid) {
6652 my $agent_running = $qga && qga_check_running
($vmid);
6653 if ($agent_running) {
6654 print "freeze filesystem\n";
6655 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6657 print "suspend vm\n";
6658 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6661 # if we clone a disk for a new target vm, we don't switch the disk
6662 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6664 if ($agent_running) {
6665 print "unfreeze filesystem\n";
6666 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6668 print "resume vm\n";
6669 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6675 foreach my $job (keys %$jobs) {
6676 # try to switch the disk if source and destination are on the same guest
6677 print "$job: Completing block job...\n";
6680 if ($completion eq 'complete') {
6681 $op = 'block-job-complete';
6682 } elsif ($completion eq 'cancel') {
6683 $op = 'block-job-cancel';
6685 die "invalid completion value: $completion\n";
6687 eval { mon_cmd
($vmid, $op, device
=> $job) };
6688 if ($@ =~ m/cannot be completed/) {
6689 print "$job: Block job cannot be completed, try again.\n";
6692 print "$job: Completed successfully.\n";
6693 $jobs->{$job}->{complete
} = 1;
6704 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6705 die "mirroring error: $err";
6710 sub qemu_blockjobs_cancel
{
6711 my ($vmid, $jobs) = @_;
6713 foreach my $job (keys %$jobs) {
6714 print "$job: Cancelling block job\n";
6715 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6716 $jobs->{$job}->{cancel
} = 1;
6720 my $stats = mon_cmd
($vmid, "query-block-jobs");
6722 my $running_jobs = {};
6723 foreach my $stat (@$stats) {
6724 $running_jobs->{$stat->{device
}} = $stat;
6727 foreach my $job (keys %$jobs) {
6729 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6730 print "$job: Done.\n";
6731 delete $jobs->{$job};
6735 last if scalar(keys %$jobs) == 0;
6742 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6743 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
6748 print "create linked clone of drive $drivename ($drive->{file})\n";
6749 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6750 push @$newvollist, $newvolid;
6753 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6754 $storeid = $storage if $storage;
6756 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6757 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6759 print "create full clone of drive $drivename ($drive->{file})\n";
6761 if (drive_is_cloudinit
($drive)) {
6762 $name = "vm-$newvmid-cloudinit";
6763 $name .= ".$dst_format" if $dst_format ne 'raw';
6765 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
6766 } elsif ($drivename eq 'efidisk0') {
6767 $size = get_efivars_size
($conf);
6769 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6770 push @$newvollist, $newvolid;
6772 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6774 if (drive_is_cloudinit
($drive)) {
6778 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6779 if (!$running || $snapname) {
6780 # TODO: handle bwlimits
6781 if ($drivename eq 'efidisk0') {
6782 # the relevant data on the efidisk may be smaller than the source
6783 # e.g. on RBD/ZFS, so we use dd to copy only the amount
6784 # that is given by the OVMF_VARS.fd
6785 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
});
6786 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
6787 run_command
(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size", "if=$src_path", "of=$dst_path"]);
6789 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6793 my $kvmver = get_running_qemu_version
($vmid);
6794 if (!min_version
($kvmver, 2, 7)) {
6795 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6796 if $drive->{iothread
};
6799 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $completion, $qga, $bwlimit);
6804 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6807 $disk->{format
} = undef;
6808 $disk->{file
} = $newvolid;
6809 $disk->{size
} = $size;
6814 sub get_running_qemu_version
{
6816 my $res = mon_cmd
($vmid, "query-version");
6817 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6820 sub qemu_use_old_bios_files
{
6821 my ($machine_type) = @_;
6823 return if !$machine_type;
6825 my $use_old_bios_files = undef;
6827 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6829 $use_old_bios_files = 1;
6831 my $version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, kvm_user_version
());
6832 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6833 # load new efi bios files on migration. So this hack is required to allow
6834 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6835 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6836 $use_old_bios_files = !min_version
($version, 2, 4);
6839 return ($use_old_bios_files, $machine_type);
6842 sub get_efivars_size
{
6844 my $arch = get_vm_arch
($conf);
6845 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6846 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
6847 return -s
$ovmf_vars;
6850 sub update_efidisk_size
{
6853 return if !defined($conf->{efidisk0
});
6855 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
6856 $disk->{size
} = get_efivars_size
($conf);
6857 $conf->{efidisk0
} = print_drive
($disk);
6862 sub create_efidisk
($$$$$) {
6863 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6865 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6866 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6868 my $vars_size_b = -s
$ovmf_vars;
6869 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
6870 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6871 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6873 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
6874 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
6876 return ($volid, $size/1024);
6879 sub vm_iothreads_list
{
6882 my $res = mon_cmd
($vmid, 'query-iothreads');
6885 foreach my $iothread (@$res) {
6886 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6893 my ($conf, $drive) = @_;
6897 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6899 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6905 my $controller = int($drive->{index} / $maxdev);
6906 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6908 return ($maxdev, $controller, $controller_prefix);
6911 sub windows_version
{
6914 return 0 if !$ostype;
6918 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6920 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6922 } elsif ($ostype =~ m/^win(\d+)$/) {
6929 sub resolve_dst_disk_format
{
6930 my ($storecfg, $storeid, $src_volname, $format) = @_;
6931 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6934 # if no target format is specified, use the source disk format as hint
6936 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6937 $format = qemu_img_format
($scfg, $src_volname);
6943 # test if requested format is supported - else use default
6944 my $supported = grep { $_ eq $format } @$validFormats;
6945 $format = $defFormat if !$supported;
6949 # NOTE: if this logic changes, please update docs & possibly gui logic
6950 sub find_vmstate_storage
{
6951 my ($conf, $storecfg) = @_;
6953 # first, return storage from conf if set
6954 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
6956 my ($target, $shared, $local);
6958 foreach_storage_used_by_vm
($conf, sub {
6960 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
6961 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
6962 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
6965 # second, use shared storage where VM has at least one disk
6966 # third, use local storage where VM has at least one disk
6967 # fall back to local storage
6968 $target = $shared // $local // 'local';
6974 my ($uuid, $uuid_str);
6975 UUID
::generate
($uuid);
6976 UUID
::unparse
($uuid, $uuid_str);
6980 sub generate_smbios1_uuid
{
6981 return "uuid=".generate_uuid
();
6987 mon_cmd
($vmid, 'nbd-server-stop');
6990 sub create_reboot_request
{
6992 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
6993 or die "failed to create reboot trigger file: $!\n";
6997 sub clear_reboot_request
{
6999 my $path = "/run/qemu-server/$vmid.reboot";
7002 $res = unlink($path);
7003 die "could not remove reboot request for $vmid: $!"
7004 if !$res && $! != POSIX
::ENOENT
;
7009 # bash completion helper
7011 sub complete_backup_archives
{
7012 my ($cmdname, $pname, $cvalue) = @_;
7014 my $cfg = PVE
::Storage
::config
();
7018 if ($cvalue =~ m/^([^:]+):/) {
7022 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7025 foreach my $id (keys %$data) {
7026 foreach my $item (@{$data->{$id}}) {
7027 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7028 push @$res, $item->{volid
} if defined($item->{volid
});
7035 my $complete_vmid_full = sub {
7038 my $idlist = vmstatus
();
7042 foreach my $id (keys %$idlist) {
7043 my $d = $idlist->{$id};
7044 if (defined($running)) {
7045 next if $d->{template
};
7046 next if $running && $d->{status
} ne 'running';
7047 next if !$running && $d->{status
} eq 'running';
7056 return &$complete_vmid_full();
7059 sub complete_vmid_stopped
{
7060 return &$complete_vmid_full(0);
7063 sub complete_vmid_running
{
7064 return &$complete_vmid_full(1);
7067 sub complete_storage
{
7069 my $cfg = PVE
::Storage
::config
();
7070 my $ids = $cfg->{ids
};
7073 foreach my $sid (keys %$ids) {
7074 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7075 next if !$ids->{$sid}->{content
}->{images
};
7082 sub complete_migration_storage
{
7083 my ($cmd, $param, $current_value, $all_args) = @_;
7085 my $targetnode = @$all_args[1];
7087 my $cfg = PVE
::Storage
::config
();
7088 my $ids = $cfg->{ids
};
7091 foreach my $sid (keys %$ids) {
7092 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
7093 next if !$ids->{$sid}->{content
}->{images
};