Fix #1924: add snapshot parameter
[qemu-server.git] / PVE / QemuServer.pm
1 package PVE::QemuServer;
2
3 use strict;
4 use warnings;
5 use POSIX;
6 use IO::Handle;
7 use IO::Select;
8 use IO::File;
9 use IO::Dir;
10 use IO::Socket::UNIX;
11 use File::Basename;
12 use File::Path;
13 use File::stat;
14 use Getopt::Long;
15 use Digest::SHA;
16 use Fcntl ':flock';
17 use Cwd 'abs_path';
18 use IPC::Open3;
19 use JSON;
20 use Fcntl;
21 use PVE::SafeSyslog;
22 use Storable qw(dclone);
23 use PVE::Exception qw(raise raise_param_exc);
24 use PVE::Storage;
25 use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
26 use PVE::JSONSchema qw(get_standard_option);
27 use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
28 use PVE::INotify;
29 use PVE::ProcFSTools;
30 use PVE::QemuConfig;
31 use PVE::QMPClient;
32 use PVE::RPCEnvironment;
33 use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr);
34 use PVE::QemuServer::Memory;
35 use PVE::QemuServer::USB qw(parse_usb_device);
36 use PVE::QemuServer::Cloudinit;
37 use PVE::SysFSTools;
38 use PVE::Systemd;
39 use Time::HiRes qw(gettimeofday);
40 use File::Copy qw(copy);
41 use URI::Escape;
42
43 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
44 my $OVMF = {
45     x86_64 => [
46         "$EDK2_FW_BASE/OVMF_CODE.fd",
47         "$EDK2_FW_BASE/OVMF_VARS.fd"
48     ],
49     aarch64 => [
50         "$EDK2_FW_BASE/AAVMF_CODE.fd",
51         "$EDK2_FW_BASE/AAVMF_VARS.fd"
52     ],
53 };
54
55 my $qemu_snap_storage = {rbd => 1, sheepdog => 1};
56
57 my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
58
59 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
60
61 # Note about locking: we use flock on the config file protect
62 # against concurent actions.
63 # Aditionaly, we have a 'lock' setting in the config file. This
64 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
65 # allowed when such lock is set. But you can ignore this kind of
66 # lock with the --skiplock flag.
67
68 cfs_register_file('/qemu-server/',
69                   \&parse_vm_config,
70                   \&write_vm_config);
71
72 PVE::JSONSchema::register_standard_option('pve-qm-stateuri', {
73     description => "Some command save/restore state from this location.",
74     type => 'string',
75     maxLength => 128,
76     optional => 1,
77 });
78
79 PVE::JSONSchema::register_standard_option('pve-snapshot-name', {
80     description => "The name of the snapshot.",
81     type => 'string', format => 'pve-configid',
82     maxLength => 40,
83 });
84
85 PVE::JSONSchema::register_standard_option('pve-qm-image-format', {
86     type => 'string',
87     enum => [qw(raw cow qcow qed qcow2 vmdk cloop)],
88     description => "The drive's backing file's data format.",
89     optional => 1,
90 });
91
92 PVE::JSONSchema::register_standard_option('pve-qemu-machine', {
93         description => "Specifies the Qemu machine type.",
94         type => 'string',
95         pattern => '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
96         maxLength => 40,
97         optional => 1,
98 });
99
100 #no warnings 'redefine';
101
102 sub cgroups_write {
103    my ($controller, $vmid, $option, $value) = @_;
104
105    my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
106    PVE::ProcFSTools::write_proc_entry($path, $value);
107
108 }
109
110 my $nodename = PVE::INotify::nodename();
111
112 mkdir "/etc/pve/nodes/$nodename";
113 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
114 mkdir $confdir;
115
116 my $var_run_tmpdir = "/var/run/qemu-server";
117 mkdir $var_run_tmpdir;
118
119 my $lock_dir = "/var/lock/qemu-server";
120 mkdir $lock_dir;
121
122 my $cpu_vendor_list = {
123     # Intel CPUs
124     486 => 'GenuineIntel',
125     pentium => 'GenuineIntel',
126     pentium2  => 'GenuineIntel',
127     pentium3  => 'GenuineIntel',
128     coreduo => 'GenuineIntel',
129     core2duo => 'GenuineIntel',
130     Conroe  => 'GenuineIntel',
131     Penryn  => 'GenuineIntel',
132     Nehalem  => 'GenuineIntel',
133     'Nehalem-IBRS'  => 'GenuineIntel',
134     Westmere => 'GenuineIntel',
135     'Westmere-IBRS' => 'GenuineIntel',
136     SandyBridge => 'GenuineIntel',
137     'SandyBridge-IBRS' => 'GenuineIntel',
138     IvyBridge => 'GenuineIntel',
139     'IvyBridge-IBRS' => 'GenuineIntel',
140     Haswell => 'GenuineIntel',
141     'Haswell-IBRS' => 'GenuineIntel',
142     'Haswell-noTSX' => 'GenuineIntel',
143     'Haswell-noTSX-IBRS' => 'GenuineIntel',
144     Broadwell => 'GenuineIntel',
145     'Broadwell-IBRS' => 'GenuineIntel',
146     'Broadwell-noTSX' => 'GenuineIntel',
147     'Broadwell-noTSX-IBRS' => 'GenuineIntel',
148     'Skylake-Client' => 'GenuineIntel',
149     'Skylake-Client-IBRS' => 'GenuineIntel',
150     'Skylake-Server' => 'GenuineIntel',
151     'Skylake-Server-IBRS' => 'GenuineIntel',
152
153     # AMD CPUs
154     athlon => 'AuthenticAMD',
155     phenom  => 'AuthenticAMD',
156     Opteron_G1  => 'AuthenticAMD',
157     Opteron_G2  => 'AuthenticAMD',
158     Opteron_G3  => 'AuthenticAMD',
159     Opteron_G4  => 'AuthenticAMD',
160     Opteron_G5  => 'AuthenticAMD',
161     EPYC => 'AuthenticAMD',
162     'EPYC-IBPB' => 'AuthenticAMD',
163
164     # generic types, use vendor from host node
165     host => 'default',
166     kvm32 => 'default',
167     kvm64 => 'default',
168     qemu32 => 'default',
169     qemu64 => 'default',
170     max => 'default',
171 };
172
173 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
174
175 my $cpu_fmt = {
176     cputype => {
177         description => "Emulated CPU type.",
178         type => 'string',
179         enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
180         default => 'kvm64',
181         default_key => 1,
182     },
183     hidden => {
184         description => "Do not identify as a KVM virtual machine.",
185         type => 'boolean',
186         optional => 1,
187         default => 0
188     },
189     'hv-vendor-id' => {
190         type => 'string',
191         pattern => qr/[a-zA-Z0-9]{1,12}/,
192         format_description => 'vendor-id',
193         description => 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.',
194         optional => 1,
195     },
196     flags => {
197         description => "List of additional CPU flags separated by ';'."
198                      . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
199                      . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
200         format_description => '+FLAG[;-FLAG...]',
201         type => 'string',
202         pattern => qr/$cpu_flag(;$cpu_flag)*/,
203         optional => 1,
204     },
205 };
206
207 my $watchdog_fmt = {
208     model => {
209         default_key => 1,
210         type => 'string',
211         enum => [qw(i6300esb ib700)],
212         description => "Watchdog type to emulate.",
213         default => 'i6300esb',
214         optional => 1,
215     },
216     action => {
217         type => 'string',
218         enum => [qw(reset shutdown poweroff pause debug none)],
219         description => "The action to perform if after activation the guest fails to poll the watchdog in time.",
220         optional => 1,
221     },
222 };
223 PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
224
225 my $agent_fmt = {
226     enabled => {
227         description => "Enable/disable Qemu GuestAgent.",
228         type => 'boolean',
229         default => 0,
230         default_key => 1,
231     },
232     fstrim_cloned_disks => {
233         description => "Run fstrim after cloning/moving a disk.",
234         type => 'boolean',
235         optional => 1,
236         default => 0
237     },
238 };
239
240 my $vga_fmt = {
241     type => {
242         description => "Select the VGA type.",
243         type => 'string',
244         default => 'std',
245         optional => 1,
246         default_key => 1,
247         enum => [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
248     },
249     memory => {
250         description => "Sets the VGA memory (in MiB). Has no effect with serial display.",
251         type => 'integer',
252         optional => 1,
253         minimum => 4,
254         maximum => 512,
255     },
256 };
257
258 my $confdesc = {
259     onboot => {
260         optional => 1,
261         type => 'boolean',
262         description => "Specifies whether a VM will be started during system bootup.",
263         default => 0,
264     },
265     autostart => {
266         optional => 1,
267         type => 'boolean',
268         description => "Automatic restart after crash (currently ignored).",
269         default => 0,
270     },
271     hotplug => {
272         optional => 1,
273         type => 'string', format => 'pve-hotplug-features',
274         description => "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
275         default => 'network,disk,usb',
276     },
277     reboot => {
278         optional => 1,
279         type => 'boolean',
280         description => "Allow reboot. If set to '0' the VM exit on reboot.",
281         default => 1,
282     },
283     lock => {
284         optional => 1,
285         type => 'string',
286         description => "Lock/unlock the VM.",
287         enum => [qw(backup clone create migrate rollback snapshot snapshot-delete)],
288     },
289     cpulimit => {
290         optional => 1,
291         type => 'number',
292         description => "Limit of CPU usage.",
293         verbose_description => "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
294         minimum => 0,
295         maximum => 128,
296         default => 0,
297     },
298     cpuunits => {
299         optional => 1,
300         type => 'integer',
301         description => "CPU weight for a VM.",
302         verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
303         minimum => 2,
304         maximum => 262144,
305         default => 1024,
306     },
307     memory => {
308         optional => 1,
309         type => 'integer',
310         description => "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
311         minimum => 16,
312         default => 512,
313     },
314     balloon => {
315         optional => 1,
316         type => 'integer',
317         description => "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
318         minimum => 0,
319     },
320     shares => {
321         optional => 1,
322         type => 'integer',
323         description => "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
324         minimum => 0,
325         maximum => 50000,
326         default => 1000,
327     },
328     keyboard => {
329         optional => 1,
330         type => 'string',
331         description => "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
332                        "It should not be necessary to set it.",
333         enum => PVE::Tools::kvmkeymaplist(),
334         default => undef,
335     },
336     name => {
337         optional => 1,
338         type => 'string', format => 'dns-name',
339         description => "Set a name for the VM. Only used on the configuration web interface.",
340     },
341     scsihw => {
342         optional => 1,
343         type => 'string',
344         description => "SCSI controller model",
345         enum => [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
346         default => 'lsi',
347     },
348     description => {
349         optional => 1,
350         type => 'string',
351         description => "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
352     },
353     ostype => {
354         optional => 1,
355         type => 'string',
356         enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
357         description => "Specify guest operating system.",
358         verbose_description => <<EODESC,
359 Specify guest operating system. This is used to enable special
360 optimization/features for specific operating systems:
361
362 [horizontal]
363 other;; unspecified OS
364 wxp;; Microsoft Windows XP
365 w2k;; Microsoft Windows 2000
366 w2k3;; Microsoft Windows 2003
367 w2k8;; Microsoft Windows 2008
368 wvista;; Microsoft Windows Vista
369 win7;; Microsoft Windows 7
370 win8;; Microsoft Windows 8/2012/2012r2
371 win10;; Microsoft Windows 10/2016
372 l24;; Linux 2.4 Kernel
373 l26;; Linux 2.6/3.X Kernel
374 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
375 EODESC
376     },
377     boot => {
378         optional => 1,
379         type => 'string',
380         description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
381         pattern => '[acdn]{1,4}',
382         default => 'cdn',
383     },
384     bootdisk => {
385         optional => 1,
386         type => 'string', format => 'pve-qm-bootdisk',
387         description => "Enable booting from specified disk.",
388         pattern => '(ide|sata|scsi|virtio)\d+',
389     },
390     smp => {
391         optional => 1,
392         type => 'integer',
393         description => "The number of CPUs. Please use option -sockets instead.",
394         minimum => 1,
395         default => 1,
396     },
397     sockets => {
398         optional => 1,
399         type => 'integer',
400         description => "The number of CPU sockets.",
401         minimum => 1,
402         default => 1,
403     },
404     cores => {
405         optional => 1,
406         type => 'integer',
407         description => "The number of cores per socket.",
408         minimum => 1,
409         default => 1,
410     },
411     numa => {
412         optional => 1,
413         type => 'boolean',
414         description => "Enable/disable NUMA.",
415         default => 0,
416     },
417     hugepages => {
418         optional => 1,
419         type => 'string',
420         description => "Enable/disable hugepages memory.",
421         enum => [qw(any 2 1024)],
422     },
423     vcpus => {
424         optional => 1,
425         type => 'integer',
426         description => "Number of hotplugged vcpus.",
427         minimum => 1,
428         default => 0,
429     },
430     acpi => {
431         optional => 1,
432         type => 'boolean',
433         description => "Enable/disable ACPI.",
434         default => 1,
435     },
436     agent => {
437         optional => 1,
438         description => "Enable/disable Qemu GuestAgent and its properties.",
439         type => 'string',
440         format => $agent_fmt,
441     },
442     kvm => {
443         optional => 1,
444         type => 'boolean',
445         description => "Enable/disable KVM hardware virtualization.",
446         default => 1,
447     },
448     tdf => {
449         optional => 1,
450         type => 'boolean',
451         description => "Enable/disable time drift fix.",
452         default => 0,
453     },
454     localtime => {
455         optional => 1,
456         type => 'boolean',
457         description => "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
458     },
459     freeze => {
460         optional => 1,
461         type => 'boolean',
462         description => "Freeze CPU at startup (use 'c' monitor command to start execution).",
463     },
464     vga => {
465         optional => 1,
466         type => 'string', format => $vga_fmt,
467         description => "Configure the VGA hardware.",
468         verbose_description => "Configure the VGA Hardware. If you want to use ".
469             "high resolution modes (>= 1280x1024x16) you may need to increase " .
470             "the vga memory option. Since QEMU 2.9 the default VGA display type " .
471             "is 'std' for all OS types besides some Windows versions (XP and " .
472             "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
473             "display server. For win* OS you can select how many independent " .
474             "displays you want, Linux guests can add displays them self.\n".
475             "You can also run without any graphic card, using a serial device as terminal.",
476     },
477     watchdog => {
478         optional => 1,
479         type => 'string', format => 'pve-qm-watchdog',
480         description => "Create a virtual hardware watchdog device.",
481         verbose_description => "Create a virtual hardware watchdog device. Once enabled" .
482             " (by a guest action), the watchdog must be periodically polled " .
483             "by an agent inside the guest or else the watchdog will reset " .
484             "the guest (or execute the respective action specified)",
485     },
486     startdate => {
487         optional => 1,
488         type => 'string',
489         typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
490         description => "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
491         pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
492         default => 'now',
493     },
494     startup =>  get_standard_option('pve-startup-order'),
495     template => {
496         optional => 1,
497         type => 'boolean',
498         description => "Enable/disable Template.",
499         default => 0,
500     },
501     args => {
502         optional => 1,
503         type => 'string',
504         description => "Arbitrary arguments passed to kvm.",
505         verbose_description => <<EODESCR,
506 Arbitrary arguments passed to kvm, for example:
507
508 args: -no-reboot -no-hpet
509
510 NOTE: this option is for experts only.
511 EODESCR
512     },
513     tablet => {
514         optional => 1,
515         type => 'boolean',
516         default => 1,
517         description => "Enable/disable the USB tablet device.",
518         verbose_description => "Enable/disable the USB tablet device. This device is " .
519             "usually needed to allow absolute mouse positioning with VNC. " .
520             "Else the mouse runs out of sync with normal VNC clients. " .
521             "If you're running lots of console-only guests on one host, " .
522             "you may consider disabling this to save some context switches. " .
523             "This is turned off by default if you use spice (-vga=qxl).",
524     },
525     migrate_speed => {
526         optional => 1,
527         type => 'integer',
528         description => "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
529         minimum => 0,
530         default => 0,
531     },
532     migrate_downtime => {
533         optional => 1,
534         type => 'number',
535         description => "Set maximum tolerated downtime (in seconds) for migrations.",
536         minimum => 0,
537         default => 0.1,
538     },
539     cdrom => {
540         optional => 1,
541         type => 'string', format => 'pve-qm-ide',
542         typetext => '<volume>',
543         description => "This is an alias for option -ide2",
544     },
545     cpu => {
546         optional => 1,
547         description => "Emulated CPU type.",
548         type => 'string',
549         format => $cpu_fmt,
550     },
551     parent => get_standard_option('pve-snapshot-name', {
552         optional => 1,
553         description => "Parent snapshot name. This is used internally, and should not be modified.",
554     }),
555     snaptime => {
556         optional => 1,
557         description => "Timestamp for snapshots.",
558         type => 'integer',
559         minimum => 0,
560     },
561     vmstate => {
562         optional => 1,
563         type => 'string', format => 'pve-volume-id',
564         description => "Reference to a volume which stores the VM state. This is used internally for snapshots.",
565     },
566     vmstatestorage => get_standard_option('pve-storage-id', {
567         description => "Default storage for VM state volumes/files.",
568         optional => 1,
569     }),
570     runningmachine => get_standard_option('pve-qemu-machine', {
571         description => "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
572     }),
573     machine => get_standard_option('pve-qemu-machine'),
574     arch => {
575         description => "Virtual processor architecture. Defaults to the host.",
576         optional => 1,
577         type => 'string',
578         enum => [qw(x86_64 aarch64)],
579     },
580     smbios1 => {
581         description => "Specify SMBIOS type 1 fields.",
582         type => 'string', format => 'pve-qm-smbios1',
583         maxLength => 256,
584         optional => 1,
585     },
586     protection => {
587         optional => 1,
588         type => 'boolean',
589         description => "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
590         default => 0,
591     },
592     bios => {
593         optional => 1,
594         type => 'string',
595         enum => [ qw(seabios ovmf) ],
596         description => "Select BIOS implementation.",
597         default => 'seabios',
598     },
599     vmgenid => {
600         type => 'string',
601         pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
602         format_description => 'UUID',
603         description => "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
604         verbose_description => "The VM generation ID (vmgenid) device exposes a".
605             " 128-bit integer value identifier to the guest OS. This allows to".
606             " notify the guest operating system when the virtual machine is".
607             " executed with a different configuration (e.g. snapshot execution".
608             " or creation from a template). The guest operating system notices".
609             " the change, and is then able to react as appropriate by marking".
610             " its copies of distributed databases as dirty, re-initializing its".
611             " random number generator, etc.\n".
612             "Note that auto-creation only works when done throug API/CLI create".
613             " or update methods, but not when manually editing the config file.",
614         default => "1 (autogenerated)",
615         optional => 1,
616     },
617 };
618
619 my $confdesc_cloudinit = {
620     citype => {
621         optional => 1,
622         type => 'string',
623         description => 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
624         enum => ['configdrive2', 'nocloud'],
625     },
626     ciuser => {
627         optional => 1,
628         type => 'string',
629         description => "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
630     },
631     cipassword => {
632         optional => 1,
633         type => 'string',
634         description => 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
635     },
636     searchdomain => {
637         optional => 1,
638         type => 'string',
639         description => "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
640     },
641     nameserver => {
642         optional => 1,
643         type => 'string', format => 'address-list',
644         description => "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
645     },
646     sshkeys => {
647         optional => 1,
648         type => 'string',
649         format => 'urlencoded',
650         description => "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
651     },
652 };
653
654 # what about other qemu settings ?
655 #cpu => 'string',
656 #machine => 'string',
657 #fda => 'file',
658 #fdb => 'file',
659 #mtdblock => 'file',
660 #sd => 'file',
661 #pflash => 'file',
662 #snapshot => 'bool',
663 #bootp => 'file',
664 ##tftp => 'dir',
665 ##smb => 'dir',
666 #kernel => 'file',
667 #append => 'string',
668 #initrd => 'file',
669 ##soundhw => 'string',
670
671 while (my ($k, $v) = each %$confdesc) {
672     PVE::JSONSchema::register_standard_option("pve-qm-$k", $v);
673 }
674
675 my $MAX_IDE_DISKS = 4;
676 my $MAX_SCSI_DISKS = 14;
677 my $MAX_VIRTIO_DISKS = 16;
678 my $MAX_SATA_DISKS = 6;
679 my $MAX_USB_DEVICES = 5;
680 my $MAX_NETS = 32;
681 my $MAX_UNUSED_DISKS = 256;
682 my $MAX_HOSTPCI_DEVICES = 4;
683 my $MAX_SERIAL_PORTS = 4;
684 my $MAX_PARALLEL_PORTS = 3;
685 my $MAX_NUMA = 8;
686
687 my $numa_fmt = {
688     cpus => {
689         type => "string",
690         pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
691         description => "CPUs accessing this NUMA node.",
692         format_description => "id[-id];...",
693     },
694     memory => {
695         type => "number",
696         description => "Amount of memory this NUMA node provides.",
697         optional => 1,
698     },
699     hostnodes => {
700         type => "string",
701         pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
702         description => "Host NUMA nodes to use.",
703         format_description => "id[-id];...",
704         optional => 1,
705     },
706     policy => {
707         type => 'string',
708         enum => [qw(preferred bind interleave)],
709         description => "NUMA allocation policy.",
710         optional => 1,
711     },
712 };
713 PVE::JSONSchema::register_format('pve-qm-numanode', $numa_fmt);
714 my $numadesc = {
715     optional => 1,
716     type => 'string', format => $numa_fmt,
717     description => "NUMA topology.",
718 };
719 PVE::JSONSchema::register_standard_option("pve-qm-numanode", $numadesc);
720
721 for (my $i = 0; $i < $MAX_NUMA; $i++)  {
722     $confdesc->{"numa$i"} = $numadesc;
723 }
724
725 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000',  'pcnet',  'virtio',
726                       'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
727                       'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
728 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
729
730 my $net_fmt_bridge_descr = <<__EOD__;
731 Bridge to attach the network device to. The Proxmox VE standard bridge
732 is called 'vmbr0'.
733
734 If you do not specify a bridge, we create a kvm user (NATed) network
735 device, which provides DHCP and DNS services. The following addresses
736 are used:
737
738  10.0.2.2   Gateway
739  10.0.2.3   DNS Server
740  10.0.2.4   SMB Server
741
742 The DHCP server assign addresses to the guest starting from 10.0.2.15.
743 __EOD__
744
745 my $net_fmt = {
746     macaddr => {
747         type => 'string',
748         pattern => qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
749         description => "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
750         format_description => "XX:XX:XX:XX:XX:XX",
751         optional => 1,
752     },
753     model => {
754         type => 'string',
755         description => "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
756         enum => $nic_model_list,
757         default_key => 1,
758     },
759     (map { $_ => { keyAlias => 'model', alias => 'macaddr' }} @$nic_model_list),
760     bridge => {
761         type => 'string',
762         description => $net_fmt_bridge_descr,
763         format_description => 'bridge',
764         optional => 1,
765     },
766     queues => {
767         type => 'integer',
768         minimum => 0, maximum => 16,
769         description => 'Number of packet queues to be used on the device.',
770         optional => 1,
771     },
772     rate => {
773         type => 'number',
774         minimum => 0,
775         description => "Rate limit in mbps (megabytes per second) as floating point number.",
776         optional => 1,
777     },
778     tag => {
779         type => 'integer',
780         minimum => 1, maximum => 4094,
781         description => 'VLAN tag to apply to packets on this interface.',
782         optional => 1,
783     },
784     trunks => {
785         type => 'string',
786         pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
787         description => 'VLAN trunks to pass through this interface.',
788         format_description => 'vlanid[;vlanid...]',
789         optional => 1,
790     },
791     firewall => {
792         type => 'boolean',
793         description => 'Whether this interface should be protected by the firewall.',
794         optional => 1,
795     },
796     link_down => {
797         type => 'boolean',
798         description => 'Whether this interface should be disconnected (like pulling the plug).',
799         optional => 1,
800     },
801 };
802
803 my $netdesc = {
804     optional => 1,
805     type => 'string', format => $net_fmt,
806     description => "Specify network devices.",
807 };
808
809 PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
810
811 my $ipconfig_fmt = {
812     ip => {
813         type => 'string',
814         format => 'pve-ipv4-config',
815         format_description => 'IPv4Format/CIDR',
816         description => 'IPv4 address in CIDR format.',
817         optional => 1,
818         default => 'dhcp',
819     },
820     gw => {
821         type => 'string',
822         format => 'ipv4',
823         format_description => 'GatewayIPv4',
824         description => 'Default gateway for IPv4 traffic.',
825         optional => 1,
826         requires => 'ip',
827     },
828     ip6 => {
829         type => 'string',
830         format => 'pve-ipv6-config',
831         format_description => 'IPv6Format/CIDR',
832         description => 'IPv6 address in CIDR format.',
833         optional => 1,
834         default => 'dhcp',
835     },
836     gw6 => {
837         type => 'string',
838         format => 'ipv6',
839         format_description => 'GatewayIPv6',
840         description => 'Default gateway for IPv6 traffic.',
841         optional => 1,
842         requires => 'ip6',
843     },
844 };
845 PVE::JSONSchema::register_format('pve-qm-ipconfig', $ipconfig_fmt);
846 my $ipconfigdesc = {
847     optional => 1,
848     type => 'string', format => 'pve-qm-ipconfig',
849     description => <<'EODESCR',
850 cloud-init: Specify IP addresses and gateways for the corresponding interface.
851
852 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
853
854 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
855 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
856
857 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
858 EODESCR
859 };
860 PVE::JSONSchema::register_standard_option("pve-qm-ipconfig", $netdesc);
861
862 for (my $i = 0; $i < $MAX_NETS; $i++)  {
863     $confdesc->{"net$i"} = $netdesc;
864     $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
865 }
866
867 foreach my $key (keys %$confdesc_cloudinit) {
868     $confdesc->{$key} = $confdesc_cloudinit->{$key};
869 }
870
871 PVE::JSONSchema::register_format('pve-volume-id-or-qm-path', \&verify_volume_id_or_qm_path);
872 sub verify_volume_id_or_qm_path {
873     my ($volid, $noerr) = @_;
874
875     if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m|^/|) {
876         return $volid;
877     }
878
879     # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
880     $volid = eval { PVE::JSONSchema::check_format('pve-volume-id', $volid, '') };
881     if ($@) {
882         return undef if $noerr;
883         die $@;
884     }
885     return $volid;
886 }
887
888 my $drivename_hash;
889
890 my %drivedesc_base = (
891     volume => { alias => 'file' },
892     file => {
893         type => 'string',
894         format => 'pve-volume-id-or-qm-path',
895         default_key => 1,
896         format_description => 'volume',
897         description => "The drive's backing volume.",
898     },
899     media => {
900         type => 'string',
901         enum => [qw(cdrom disk)],
902         description => "The drive's media type.",
903         default => 'disk',
904         optional => 1
905     },
906     cyls => {
907         type => 'integer',
908         description => "Force the drive's physical geometry to have a specific cylinder count.",
909         optional => 1
910     },
911     heads => {
912         type => 'integer',
913         description => "Force the drive's physical geometry to have a specific head count.",
914         optional => 1
915     },
916     secs => {
917         type => 'integer',
918         description => "Force the drive's physical geometry to have a specific sector count.",
919         optional => 1
920     },
921     trans => {
922         type => 'string',
923         enum => [qw(none lba auto)],
924         description => "Force disk geometry bios translation mode.",
925         optional => 1,
926     },
927     snapshot => {
928         type => 'boolean',
929         description => "Controls qemu's snapshot mode feature."
930             . " If activated, changes made to the disk are temporary and will"
931             . " be discarded when the VM is shutdown.",
932         optional => 1,
933     },
934     cache => {
935         type => 'string',
936         enum => [qw(none writethrough writeback unsafe directsync)],
937         description => "The drive's cache mode",
938         optional => 1,
939     },
940     format => get_standard_option('pve-qm-image-format'),
941     size => {
942         type => 'string',
943         format => 'disk-size',
944         format_description => 'DiskSize',
945         description => "Disk size. This is purely informational and has no effect.",
946         optional => 1,
947     },
948     backup => {
949         type => 'boolean',
950         description => "Whether the drive should be included when making backups.",
951         optional => 1,
952     },
953     replicate => {
954         type => 'boolean',
955         description => 'Whether the drive should considered for replication jobs.',
956         optional => 1,
957         default => 1,
958     },
959     rerror => {
960         type => 'string',
961         enum => [qw(ignore report stop)],
962         description => 'Read error action.',
963         optional => 1,
964     },
965     werror => {
966         type => 'string',
967         enum => [qw(enospc ignore report stop)],
968         description => 'Write error action.',
969         optional => 1,
970     },
971     aio => {
972         type => 'string',
973         enum => [qw(native threads)],
974         description => 'AIO type to use.',
975         optional => 1,
976     },
977     discard => {
978         type => 'string',
979         enum => [qw(ignore on)],
980         description => 'Controls whether to pass discard/trim requests to the underlying storage.',
981         optional => 1,
982     },
983     detect_zeroes => {
984         type => 'boolean',
985         description => 'Controls whether to detect and try to optimize writes of zeroes.',
986         optional => 1,
987     },
988     serial => {
989         type => 'string',
990         format => 'urlencoded',
991         format_description => 'serial',
992         maxLength => 20*3, # *3 since it's %xx url enoded
993         description => "The drive's reported serial number, url-encoded, up to 20 bytes long.",
994         optional => 1,
995     },
996     shared => {
997         type => 'boolean',
998         description => 'Mark this locally-managed volume as available on all nodes',
999         verbose_description => "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
1000         optional => 1,
1001         default => 0,
1002     }
1003 );
1004
1005 my %iothread_fmt = ( iothread => {
1006         type => 'boolean',
1007         description => "Whether to use iothreads for this drive",
1008         optional => 1,
1009 });
1010
1011 my %model_fmt = (
1012     model => {
1013         type => 'string',
1014         format => 'urlencoded',
1015         format_description => 'model',
1016         maxLength => 40*3, # *3 since it's %xx url enoded
1017         description => "The drive's reported model name, url-encoded, up to 40 bytes long.",
1018         optional => 1,
1019     },
1020 );
1021
1022 my %queues_fmt = (
1023     queues => {
1024         type => 'integer',
1025         description => "Number of queues.",
1026         minimum => 2,
1027         optional => 1
1028     }
1029 );
1030
1031 my %scsiblock_fmt = (
1032     scsiblock => {
1033         type => 'boolean',
1034         description => "whether to use scsi-block for full passthrough of host block device\n\nWARNING: can lead to I/O errors in combination with low memory or high memory fragmentation on host",
1035         optional => 1,
1036         default => 0,
1037     },
1038 );
1039
1040 my %ssd_fmt = (
1041     ssd => {
1042         type => 'boolean',
1043         description => "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1044         optional => 1,
1045     },
1046 );
1047
1048 my $add_throttle_desc = sub {
1049     my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1050     my $d = {
1051         type => $type,
1052         format_description => $unit,
1053         description => "Maximum $what in $longunit.",
1054         optional => 1,
1055     };
1056     $d->{minimum} = $minimum if defined($minimum);
1057     $drivedesc_base{$key} = $d;
1058 };
1059 # throughput: (leaky bucket)
1060 $add_throttle_desc->('bps',     'integer', 'r/w speed',   'bps',  'bytes per second');
1061 $add_throttle_desc->('bps_rd',  'integer', 'read speed',  'bps',  'bytes per second');
1062 $add_throttle_desc->('bps_wr',  'integer', 'write speed', 'bps',  'bytes per second');
1063 $add_throttle_desc->('mbps',    'number',  'r/w speed',   'mbps', 'megabytes per second');
1064 $add_throttle_desc->('mbps_rd', 'number',  'read speed',  'mbps', 'megabytes per second');
1065 $add_throttle_desc->('mbps_wr', 'number',  'write speed', 'mbps', 'megabytes per second');
1066 $add_throttle_desc->('iops',    'integer', 'r/w I/O',     'iops', 'operations per second');
1067 $add_throttle_desc->('iops_rd', 'integer', 'read I/O',    'iops', 'operations per second');
1068 $add_throttle_desc->('iops_wr', 'integer', 'write I/O',   'iops', 'operations per second');
1069
1070 # pools: (pool of IO before throttling starts taking effect)
1071 $add_throttle_desc->('mbps_max',    'number',  'unthrottled r/w pool',       'mbps', 'megabytes per second');
1072 $add_throttle_desc->('mbps_rd_max', 'number',  'unthrottled read pool',      'mbps', 'megabytes per second');
1073 $add_throttle_desc->('mbps_wr_max', 'number',  'unthrottled write pool',     'mbps', 'megabytes per second');
1074 $add_throttle_desc->('iops_max',    'integer', 'unthrottled r/w I/O pool',   'iops', 'operations per second');
1075 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool',  'iops', 'operations per second');
1076 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1077
1078 # burst lengths
1079 $add_throttle_desc->('bps_max_length',     'integer', 'length of I/O bursts',       'seconds', 'seconds', 1);
1080 $add_throttle_desc->('bps_rd_max_length',  'integer', 'length of read I/O bursts',  'seconds', 'seconds', 1);
1081 $add_throttle_desc->('bps_wr_max_length',  'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1082 $add_throttle_desc->('iops_max_length',    'integer', 'length of I/O bursts',       'seconds', 'seconds', 1);
1083 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts',  'seconds', 'seconds', 1);
1084 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1085
1086 # legacy support
1087 $drivedesc_base{'bps_rd_length'} = { alias => 'bps_rd_max_length' };
1088 $drivedesc_base{'bps_wr_length'} = { alias => 'bps_wr_max_length' };
1089 $drivedesc_base{'iops_rd_length'} = { alias => 'iops_rd_max_length' };
1090 $drivedesc_base{'iops_wr_length'} = { alias => 'iops_wr_max_length' };
1091
1092 my $ide_fmt = {
1093     %drivedesc_base,
1094     %model_fmt,
1095     %ssd_fmt,
1096 };
1097 PVE::JSONSchema::register_format("pve-qm-ide", $ide_fmt);
1098
1099 my $idedesc = {
1100     optional => 1,
1101     type => 'string', format => $ide_fmt,
1102     description => "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1103 };
1104 PVE::JSONSchema::register_standard_option("pve-qm-ide", $idedesc);
1105
1106 my $scsi_fmt = {
1107     %drivedesc_base,
1108     %iothread_fmt,
1109     %queues_fmt,
1110     %scsiblock_fmt,
1111     %ssd_fmt,
1112 };
1113 my $scsidesc = {
1114     optional => 1,
1115     type => 'string', format => $scsi_fmt,
1116     description => "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1117 };
1118 PVE::JSONSchema::register_standard_option("pve-qm-scsi", $scsidesc);
1119
1120 my $sata_fmt = {
1121     %drivedesc_base,
1122     %ssd_fmt,
1123 };
1124 my $satadesc = {
1125     optional => 1,
1126     type => 'string', format => $sata_fmt,
1127     description => "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1128 };
1129 PVE::JSONSchema::register_standard_option("pve-qm-sata", $satadesc);
1130
1131 my $virtio_fmt = {
1132     %drivedesc_base,
1133     %iothread_fmt,
1134 };
1135 my $virtiodesc = {
1136     optional => 1,
1137     type => 'string', format => $virtio_fmt,
1138     description => "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1139 };
1140 PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc);
1141
1142 my $alldrive_fmt = {
1143     %drivedesc_base,
1144     %iothread_fmt,
1145     %model_fmt,
1146     %queues_fmt,
1147     %scsiblock_fmt,
1148     %ssd_fmt,
1149 };
1150
1151 my $efidisk_fmt = {
1152     volume => { alias => 'file' },
1153     file => {
1154         type => 'string',
1155         format => 'pve-volume-id-or-qm-path',
1156         default_key => 1,
1157         format_description => 'volume',
1158         description => "The drive's backing volume.",
1159     },
1160     format => get_standard_option('pve-qm-image-format'),
1161     size => {
1162         type => 'string',
1163         format => 'disk-size',
1164         format_description => 'DiskSize',
1165         description => "Disk size. This is purely informational and has no effect.",
1166         optional => 1,
1167     },
1168 };
1169
1170 my $efidisk_desc = {
1171     optional => 1,
1172     type => 'string', format => $efidisk_fmt,
1173     description => "Configure a Disk for storing EFI vars",
1174 };
1175
1176 PVE::JSONSchema::register_standard_option("pve-qm-efidisk", $efidisk_desc);
1177
1178 my $usb_fmt = {
1179     host => {
1180         default_key => 1,
1181         type => 'string', format => 'pve-qm-usb-device',
1182         format_description => 'HOSTUSBDEVICE|spice',
1183         description => <<EODESCR,
1184 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1185
1186  'bus-port(.port)*' (decimal numbers) or
1187  'vendor_id:product_id' (hexadeciaml numbers) or
1188  'spice'
1189
1190 You can use the 'lsusb -t' command to list existing usb devices.
1191
1192 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1193
1194 The value 'spice' can be used to add a usb redirection devices for spice.
1195 EODESCR
1196     },
1197     usb3 => {
1198         optional => 1,
1199         type => 'boolean',
1200         description => "Specifies whether if given host option is a USB3 device or port (this does currently not work reliably with spice redirection and is then ignored).",
1201         default => 0,
1202     },
1203 };
1204
1205 my $usbdesc = {
1206     optional => 1,
1207     type => 'string', format => $usb_fmt,
1208     description => "Configure an USB device (n is 0 to 4).",
1209 };
1210 PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
1211
1212 my $PCIRE = qr/[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1213 my $hostpci_fmt = {
1214     host => {
1215         default_key => 1,
1216         type => 'string',
1217         pattern => qr/$PCIRE(;$PCIRE)*/,
1218         format_description => 'HOSTPCIID[;HOSTPCIID2...]',
1219         description => <<EODESCR,
1220 Host PCI device pass through. The PCI ID of a host's PCI device or a list 
1221 of PCI virtual functions of the host. HOSTPCIID syntax is:
1222
1223 'bus:dev.func' (hexadecimal numbers)
1224
1225 You can us the 'lspci' command to list existing PCI devices.
1226 EODESCR
1227     },
1228     rombar => {
1229         type => 'boolean',
1230         description =>  "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1231         optional => 1,
1232         default => 1,
1233     },
1234     romfile => {
1235         type => 'string',
1236         pattern => '[^,;]+',
1237         format_description => 'string',
1238         description => "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1239         optional => 1,
1240     },
1241     pcie => {
1242         type => 'boolean',
1243         description =>  "Choose the PCI-express bus (needs the 'q35' machine model).",
1244         optional => 1,
1245         default => 0,
1246     },
1247     'x-vga' => {
1248         type => 'boolean',
1249         description =>  "Enable vfio-vga device support.",
1250         optional => 1,
1251         default => 0,
1252     },
1253     'mdev' => {
1254         type => 'string',
1255         format_description => 'string',
1256         pattern => '[^/\.:]+',
1257         optional => 1,
1258         description => <<EODESCR
1259 The type of mediated device to use.
1260 An instance of this type will be created on startup of the VM and
1261 will be cleaned up when the VM stops.
1262 EODESCR
1263     }
1264 };
1265 PVE::JSONSchema::register_format('pve-qm-hostpci', $hostpci_fmt);
1266
1267 my $hostpcidesc = {
1268         optional => 1,
1269         type => 'string', format => 'pve-qm-hostpci',
1270         description => "Map host PCI devices into guest.",
1271         verbose_description =>  <<EODESCR,
1272 Map host PCI devices into guest.
1273
1274 NOTE: This option allows direct access to host hardware. So it is no longer 
1275 possible to migrate such machines - use with special care.
1276
1277 CAUTION: Experimental! User reported problems with this option.
1278 EODESCR
1279 };
1280 PVE::JSONSchema::register_standard_option("pve-qm-hostpci", $hostpcidesc);
1281
1282 my $serialdesc = {
1283         optional => 1,
1284         type => 'string',
1285         pattern => '(/dev/.+|socket)',
1286         description =>  "Create a serial device inside the VM (n is 0 to 3)",
1287         verbose_description =>  <<EODESCR,
1288 Create a serial device inside the VM (n is 0 to 3), and pass through a
1289 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1290 host side (use 'qm terminal' to open a terminal connection).
1291
1292 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1293
1294 CAUTION: Experimental! User reported problems with this option.
1295 EODESCR
1296 };
1297
1298 my $paralleldesc= {
1299         optional => 1,
1300         type => 'string',
1301         pattern => '/dev/parport\d+|/dev/usb/lp\d+',
1302         description =>  "Map host parallel devices (n is 0 to 2).",
1303         verbose_description =>  <<EODESCR,
1304 Map host parallel devices (n is 0 to 2).
1305
1306 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1307
1308 CAUTION: Experimental! User reported problems with this option.
1309 EODESCR
1310 };
1311
1312 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++)  {
1313     $confdesc->{"parallel$i"} = $paralleldesc;
1314 }
1315
1316 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++)  {
1317     $confdesc->{"serial$i"} = $serialdesc;
1318 }
1319
1320 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
1321     $confdesc->{"hostpci$i"} = $hostpcidesc;
1322 }
1323
1324 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++)  {
1325     $drivename_hash->{"ide$i"} = 1;
1326     $confdesc->{"ide$i"} = $idedesc;
1327 }
1328
1329 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++)  {
1330     $drivename_hash->{"sata$i"} = 1;
1331     $confdesc->{"sata$i"} = $satadesc;
1332 }
1333
1334 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++)  {
1335     $drivename_hash->{"scsi$i"} = 1;
1336     $confdesc->{"scsi$i"} = $scsidesc ;
1337 }
1338
1339 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++)  {
1340     $drivename_hash->{"virtio$i"} = 1;
1341     $confdesc->{"virtio$i"} = $virtiodesc;
1342 }
1343
1344 $drivename_hash->{efidisk0} = 1;
1345 $confdesc->{efidisk0} = $efidisk_desc;
1346
1347 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++)  {
1348     $confdesc->{"usb$i"} = $usbdesc;
1349 }
1350
1351 my $unuseddesc = {
1352     optional => 1,
1353     type => 'string', format => 'pve-volume-id',
1354     description => "Reference to unused volumes. This is used internally, and should not be modified manually.",
1355 };
1356
1357 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++)  {
1358     $confdesc->{"unused$i"} = $unuseddesc;
1359 }
1360
1361 my $kvm_api_version = 0;
1362
1363 sub kvm_version {
1364     return $kvm_api_version if $kvm_api_version;
1365
1366     open my $fh, '<', '/dev/kvm'
1367         or return undef;
1368
1369     # 0xae00 => KVM_GET_API_VERSION
1370     $kvm_api_version = ioctl($fh, 0xae00, 0);
1371
1372     return $kvm_api_version;
1373 }
1374
1375 my $kvm_user_version;
1376
1377 sub kvm_user_version {
1378
1379     return $kvm_user_version if $kvm_user_version;
1380
1381     $kvm_user_version = 'unknown';
1382
1383     my $code = sub {
1384         my $line = shift;
1385         if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1386             $kvm_user_version = $2;
1387         }
1388     };
1389
1390     eval { run_command("kvm -version", outfunc => $code); };
1391     warn $@ if $@;
1392
1393     return $kvm_user_version;
1394
1395 }
1396
1397 sub kernel_has_vhost_net {
1398     return -c '/dev/vhost-net';
1399 }
1400
1401 sub valid_drive_names {
1402     # order is important - used to autoselect boot disk
1403     return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1404             (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1405             (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1406             (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1407             'efidisk0');
1408 }
1409
1410 sub is_valid_drivename {
1411     my $dev = shift;
1412
1413     return defined($drivename_hash->{$dev});
1414 }
1415
1416 sub option_exists {
1417     my $key = shift;
1418     return defined($confdesc->{$key});
1419 }
1420
1421 sub nic_models {
1422     return $nic_model_list;
1423 }
1424
1425 sub os_list_description {
1426
1427     return {
1428         other => 'Other',
1429         wxp => 'Windows XP',
1430         w2k => 'Windows 2000',
1431         w2k3 =>, 'Windows 2003',
1432         w2k8 => 'Windows 2008',
1433         wvista => 'Windows Vista',
1434         win7 => 'Windows 7',
1435         win8 => 'Windows 8/2012',
1436         win10 => 'Windows 10/2016',
1437         l24 => 'Linux 2.4',
1438         l26 => 'Linux 2.6',
1439     };
1440 }
1441
1442 my $cdrom_path;
1443
1444 sub get_cdrom_path {
1445
1446     return  $cdrom_path if $cdrom_path;
1447
1448     return $cdrom_path = "/dev/cdrom" if -l "/dev/cdrom";
1449     return $cdrom_path = "/dev/cdrom1" if -l "/dev/cdrom1";
1450     return $cdrom_path = "/dev/cdrom2" if -l "/dev/cdrom2";
1451 }
1452
1453 sub get_iso_path {
1454     my ($storecfg, $vmid, $cdrom) = @_;
1455
1456     if ($cdrom eq 'cdrom') {
1457         return get_cdrom_path();
1458     } elsif ($cdrom eq 'none') {
1459         return '';
1460     } elsif ($cdrom =~ m|^/|) {
1461         return $cdrom;
1462     } else {
1463         return PVE::Storage::path($storecfg, $cdrom);
1464     }
1465 }
1466
1467 # try to convert old style file names to volume IDs
1468 sub filename_to_volume_id {
1469     my ($vmid, $file, $media) = @_;
1470
1471      if (!($file eq 'none' || $file eq 'cdrom' ||
1472           $file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1473
1474         return undef if $file =~ m|/|;
1475
1476         if ($media && $media eq 'cdrom') {
1477             $file = "local:iso/$file";
1478         } else {
1479             $file = "local:$vmid/$file";
1480         }
1481     }
1482
1483     return $file;
1484 }
1485
1486 sub verify_media_type {
1487     my ($opt, $vtype, $media) = @_;
1488
1489     return if !$media;
1490
1491     my $etype;
1492     if ($media eq 'disk') {
1493         $etype = 'images';
1494     } elsif ($media eq 'cdrom') {
1495         $etype = 'iso';
1496     } else {
1497         die "internal error";
1498     }
1499
1500     return if ($vtype eq $etype);
1501
1502     raise_param_exc({ $opt => "unexpected media type ($vtype != $etype)" });
1503 }
1504
1505 sub cleanup_drive_path {
1506     my ($opt, $storecfg, $drive) = @_;
1507
1508     # try to convert filesystem paths to volume IDs
1509
1510     if (($drive->{file} !~ m/^(cdrom|none)$/) &&
1511         ($drive->{file} !~ m|^/dev/.+|) &&
1512         ($drive->{file} !~ m/^([^:]+):(.+)$/) &&
1513         ($drive->{file} !~ m/^\d+$/)) {
1514         my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
1515         raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1516         $drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
1517         verify_media_type($opt, $vtype, $drive->{media});
1518         $drive->{file} = $volid;
1519     }
1520
1521     $drive->{media} = 'cdrom' if !$drive->{media} && $drive->{file} =~ m/^(cdrom|none)$/;
1522 }
1523
1524 sub parse_hotplug_features {
1525     my ($data) = @_;
1526
1527     my $res = {};
1528
1529     return $res if $data eq '0';
1530
1531     $data = $confdesc->{hotplug}->{default} if $data eq '1';
1532
1533     foreach my $feature (PVE::Tools::split_list($data)) {
1534         if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1535             $res->{$1} = 1;
1536         } else {
1537             die "invalid hotplug feature '$feature'\n";
1538         }
1539     }
1540     return $res;
1541 }
1542
1543 PVE::JSONSchema::register_format('pve-hotplug-features', \&pve_verify_hotplug_features);
1544 sub pve_verify_hotplug_features {
1545     my ($value, $noerr) = @_;
1546
1547     return $value if parse_hotplug_features($value);
1548
1549     return undef if $noerr;
1550
1551     die "unable to parse hotplug option\n";
1552 }
1553
1554 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1555 #        [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1556 #        [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1557 #        [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1558 #        [,iothread=on][,serial=serial][,model=model]
1559
1560 sub parse_drive {
1561     my ($key, $data) = @_;
1562
1563     my ($interface, $index);
1564
1565     if ($key =~ m/^([^\d]+)(\d+)$/) {
1566         $interface = $1;
1567         $index = $2;
1568     } else {
1569         return undef;
1570     }
1571
1572     my $desc = $key =~ /^unused\d+$/ ? $alldrive_fmt
1573                                      : $confdesc->{$key}->{format};
1574     if (!$desc) {
1575         warn "invalid drive key: $key\n";
1576         return undef;
1577     }
1578     my $res = eval { PVE::JSONSchema::parse_property_string($desc, $data) };
1579     return undef if !$res;
1580     $res->{interface} = $interface;
1581     $res->{index} = $index;
1582
1583     my $error = 0;
1584     foreach my $opt (qw(bps bps_rd bps_wr)) {
1585         if (my $bps = defined(delete $res->{$opt})) {
1586             if (defined($res->{"m$opt"})) {
1587                 warn "both $opt and m$opt specified\n";
1588                 ++$error;
1589                 next;
1590             }
1591             $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1592         }
1593     }
1594
1595     # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1596     for my $requirement (
1597         [mbps_max => 'mbps'],
1598         [mbps_rd_max => 'mbps_rd'],
1599         [mbps_wr_max => 'mbps_wr'],
1600         [miops_max => 'miops'],
1601         [miops_rd_max => 'miops_rd'],
1602         [miops_wr_max => 'miops_wr'],
1603         [bps_max_length => 'mbps_max'],
1604         [bps_rd_max_length => 'mbps_rd_max'],
1605         [bps_wr_max_length => 'mbps_wr_max'],
1606         [iops_max_length => 'iops_max'],
1607         [iops_rd_max_length => 'iops_rd_max'],
1608         [iops_wr_max_length => 'iops_wr_max']) {
1609         my ($option, $requires) = @$requirement;
1610         if ($res->{$option} && !$res->{$requires}) {
1611             warn "$option requires $requires\n";
1612             ++$error;
1613         }
1614     }
1615
1616     return undef if $error;
1617
1618     return undef if $res->{mbps_rd} && $res->{mbps};
1619     return undef if $res->{mbps_wr} && $res->{mbps};
1620     return undef if $res->{iops_rd} && $res->{iops};
1621     return undef if $res->{iops_wr} && $res->{iops};
1622
1623     if ($res->{media} && ($res->{media} eq 'cdrom')) {
1624         return undef if $res->{snapshot} || $res->{trans} || $res->{format};
1625         return undef if $res->{heads} || $res->{secs} || $res->{cyls};
1626         return undef if $res->{interface} eq 'virtio';
1627     }
1628
1629     if (my $size = $res->{size}) {
1630         return undef if !defined($res->{size} = PVE::JSONSchema::parse_size($size));
1631     }
1632
1633     return $res;
1634 }
1635
1636 sub print_drive {
1637     my ($vmid, $drive) = @_;
1638     my $data = { %$drive };
1639     delete $data->{$_} for qw(index interface);
1640     return PVE::JSONSchema::print_property_string($data, $alldrive_fmt);
1641 }
1642
1643 sub scsi_inquiry {
1644     my($fh, $noerr) = @_;
1645
1646     my $SG_IO = 0x2285;
1647     my $SG_GET_VERSION_NUM = 0x2282;
1648
1649     my $versionbuf = "\x00" x 8;
1650     my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1651     if (!$ret) {
1652         die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1653         return undef;
1654     }
1655     my $version = unpack("I", $versionbuf);
1656     if ($version < 30000) {
1657         die "scsi generic interface too old\n"  if !$noerr;
1658         return undef;
1659     }
1660
1661     my $buf = "\x00" x 36;
1662     my $sensebuf = "\x00" x 8;
1663     my $cmd = pack("C x3 C x1", 0x12, 36);
1664
1665     # see /usr/include/scsi/sg.h
1666     my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1667
1668     my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1669                       length($sensebuf), 0, length($buf), $buf,
1670                       $cmd, $sensebuf, 6000);
1671
1672     $ret = ioctl($fh, $SG_IO, $packet);
1673     if (!$ret) {
1674         die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1675         return undef;
1676     }
1677
1678     my @res = unpack($sg_io_hdr_t, $packet);
1679     if ($res[17] || $res[18]) {
1680         die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1681         return undef;
1682     }
1683
1684     my $res = {};
1685     (my $byte0, my $byte1, $res->{vendor},
1686      $res->{product}, $res->{revision}) = unpack("C C x6 A8 A16 A4", $buf);
1687
1688     $res->{removable} = $byte1 & 128 ? 1 : 0;
1689     $res->{type} = $byte0 & 31;
1690
1691     return $res;
1692 }
1693
1694 sub path_is_scsi {
1695     my ($path) = @_;
1696
1697     my $fh = IO::File->new("+<$path") || return undef;
1698     my $res = scsi_inquiry($fh, 1);
1699     close($fh);
1700
1701     return $res;
1702 }
1703
1704 sub machine_type_is_q35 {
1705     my ($conf) = @_;
1706
1707     return $conf->{machine} && ($conf->{machine} =~ m/q35/) ? 1 : 0;
1708 }
1709
1710 sub print_tabletdevice_full {
1711     my ($conf, $arch) = @_;
1712
1713     my $q35 = machine_type_is_q35($conf);
1714
1715     # we use uhci for old VMs because tablet driver was buggy in older qemu
1716     my $usbbus;
1717     if (machine_type_is_q35($conf) || $arch eq 'aarch64') {
1718         $usbbus = 'ehci';
1719     } else {
1720         $usbbus = 'uhci';
1721     }
1722
1723     return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1724 }
1725
1726 sub print_keyboarddevice_full {
1727     my ($conf, $arch, $machine) = @_;
1728
1729     return undef if $arch ne 'aarch64';
1730
1731     return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1732 }
1733
1734 sub print_drivedevice_full {
1735     my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1736
1737     my $device = '';
1738     my $maxdev = 0;
1739
1740     if ($drive->{interface} eq 'virtio') {
1741         my $pciaddr = print_pci_addr("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1742         $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1743         $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread};
1744     } elsif ($drive->{interface} eq 'scsi') {
1745
1746         my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
1747         my $unit = $drive->{index} % $maxdev;
1748         my $devicetype = 'hd';
1749         my $path = '';
1750         if (drive_is_cdrom($drive)) {
1751             $devicetype = 'cd';
1752         } else {
1753             if ($drive->{file} =~ m|^/|) {
1754                 $path = $drive->{file};
1755                 if (my $info = path_is_scsi($path)) {
1756                     if ($info->{type} == 0 && $drive->{scsiblock}) {
1757                         $devicetype = 'block';
1758                     } elsif ($info->{type} == 1) { # tape
1759                         $devicetype = 'generic';
1760                     }
1761                 }
1762             } else {
1763                  $path = PVE::Storage::path($storecfg, $drive->{file});
1764             }
1765
1766             if($path =~ m/^iscsi\:\/\//){
1767                 $devicetype = 'generic';
1768             }
1769         }
1770
1771         if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)){
1772             $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1773         } else {
1774             $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0,lun=$drive->{index},drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1775         }
1776
1777         if ($drive->{ssd} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1778             $device .= ",rotation_rate=1";
1779         }
1780
1781     } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') {
1782         my $maxdev = ($drive->{interface} eq 'sata') ? $MAX_SATA_DISKS : 2;
1783         my $controller = int($drive->{index} / $maxdev);
1784         my $unit = $drive->{index} % $maxdev;
1785         my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
1786
1787         $device = "ide-$devicetype";
1788         if ($drive->{interface} eq 'ide') {
1789             $device .= ",bus=ide.$controller,unit=$unit";
1790         } else {
1791             $device .= ",bus=ahci$controller.$unit";
1792         }
1793         $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1794
1795         if ($devicetype eq 'hd') {
1796             if (my $model = $drive->{model}) {
1797                 $model = URI::Escape::uri_unescape($model);
1798                 $device .= ",model=$model";
1799             }
1800             if ($drive->{ssd}) {
1801                 $device .= ",rotation_rate=1";
1802             }
1803         }
1804     } elsif ($drive->{interface} eq 'usb') {
1805         die "implement me";
1806         #  -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1807     } else {
1808         die "unsupported interface type";
1809     }
1810
1811     $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex};
1812
1813     if (my $serial = $drive->{serial}) {
1814         $serial = URI::Escape::uri_unescape($serial);
1815         $device .= ",serial=$serial";
1816     }
1817
1818
1819     return $device;
1820 }
1821
1822 sub get_initiator_name {
1823     my $initiator;
1824
1825     my $fh = IO::File->new('/etc/iscsi/initiatorname.iscsi') || return undef;
1826     while (defined(my $line = <$fh>)) {
1827         next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1828         $initiator = $1;
1829         last;
1830     }
1831     $fh->close();
1832
1833     return $initiator;
1834 }
1835
1836 sub print_drive_full {
1837     my ($storecfg, $vmid, $drive) = @_;
1838
1839     my $path;
1840     my $volid = $drive->{file};
1841     my $format;
1842     
1843     if (drive_is_cdrom($drive)) {
1844         $path = get_iso_path($storecfg, $vmid, $volid);
1845     } else {
1846         my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
1847         if ($storeid) {
1848             $path = PVE::Storage::path($storecfg, $volid);
1849             my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
1850             $format = qemu_img_format($scfg, $volname);
1851         } else {
1852             $path = $volid;
1853             $format = "raw";
1854         }
1855    }
1856
1857     my $opts = '';
1858     my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1859     foreach my $o (@qemu_drive_options) {
1860         $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1861     }
1862
1863     # snapshot only accepts on|off
1864     if (defined($drive->{snapshot})) {
1865         my $v = $drive->{snapshot} ? 'on' : 'off';
1866         $opts .= ",snapshot=$v";
1867     }
1868
1869     foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) {
1870         my ($dir, $qmpname) = @$type;
1871         if (my $v = $drive->{"mbps$dir"}) {
1872             $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1873         }
1874         if (my $v = $drive->{"mbps${dir}_max"}) {
1875             $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1876         }
1877         if (my $v = $drive->{"bps${dir}_max_length"}) {
1878             $opts .= ",throttling.bps$qmpname-max-length=$v";
1879         }
1880         if (my $v = $drive->{"iops${dir}"}) {
1881             $opts .= ",throttling.iops$qmpname=$v";
1882         }
1883         if (my $v = $drive->{"iops${dir}_max"}) {
1884             $opts .= ",throttling.iops$qmpname-max=$v";
1885         }
1886         if (my $v = $drive->{"iops${dir}_max_length"}) {
1887             $opts .= ",throttling.iops$qmpname-max-length=$v";
1888         }
1889     }
1890
1891     $opts .= ",format=$format" if $format && !$drive->{format};
1892
1893     my $cache_direct = 0;
1894
1895     if (my $cache = $drive->{cache}) {
1896         $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1897     } elsif (!drive_is_cdrom($drive)) {
1898         $opts .= ",cache=none";
1899         $cache_direct = 1;
1900     }
1901
1902     # aio native works only with O_DIRECT
1903     if (!$drive->{aio}) {
1904         if($cache_direct) {
1905             $opts .= ",aio=native";
1906         } else {
1907             $opts .= ",aio=threads";
1908         }
1909     }
1910
1911     if (!drive_is_cdrom($drive)) {
1912         my $detectzeroes;
1913         if (defined($drive->{detect_zeroes}) && !$drive->{detect_zeroes}) {
1914             $detectzeroes = 'off';
1915         } elsif ($drive->{discard}) {
1916             $detectzeroes = $drive->{discard} eq 'on' ? 'unmap' : 'on';
1917         } else {
1918             # This used to be our default with discard not being specified:
1919             $detectzeroes = 'on';
1920         }
1921         $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1922     }
1923
1924     my $pathinfo = $path ? "file=$path," : '';
1925
1926     return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1927 }
1928
1929 sub print_netdevice_full {
1930     my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1931
1932     my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
1933
1934     my $device = $net->{model};
1935     if ($net->{model} eq 'virtio') {
1936          $device = 'virtio-net-pci';
1937      };
1938
1939     my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $machine_type);
1940     my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1941     if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
1942         #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1943         my $vectors = $net->{queues} * 2 + 2;
1944         $tmpstr .= ",vectors=$vectors,mq=on";
1945     }
1946     $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
1947
1948     if ($use_old_bios_files) {
1949         my $romfile;
1950         if ($device eq 'virtio-net-pci') {
1951             $romfile = 'pxe-virtio.rom';
1952         } elsif ($device eq 'e1000') {
1953             $romfile = 'pxe-e1000.rom';
1954         } elsif ($device eq 'ne2k') {
1955             $romfile = 'pxe-ne2k_pci.rom';
1956         } elsif ($device eq 'pcnet') {
1957             $romfile = 'pxe-pcnet.rom';
1958         } elsif ($device eq 'rtl8139') {
1959             $romfile = 'pxe-rtl8139.rom';
1960         }
1961         $tmpstr .= ",romfile=$romfile" if $romfile;
1962     }
1963
1964     return $tmpstr;
1965 }
1966
1967 sub print_netdev_full {
1968     my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1969
1970     my $i = '';
1971     if ($netid =~ m/^net(\d+)$/) {
1972         $i = int($1);
1973     }
1974
1975     die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
1976
1977     my $ifname = "tap${vmid}i$i";
1978
1979     # kvm uses TUNSETIFF ioctl, and that limits ifname length
1980     die "interface name '$ifname' is too long (max 15 character)\n"
1981         if length($ifname) >= 16;
1982
1983     my $vhostparam = '';
1984     if (is_native($arch)) {
1985         $vhostparam = ',vhost=on' if kernel_has_vhost_net() && $net->{model} eq 'virtio';
1986     }
1987
1988     my $vmname = $conf->{name} || "vm$vmid";
1989
1990     my $netdev = "";
1991     my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
1992
1993     if ($net->{bridge}) {
1994         $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1995     } else {
1996         $netdev = "type=user,id=$netid,hostname=$vmname";
1997     }
1998
1999     $netdev .= ",queues=$net->{queues}" if ($net->{queues} && $net->{model} eq 'virtio');
2000
2001     return $netdev;
2002 }
2003
2004
2005 sub print_cpu_device {
2006     my ($conf, $id) = @_;
2007
2008     my $kvm = $conf->{kvm} // 1;
2009     my $cpu = $kvm ? "kvm64" : "qemu64";
2010     if (my $cputype = $conf->{cpu}) {
2011         my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
2012             or die "Cannot parse cpu description: $cputype\n";
2013         $cpu = $cpuconf->{cputype};
2014     }
2015
2016     my $cores = $conf->{cores} || 1;
2017
2018     my $current_core = ($id - 1) % $cores;
2019     my $current_socket = int(($id - 1 - $current_core)/$cores);
2020
2021     return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2022 }
2023
2024 my $vga_map = {
2025     'cirrus' => 'cirrus-vga',
2026     'std' => 'VGA',
2027     'vmware' => 'vmware-svga',
2028     'virtio' => 'virtio-vga',
2029 };
2030
2031 sub print_vga_device {
2032     my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2033
2034     my $type = $vga_map->{$vga->{type}};
2035     if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
2036         $type = 'virtio-gpu';
2037     }
2038     my $vgamem_mb = $vga->{memory};
2039     if ($qxlnum) {
2040         $type = $id ? 'qxl' : 'qxl-vga';
2041     }
2042     die "no devicetype for $vga->{type}\n" if !$type;
2043
2044     my $memory = "";
2045     if ($vgamem_mb) {
2046         if ($vga->{type} eq 'virtio') {
2047             my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
2048             $memory = ",max_hostmem=$bytes";
2049         } elsif ($qxlnum) {
2050             # from https://www.spice-space.org/multiple-monitors.html
2051             $memory = ",vgamem_mb=$vga->{memory}";
2052             my $ram = $vgamem_mb * 4;
2053             my $vram = $vgamem_mb * 2;
2054             $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2055         } else {
2056             $memory = ",vgamem_mb=$vga->{memory}";
2057         }
2058     } elsif ($qxlnum && $id) {
2059         $memory = ",ram_size=67108864,vram_size=33554432";
2060     }
2061
2062     my $q35 = machine_type_is_q35($conf);
2063     my $vgaid = "vga" . ($id // '');
2064     my $pciaddr;
2065
2066     if ($q35 && $vgaid eq 'vga') {
2067         # the first display uses pcie.0 bus on q35 machines
2068         $pciaddr = print_pcie_addr($vgaid, $bridges, $arch, $machine);
2069     } else {
2070         $pciaddr = print_pci_addr($vgaid, $bridges, $arch, $machine);
2071     }
2072
2073     return "$type,id=${vgaid}${memory}${pciaddr}";
2074 }
2075
2076 sub drive_is_cloudinit {
2077     my ($drive) = @_;
2078     return $drive->{file} =~ m@[:/]vm-\d+-cloudinit(?:\.$QEMU_FORMAT_RE)?$@;
2079 }
2080
2081 sub drive_is_cdrom {
2082     my ($drive, $exclude_cloudinit) = @_;
2083
2084     return 0 if $exclude_cloudinit && drive_is_cloudinit($drive);
2085
2086     return $drive && $drive->{media} && ($drive->{media} eq 'cdrom');
2087
2088 }
2089
2090 sub parse_number_sets {
2091     my ($set) = @_;
2092     my $res = [];
2093     foreach my $part (split(/;/, $set)) {
2094         if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2095             die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2096             push @$res, [ $1, $2 ];
2097         } else {
2098             die "invalid range: $part\n";
2099         }
2100     }
2101     return $res;
2102 }
2103
2104 sub parse_numa {
2105     my ($data) = @_;
2106
2107     my $res = PVE::JSONSchema::parse_property_string($numa_fmt, $data);
2108     $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
2109     $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
2110     return $res;
2111 }
2112
2113 sub parse_hostpci {
2114     my ($value) = @_;
2115
2116     return undef if !$value;
2117
2118     my $res = PVE::JSONSchema::parse_property_string($hostpci_fmt, $value);
2119
2120     my @idlist = split(/;/, $res->{host});
2121     delete $res->{host};
2122     foreach my $id (@idlist) {
2123         if ($id =~ m/\./) { # full id 00:00.1
2124             push @{$res->{pciid}}, {
2125                 id => $id,
2126             };
2127         } else { # partial id 00:00
2128             $res->{pciid} = PVE::SysFSTools::lspci($id);
2129         }
2130     }
2131     return $res;
2132 }
2133
2134 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2135 sub parse_net {
2136     my ($data) = @_;
2137
2138     my $res = eval { PVE::JSONSchema::parse_property_string($net_fmt, $data) };
2139     if ($@) {
2140         warn $@;
2141         return undef;
2142     }
2143     if (!defined($res->{macaddr})) {
2144         my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
2145         $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
2146     }
2147     return $res;
2148 }
2149
2150 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2151 sub parse_ipconfig {
2152     my ($data) = @_;
2153
2154     my $res = eval { PVE::JSONSchema::parse_property_string($ipconfig_fmt, $data) };
2155     if ($@) {
2156         warn $@;
2157         return undef;
2158     }
2159
2160     if ($res->{gw} && !$res->{ip}) {
2161         warn 'gateway specified without specifying an IP address';
2162         return undef;
2163     }
2164     if ($res->{gw6} && !$res->{ip6}) {
2165         warn 'IPv6 gateway specified without specifying an IPv6 address';
2166         return undef;
2167     }
2168     if ($res->{gw} && $res->{ip} eq 'dhcp') {
2169         warn 'gateway specified together with DHCP';
2170         return undef;
2171     }
2172     if ($res->{gw6} && $res->{ip6} !~ /^$IPV6RE/) {
2173         # gw6 + auto/dhcp
2174         warn "IPv6 gateway specified together with $res->{ip6} address";
2175         return undef;
2176     }
2177
2178     if (!$res->{ip} && !$res->{ip6}) {
2179         return { ip => 'dhcp', ip6 => 'dhcp' };
2180     }
2181
2182     return $res;
2183 }
2184
2185 sub print_net {
2186     my $net = shift;
2187
2188     return PVE::JSONSchema::print_property_string($net, $net_fmt);
2189 }
2190
2191 sub add_random_macs {
2192     my ($settings) = @_;
2193
2194     foreach my $opt (keys %$settings) {
2195         next if $opt !~ m/^net(\d+)$/;
2196         my $net = parse_net($settings->{$opt});
2197         next if !$net;
2198         $settings->{$opt} = print_net($net);
2199     }
2200 }
2201
2202 sub vm_is_volid_owner {
2203     my ($storecfg, $vmid, $volid) = @_;
2204
2205     if ($volid !~  m|^/|) {
2206         my ($path, $owner);
2207         eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
2208         if ($owner && ($owner == $vmid)) {
2209             return 1;
2210         }
2211     }
2212
2213     return undef;
2214 }
2215
2216 sub split_flagged_list {
2217     my $text = shift || '';
2218     $text =~ s/[,;]/ /g;
2219     $text =~ s/^\s+//;
2220     return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2221 }
2222
2223 sub join_flagged_list {
2224     my ($how, $lst) = @_;
2225     join $how, map { $lst->{$_} . $_ } keys %$lst;
2226 }
2227
2228 sub vmconfig_delete_pending_option {
2229     my ($conf, $key, $force) = @_;
2230
2231     delete $conf->{pending}->{$key};
2232     my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
2233     $pending_delete_hash->{$key} = $force ? '!' : '';
2234     $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
2235 }
2236
2237 sub vmconfig_undelete_pending_option {
2238     my ($conf, $key) = @_;
2239
2240     my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
2241     delete $pending_delete_hash->{$key};
2242
2243     if (%$pending_delete_hash) {
2244         $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
2245     } else {
2246         delete $conf->{pending}->{delete};
2247     }
2248 }
2249
2250 sub vmconfig_register_unused_drive {
2251     my ($storecfg, $vmid, $conf, $drive) = @_;
2252
2253     if (drive_is_cloudinit($drive)) {
2254         eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
2255         warn $@ if $@;
2256     } elsif (!drive_is_cdrom($drive)) {
2257         my $volid = $drive->{file};
2258         if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
2259             PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
2260         }
2261     }
2262 }
2263
2264 sub vmconfig_cleanup_pending {
2265     my ($conf) = @_;
2266
2267     # remove pending changes when nothing changed
2268     my $changes;
2269     foreach my $opt (keys %{$conf->{pending}}) {
2270         if (defined($conf->{$opt}) && ($conf->{pending}->{$opt} eq  $conf->{$opt})) {
2271             $changes = 1;
2272             delete $conf->{pending}->{$opt};
2273         }
2274     }
2275
2276     my $current_delete_hash = split_flagged_list($conf->{pending}->{delete});
2277     my $pending_delete_hash = {};
2278     while (my ($opt, $force) = each %$current_delete_hash) {
2279         if (defined($conf->{$opt})) {
2280             $pending_delete_hash->{$opt} = $force;
2281         } else {
2282             $changes = 1;
2283         }
2284     }
2285
2286     if (%$pending_delete_hash) {
2287         $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
2288     } else {
2289         delete $conf->{pending}->{delete};
2290     }
2291
2292     return $changes;
2293 }
2294
2295 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2296 my $smbios1_fmt = {
2297     uuid => {
2298         type => 'string',
2299         pattern => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2300         format_description => 'UUID',
2301         description => "Set SMBIOS1 UUID.",
2302         optional => 1,
2303     },
2304     version => {
2305         type => 'string',
2306         pattern => '\S+',
2307         format_description => 'string',
2308         description => "Set SMBIOS1 version.",
2309         optional => 1,
2310     },
2311     serial => {
2312         type => 'string',
2313         pattern => '\S+',
2314         format_description => 'string',
2315         description => "Set SMBIOS1 serial number.",
2316         optional => 1,
2317     },
2318     manufacturer => {
2319         type => 'string',
2320         pattern => '\S+',
2321         format_description => 'string',
2322         description => "Set SMBIOS1 manufacturer.",
2323         optional => 1,
2324     },
2325     product => {
2326         type => 'string',
2327         pattern => '\S+',
2328         format_description => 'string',
2329         description => "Set SMBIOS1 product ID.",
2330         optional => 1,
2331     },
2332     sku => {
2333         type => 'string',
2334         pattern => '\S+',
2335         format_description => 'string',
2336         description => "Set SMBIOS1 SKU string.",
2337         optional => 1,
2338     },
2339     family => {
2340         type => 'string',
2341         pattern => '\S+',
2342         format_description => 'string',
2343         description => "Set SMBIOS1 family string.",
2344         optional => 1,
2345     },
2346 };
2347
2348 sub parse_smbios1 {
2349     my ($data) = @_;
2350
2351     my $res = eval { PVE::JSONSchema::parse_property_string($smbios1_fmt, $data) };
2352     warn $@ if $@;
2353     return $res;
2354 }
2355
2356 sub print_smbios1 {
2357     my ($smbios1) = @_;
2358     return PVE::JSONSchema::print_property_string($smbios1, $smbios1_fmt);
2359 }
2360
2361 PVE::JSONSchema::register_format('pve-qm-smbios1', $smbios1_fmt);
2362
2363 PVE::JSONSchema::register_format('pve-qm-bootdisk', \&verify_bootdisk);
2364 sub verify_bootdisk {
2365     my ($value, $noerr) = @_;
2366
2367     return $value if is_valid_drivename($value);
2368
2369     return undef if $noerr;
2370
2371     die "invalid boot disk '$value'\n";
2372 }
2373
2374 sub parse_watchdog {
2375     my ($value) = @_;
2376
2377     return undef if !$value;
2378
2379     my $res = eval { PVE::JSONSchema::parse_property_string($watchdog_fmt, $value) };
2380     warn $@ if $@;
2381     return $res;
2382 }
2383
2384 sub parse_guest_agent {
2385     my ($value) = @_;
2386
2387     return {} if !defined($value->{agent});
2388
2389     my $res = eval { PVE::JSONSchema::parse_property_string($agent_fmt, $value->{agent}) };
2390     warn $@ if $@;
2391
2392     # if the agent is disabled ignore the other potentially set properties
2393     return {} if !$res->{enabled};
2394     return $res;
2395 }
2396
2397 sub parse_vga {
2398     my ($value) = @_;
2399
2400     return {} if !$value;
2401     my $res = eval { PVE::JSONSchema::parse_property_string($vga_fmt, $value) };
2402     warn $@ if $@;
2403     return $res;
2404 }
2405
2406 PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
2407 sub verify_usb_device {
2408     my ($value, $noerr) = @_;
2409
2410     return $value if parse_usb_device($value);
2411
2412     return undef if $noerr;
2413
2414     die "unable to parse usb device\n";
2415 }
2416
2417 # add JSON properties for create and set function
2418 sub json_config_properties {
2419     my $prop = shift;
2420
2421     foreach my $opt (keys %$confdesc) {
2422         next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2423         $prop->{$opt} = $confdesc->{$opt};
2424     }
2425
2426     return $prop;
2427 }
2428
2429 # return copy of $confdesc_cloudinit to generate documentation
2430 sub cloudinit_config_properties {
2431
2432     return dclone($confdesc_cloudinit);
2433 }
2434
2435 sub check_type {
2436     my ($key, $value) = @_;
2437
2438     die "unknown setting '$key'\n" if !$confdesc->{$key};
2439
2440     my $type = $confdesc->{$key}->{type};
2441
2442     if (!defined($value)) {
2443         die "got undefined value\n";
2444     }
2445
2446     if ($value =~ m/[\n\r]/) {
2447         die "property contains a line feed\n";
2448     }
2449
2450     if ($type eq 'boolean') {
2451         return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2452         return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2453         die "type check ('boolean') failed - got '$value'\n";
2454     } elsif ($type eq 'integer') {
2455         return int($1) if $value =~ m/^(\d+)$/;
2456         die "type check ('integer') failed - got '$value'\n";
2457     } elsif ($type eq 'number') {
2458         return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2459         die "type check ('number') failed - got '$value'\n";
2460     } elsif ($type eq 'string') {
2461         if (my $fmt = $confdesc->{$key}->{format}) {
2462             PVE::JSONSchema::check_format($fmt, $value);
2463             return $value;
2464         }
2465         $value =~ s/^\"(.*)\"$/$1/;
2466         return $value;
2467     } else {
2468         die "internal error"
2469     }
2470 }
2471
2472 sub touch_config {
2473     my ($vmid) = @_;
2474
2475     my $conf = PVE::QemuConfig->config_file($vmid);
2476     utime undef, undef, $conf;
2477 }
2478
2479 sub destroy_vm {
2480     my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2481
2482     my $conffile = PVE::QemuConfig->config_file($vmid);
2483
2484     my $conf = PVE::QemuConfig->load_config($vmid);
2485
2486     PVE::QemuConfig->check_lock($conf) if !$skiplock;
2487
2488     if ($conf->{template}) {
2489         # check if any base image is still used by a linked clone
2490         foreach_drive($conf, sub {
2491                 my ($ds, $drive) = @_;
2492
2493                 return if drive_is_cdrom($drive);
2494
2495                 my $volid = $drive->{file};
2496
2497                 return if !$volid || $volid =~ m|^/|;
2498
2499                 die "base volume '$volid' is still in use by linked cloned\n"
2500                     if PVE::Storage::volume_is_base_and_used($storecfg, $volid);
2501
2502         });
2503     }
2504
2505     # only remove disks owned by this VM
2506     foreach_drive($conf, sub {
2507         my ($ds, $drive) = @_;
2508
2509         return if drive_is_cdrom($drive, 1);
2510
2511         my $volid = $drive->{file};
2512
2513         return if !$volid || $volid =~ m|^/|;
2514
2515         my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
2516         return if !$path || !$owner || ($owner != $vmid);
2517
2518         eval {
2519             PVE::Storage::vdisk_free($storecfg, $volid);
2520         };
2521         warn "Could not remove disk '$volid', check manually: $@" if $@;
2522
2523     });
2524
2525     if ($keep_empty_config) {
2526         PVE::Tools::file_set_contents($conffile, "memory: 128\n");
2527     } else {
2528         unlink $conffile;
2529     }
2530
2531     # also remove unused disk
2532     eval {
2533         my $dl = PVE::Storage::vdisk_list($storecfg, undef, $vmid);
2534
2535         eval {
2536             PVE::Storage::foreach_volid($dl, sub {
2537                 my ($volid, $sid, $volname, $d) = @_;
2538                 PVE::Storage::vdisk_free($storecfg, $volid);
2539             });
2540         };
2541         warn $@ if $@;
2542
2543     };
2544     warn $@ if $@;
2545 }
2546
2547 sub parse_vm_config {
2548     my ($filename, $raw) = @_;
2549
2550     return undef if !defined($raw);
2551
2552     my $res = {
2553         digest => Digest::SHA::sha1_hex($raw),
2554         snapshots => {},
2555         pending => {},
2556     };
2557
2558     $filename =~ m|/qemu-server/(\d+)\.conf$|
2559         || die "got strange filename '$filename'";
2560
2561     my $vmid = $1;
2562
2563     my $conf = $res;
2564     my $descr;
2565     my $section = '';
2566
2567     my @lines = split(/\n/, $raw);
2568     foreach my $line (@lines) {
2569         next if $line =~ m/^\s*$/;
2570
2571         if ($line =~ m/^\[PENDING\]\s*$/i) {
2572             $section = 'pending';
2573             if (defined($descr)) {
2574                 $descr =~ s/\s+$//;
2575                 $conf->{description} = $descr;
2576             }
2577             $descr = undef;
2578             $conf = $res->{$section} = {};
2579             next;
2580
2581         } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2582             $section = $1;
2583             if (defined($descr)) {
2584                 $descr =~ s/\s+$//;
2585                 $conf->{description} = $descr;
2586             }
2587             $descr = undef;
2588             $conf = $res->{snapshots}->{$section} = {};
2589             next;
2590         }
2591
2592         if ($line =~ m/^\#(.*)\s*$/) {
2593             $descr = '' if !defined($descr);
2594             $descr .= PVE::Tools::decode_text($1) . "\n";
2595             next;
2596         }
2597
2598         if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2599             $descr = '' if !defined($descr);
2600             $descr .= PVE::Tools::decode_text($2);
2601         } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2602             $conf->{snapstate} = $1;
2603         } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2604             my $key = $1;
2605             my $value = $2;
2606             $conf->{$key} = $value;
2607         } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2608             my $value = $1;
2609             if ($section eq 'pending') {
2610                 $conf->{delete} = $value; # we parse this later
2611             } else {
2612                 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2613             }
2614         } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2615             my $key = $1;
2616             my $value = $2;
2617             eval { $value = check_type($key, $value); };
2618             if ($@) {
2619                 warn "vm $vmid - unable to parse value of '$key' - $@";
2620             } else {
2621                 $key = 'ide2' if $key eq 'cdrom';
2622                 my $fmt = $confdesc->{$key}->{format};
2623                 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2624                     my $v = parse_drive($key, $value);
2625                     if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
2626                         $v->{file} = $volid;
2627                         $value = print_drive($vmid, $v);
2628                     } else {
2629                         warn "vm $vmid - unable to parse value of '$key'\n";
2630                         next;
2631                     }
2632                 }
2633
2634                 $conf->{$key} = $value;
2635             }
2636         }
2637     }
2638
2639     if (defined($descr)) {
2640         $descr =~ s/\s+$//;
2641         $conf->{description} = $descr;
2642     }
2643     delete $res->{snapstate}; # just to be sure
2644
2645     return $res;
2646 }
2647
2648 sub write_vm_config {
2649     my ($filename, $conf) = @_;
2650
2651     delete $conf->{snapstate}; # just to be sure
2652
2653     if ($conf->{cdrom}) {
2654         die "option ide2 conflicts with cdrom\n" if $conf->{ide2};
2655         $conf->{ide2} = $conf->{cdrom};
2656         delete $conf->{cdrom};
2657     }
2658
2659     # we do not use 'smp' any longer
2660     if ($conf->{sockets}) {
2661         delete $conf->{smp};
2662     } elsif ($conf->{smp}) {
2663         $conf->{sockets} = $conf->{smp};
2664         delete $conf->{cores};
2665         delete $conf->{smp};
2666     }
2667
2668     my $used_volids = {};
2669
2670     my $cleanup_config = sub {
2671         my ($cref, $pending, $snapname) = @_;
2672
2673         foreach my $key (keys %$cref) {
2674             next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2675                 $key eq 'snapstate' || $key eq 'pending';
2676             my $value = $cref->{$key};
2677             if ($key eq 'delete') {
2678                 die "propertry 'delete' is only allowed in [PENDING]\n"
2679                     if !$pending;
2680                 # fixme: check syntax?
2681                 next;
2682             }
2683             eval { $value = check_type($key, $value); };
2684             die "unable to parse value of '$key' - $@" if $@;
2685
2686             $cref->{$key} = $value;
2687
2688             if (!$snapname && is_valid_drivename($key)) {
2689                 my $drive = parse_drive($key, $value);
2690                 $used_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
2691             }
2692         }
2693     };
2694
2695     &$cleanup_config($conf);
2696
2697     &$cleanup_config($conf->{pending}, 1);
2698
2699     foreach my $snapname (keys %{$conf->{snapshots}}) {
2700         die "internal error" if $snapname eq 'pending';
2701         &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
2702     }
2703
2704     # remove 'unusedX' settings if we re-add a volume
2705     foreach my $key (keys %$conf) {
2706         my $value = $conf->{$key};
2707         if ($key =~ m/^unused/ && $used_volids->{$value}) {
2708             delete $conf->{$key};
2709         }
2710     }
2711
2712     my $generate_raw_config = sub {
2713         my ($conf, $pending) = @_;
2714
2715         my $raw = '';
2716
2717         # add description as comment to top of file
2718         if (defined(my $descr = $conf->{description})) {
2719             if ($descr) {
2720                 foreach my $cl (split(/\n/, $descr)) {
2721                     $raw .= '#' .  PVE::Tools::encode_text($cl) . "\n";
2722                 }
2723             } else {
2724                 $raw .= "#\n" if $pending;
2725             }
2726         }
2727
2728         foreach my $key (sort keys %$conf) {
2729             next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2730             $raw .= "$key: $conf->{$key}\n";
2731         }
2732         return $raw;
2733     };
2734
2735     my $raw = &$generate_raw_config($conf);
2736
2737     if (scalar(keys %{$conf->{pending}})){
2738         $raw .= "\n[PENDING]\n";
2739         $raw .= &$generate_raw_config($conf->{pending}, 1);
2740     }
2741
2742     foreach my $snapname (sort keys %{$conf->{snapshots}}) {
2743         $raw .= "\n[$snapname]\n";
2744         $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
2745     }
2746
2747     return $raw;
2748 }
2749
2750 sub load_defaults {
2751
2752     my $res = {};
2753
2754     # we use static defaults from our JSON schema configuration
2755     foreach my $key (keys %$confdesc) {
2756         if (defined(my $default = $confdesc->{$key}->{default})) {
2757             $res->{$key} = $default;
2758         }
2759     }
2760
2761     return $res;
2762 }
2763
2764 sub config_list {
2765     my $vmlist = PVE::Cluster::get_vmlist();
2766     my $res = {};
2767     return $res if !$vmlist || !$vmlist->{ids};
2768     my $ids = $vmlist->{ids};
2769
2770     foreach my $vmid (keys %$ids) {
2771         my $d = $ids->{$vmid};
2772         next if !$d->{node} || $d->{node} ne $nodename;
2773         next if !$d->{type} || $d->{type} ne 'qemu';
2774         $res->{$vmid}->{exists} = 1;
2775     }
2776     return $res;
2777 }
2778
2779 # test if VM uses local resources (to prevent migration)
2780 sub check_local_resources {
2781     my ($conf, $noerr) = @_;
2782
2783     my $loc_res = 0;
2784
2785     $loc_res = 1 if $conf->{hostusb}; # old syntax
2786     $loc_res = 1 if $conf->{hostpci}; # old syntax
2787
2788     foreach my $k (keys %$conf) {
2789         next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2790         # sockets are safe: they will recreated be on the target side post-migrate
2791         next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2792         $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2793     }
2794
2795     die "VM uses local resources\n" if $loc_res && !$noerr;
2796
2797     return $loc_res;
2798 }
2799
2800 # check if used storages are available on all nodes (use by migrate)
2801 sub check_storage_availability {
2802     my ($storecfg, $conf, $node) = @_;
2803
2804     foreach_drive($conf, sub {
2805         my ($ds, $drive) = @_;
2806
2807         my $volid = $drive->{file};
2808         return if !$volid;
2809
2810         my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2811         return if !$sid;
2812
2813         # check if storage is available on both nodes
2814         my $scfg = PVE::Storage::storage_check_node($storecfg, $sid);
2815         PVE::Storage::storage_check_node($storecfg, $sid, $node);
2816    });
2817 }
2818
2819 # list nodes where all VM images are available (used by has_feature API)
2820 sub shared_nodes {
2821     my ($conf, $storecfg) = @_;
2822
2823     my $nodelist = PVE::Cluster::get_nodelist();
2824     my $nodehash = { map { $_ => 1 } @$nodelist };
2825     my $nodename = PVE::INotify::nodename();
2826
2827     foreach_drive($conf, sub {
2828         my ($ds, $drive) = @_;
2829
2830         my $volid = $drive->{file};
2831         return if !$volid;
2832
2833         my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2834         if ($storeid) {
2835             my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2836             if ($scfg->{disable}) {
2837                 $nodehash = {};
2838             } elsif (my $avail = $scfg->{nodes}) {
2839                 foreach my $node (keys %$nodehash) {
2840                     delete $nodehash->{$node} if !$avail->{$node};
2841                 }
2842             } elsif (!$scfg->{shared}) {
2843                 foreach my $node (keys %$nodehash) {
2844                     delete $nodehash->{$node} if $node ne $nodename
2845                 }
2846             }
2847         }
2848     });
2849
2850     return $nodehash
2851 }
2852
2853 sub check_cmdline {
2854     my ($pidfile, $pid) = @_;
2855
2856     my $fh = IO::File->new("/proc/$pid/cmdline", "r");
2857     if (defined($fh)) {
2858         my $line = <$fh>;
2859         $fh->close;
2860         return undef if !$line;
2861         my @param = split(/\0/, $line);
2862
2863         my $cmd = $param[0];
2864         return if !$cmd || ($cmd !~ m|kvm$| && $cmd !~ m@(?:^|/)qemu-system-[^/]+$@);
2865
2866         for (my $i = 0; $i < scalar (@param); $i++) {
2867             my $p = $param[$i];
2868             next if !$p;
2869             if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2870                 my $p = $param[$i+1];
2871                 return 1 if $p && ($p eq $pidfile);
2872                 return undef;
2873             }
2874         }
2875     }
2876     return undef;
2877 }
2878
2879 sub check_running {
2880     my ($vmid, $nocheck, $node) = @_;
2881
2882     my $filename = PVE::QemuConfig->config_file($vmid, $node);
2883
2884     die "unable to find configuration file for VM $vmid - no such machine\n"
2885         if !$nocheck && ! -f $filename;
2886
2887     my $pidfile = pidfile_name($vmid);
2888
2889     if (my $fd = IO::File->new("<$pidfile")) {
2890         my $st = stat($fd);
2891         my $line = <$fd>;
2892         close($fd);
2893
2894         my $mtime = $st->mtime;
2895         if ($mtime > time()) {
2896             warn "file '$filename' modified in future\n";
2897         }
2898
2899         if ($line =~ m/^(\d+)$/) {
2900             my $pid = $1;
2901             if (check_cmdline($pidfile, $pid)) {
2902                 if (my $pinfo = PVE::ProcFSTools::check_process_running($pid)) {
2903                     return $pid;
2904                 }
2905             }
2906         }
2907     }
2908
2909     return undef;
2910 }
2911
2912 sub vzlist {
2913
2914     my $vzlist = config_list();
2915
2916     my $fd = IO::Dir->new($var_run_tmpdir) || return $vzlist;
2917
2918     while (defined(my $de = $fd->read)) {
2919         next if $de !~ m/^(\d+)\.pid$/;
2920         my $vmid = $1;
2921         next if !defined($vzlist->{$vmid});
2922         if (my $pid = check_running($vmid)) {
2923             $vzlist->{$vmid}->{pid} = $pid;
2924         }
2925     }
2926
2927     return $vzlist;
2928 }
2929
2930 sub disksize {
2931     my ($storecfg, $conf) = @_;
2932
2933     my $bootdisk = $conf->{bootdisk};
2934     return undef if !$bootdisk;
2935     return undef if !is_valid_drivename($bootdisk);
2936
2937     return undef if !$conf->{$bootdisk};
2938
2939     my $drive = parse_drive($bootdisk, $conf->{$bootdisk});
2940     return undef if !defined($drive);
2941
2942     return undef if drive_is_cdrom($drive);
2943
2944     my $volid = $drive->{file};
2945     return undef if !$volid;
2946
2947     return $drive->{size};
2948 }
2949
2950 our $vmstatus_return_properties = {
2951     vmid => get_standard_option('pve-vmid'),
2952     status => {
2953         description => "Qemu process status.",
2954         type => 'string',
2955         enum => ['stopped', 'running'],
2956     },
2957     maxmem => {
2958         description => "Maximum memory in bytes.",
2959         type => 'integer',
2960         optional => 1,
2961         renderer => 'bytes',
2962     },
2963     maxdisk => {
2964         description => "Root disk size in bytes.",
2965         type => 'integer',
2966         optional => 1,
2967         renderer => 'bytes',
2968     },
2969     name => {
2970         description => "VM name.",
2971         type => 'string',
2972         optional => 1,
2973     },
2974     qmpstatus => {
2975         description => "Qemu QMP agent status.",
2976         type => 'string',
2977         optional => 1,
2978     },
2979     pid => {
2980         description => "PID of running qemu process.",
2981         type => 'integer',
2982         optional => 1,
2983     },
2984     uptime => {
2985         description => "Uptime.",
2986         type => 'integer',
2987         optional => 1,
2988         renderer => 'duration',
2989     },
2990     cpus => {
2991         description => "Maximum usable CPUs.",
2992         type => 'number',
2993         optional => 1,
2994     },
2995 };
2996
2997 my $last_proc_pid_stat;
2998
2999 # get VM status information
3000 # This must be fast and should not block ($full == false)
3001 # We only query KVM using QMP if $full == true (this can be slow)
3002 sub vmstatus {
3003     my ($opt_vmid, $full) = @_;
3004
3005     my $res = {};
3006
3007     my $storecfg = PVE::Storage::config();
3008
3009     my $list = vzlist();
3010     my $defaults = load_defaults();
3011
3012     my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
3013
3014     my $cpucount = $cpuinfo->{cpus} || 1;
3015
3016     foreach my $vmid (keys %$list) {
3017         next if $opt_vmid && ($vmid ne $opt_vmid);
3018
3019         my $cfspath = PVE::QemuConfig->cfs_config_path($vmid);
3020         my $conf = PVE::Cluster::cfs_read_file($cfspath) || {};
3021
3022         my $d = { vmid => $vmid };
3023         $d->{pid} = $list->{$vmid}->{pid};
3024
3025         # fixme: better status?
3026         $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
3027
3028         my $size = disksize($storecfg, $conf);
3029         if (defined($size)) {
3030             $d->{disk} = 0; # no info available
3031             $d->{maxdisk} = $size;
3032         } else {
3033             $d->{disk} = 0;
3034             $d->{maxdisk} = 0;
3035         }
3036
3037         $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
3038             * ($conf->{cores} || $defaults->{cores});
3039         $d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
3040         $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
3041
3042         $d->{name} = $conf->{name} || "VM $vmid";
3043         $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
3044             : $defaults->{memory}*(1024*1024);
3045
3046         if ($conf->{balloon}) {
3047             $d->{balloon_min} = $conf->{balloon}*(1024*1024);
3048             $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
3049                 : $defaults->{shares};
3050         }
3051
3052         $d->{uptime} = 0;
3053         $d->{cpu} = 0;
3054         $d->{mem} = 0;
3055
3056         $d->{netout} = 0;
3057         $d->{netin} = 0;
3058
3059         $d->{diskread} = 0;
3060         $d->{diskwrite} = 0;
3061
3062         $d->{template} = PVE::QemuConfig->is_template($conf);
3063
3064         $d->{serial} = 1 if conf_has_serial($conf);
3065
3066         $res->{$vmid} = $d;
3067     }
3068
3069     my $netdev = PVE::ProcFSTools::read_proc_net_dev();
3070     foreach my $dev (keys %$netdev) {
3071         next if $dev !~ m/^tap([1-9]\d*)i/;
3072         my $vmid = $1;
3073         my $d = $res->{$vmid};
3074         next if !$d;
3075
3076         $d->{netout} += $netdev->{$dev}->{receive};
3077         $d->{netin} += $netdev->{$dev}->{transmit};
3078
3079         if ($full) {
3080             $d->{nics}->{$dev}->{netout} = $netdev->{$dev}->{receive};
3081             $d->{nics}->{$dev}->{netin} = $netdev->{$dev}->{transmit};
3082         }
3083
3084     }
3085
3086     my $ctime = gettimeofday;
3087
3088     foreach my $vmid (keys %$list) {
3089
3090         my $d = $res->{$vmid};
3091         my $pid = $d->{pid};
3092         next if !$pid;
3093
3094         my $pstat = PVE::ProcFSTools::read_proc_pid_stat($pid);
3095         next if !$pstat; # not running
3096
3097         my $used = $pstat->{utime} + $pstat->{stime};
3098
3099         $d->{uptime} = int(($uptime - $pstat->{starttime})/$cpuinfo->{user_hz});
3100
3101         if ($pstat->{vsize}) {
3102             $d->{mem} = int(($pstat->{rss}/$pstat->{vsize})*$d->{maxmem});
3103         }
3104
3105         my $old = $last_proc_pid_stat->{$pid};
3106         if (!$old) {
3107             $last_proc_pid_stat->{$pid} = {
3108                 time => $ctime,
3109                 used => $used,
3110                 cpu => 0,
3111             };
3112             next;
3113         }
3114
3115         my $dtime = ($ctime -  $old->{time}) * $cpucount * $cpuinfo->{user_hz};
3116
3117         if ($dtime > 1000) {
3118             my $dutime = $used -  $old->{used};
3119
3120             $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
3121             $last_proc_pid_stat->{$pid} = {
3122                 time => $ctime,
3123                 used => $used,
3124                 cpu => $d->{cpu},
3125             };
3126         } else {
3127             $d->{cpu} = $old->{cpu};
3128         }
3129     }
3130
3131     return $res if !$full;
3132
3133     my $qmpclient = PVE::QMPClient->new();
3134
3135     my $ballooncb = sub {
3136         my ($vmid, $resp) = @_;
3137
3138         my $info = $resp->{'return'};
3139         return if !$info->{max_mem};
3140
3141         my $d = $res->{$vmid};
3142
3143         # use memory assigned to VM
3144         $d->{maxmem} = $info->{max_mem};
3145         $d->{balloon} = $info->{actual};
3146
3147         if (defined($info->{total_mem}) && defined($info->{free_mem})) {
3148             $d->{mem} = $info->{total_mem} - $info->{free_mem};
3149             $d->{freemem} = $info->{free_mem};
3150         }
3151
3152         $d->{ballooninfo} = $info;
3153     };
3154
3155     my $blockstatscb = sub {
3156         my ($vmid, $resp) = @_;
3157         my $data = $resp->{'return'} || [];
3158         my $totalrdbytes = 0;
3159         my $totalwrbytes = 0;
3160
3161         for my $blockstat (@$data) {
3162             $totalrdbytes = $totalrdbytes + $blockstat->{stats}->{rd_bytes};
3163             $totalwrbytes = $totalwrbytes + $blockstat->{stats}->{wr_bytes};
3164
3165             $blockstat->{device} =~ s/drive-//;
3166             $res->{$vmid}->{blockstat}->{$blockstat->{device}} = $blockstat->{stats};
3167         }
3168         $res->{$vmid}->{diskread} = $totalrdbytes;
3169         $res->{$vmid}->{diskwrite} = $totalwrbytes;
3170     };
3171
3172     my $statuscb = sub {
3173         my ($vmid, $resp) = @_;
3174
3175         $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3176         # this fails if ballon driver is not loaded, so this must be
3177         # the last commnand (following command are aborted if this fails).
3178         $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3179
3180         my $status = 'unknown';
3181         if (!defined($status = $resp->{'return'}->{status})) {
3182             warn "unable to get VM status\n";
3183             return;
3184         }
3185
3186         $res->{$vmid}->{qmpstatus} = $resp->{'return'}->{status};
3187     };
3188
3189     foreach my $vmid (keys %$list) {
3190         next if $opt_vmid && ($vmid ne $opt_vmid);
3191         next if !$res->{$vmid}->{pid}; # not running
3192         $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3193     }
3194
3195     $qmpclient->queue_execute(undef, 2);
3196
3197     foreach my $vmid (keys %$list) {
3198         next if $opt_vmid && ($vmid ne $opt_vmid);
3199         $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
3200     }
3201
3202     return $res;
3203 }
3204
3205 sub foreach_drive {
3206     my ($conf, $func, @param) = @_;
3207
3208     foreach my $ds (valid_drive_names()) {
3209         next if !defined($conf->{$ds});
3210
3211         my $drive = parse_drive($ds, $conf->{$ds});
3212         next if !$drive;
3213
3214         &$func($ds, $drive, @param);
3215     }
3216 }
3217
3218 sub foreach_volid {
3219     my ($conf, $func, @param) = @_;
3220
3221     my $volhash = {};
3222
3223     my $test_volid = sub {
3224         my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3225
3226         return if !$volid;
3227
3228         $volhash->{$volid}->{cdrom} //= 1;
3229         $volhash->{$volid}->{cdrom} = 0 if !$is_cdrom;
3230
3231         $volhash->{$volid}->{replicate} //= 0;
3232         $volhash->{$volid}->{replicate} = 1 if $replicate;
3233
3234         $volhash->{$volid}->{shared} //= 0;
3235         $volhash->{$volid}->{shared} = 1 if $shared;
3236
3237         $volhash->{$volid}->{referenced_in_config} //= 0;
3238         $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
3239
3240         $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
3241             if defined($snapname);
3242     };
3243
3244     foreach_drive($conf, sub {
3245         my ($ds, $drive) = @_;
3246         $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, undef);
3247     });
3248
3249     foreach my $snapname (keys %{$conf->{snapshots}}) {
3250         my $snap = $conf->{snapshots}->{$snapname};
3251         $test_volid->($snap->{vmstate}, 0, 1, $snapname);
3252         foreach_drive($snap, sub {
3253             my ($ds, $drive) = @_;
3254             $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, $snapname);
3255         });
3256     }
3257
3258     foreach my $volid (keys %$volhash) {
3259         &$func($volid, $volhash->{$volid}, @param);
3260     }
3261 }
3262
3263 sub conf_has_serial {
3264     my ($conf) = @_;
3265
3266     for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++)  {
3267         if ($conf->{"serial$i"}) {
3268             return 1;
3269         }
3270     }
3271
3272     return 0;
3273 }
3274
3275 sub vga_conf_has_spice {
3276     my ($vga) = @_;
3277
3278     my $vgaconf = parse_vga($vga);
3279     my $vgatype = $vgaconf->{type};
3280     return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3281
3282     return $1 || 1;
3283 }
3284
3285 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3286 sub get_host_arch() {
3287     $host_arch = (POSIX::uname())[4] if !$host_arch;
3288     return $host_arch;
3289 }
3290
3291 sub is_native($) {
3292     my ($arch) = @_;
3293     return get_host_arch() eq $arch;
3294 }
3295
3296 my $default_machines = {
3297     x86_64 => 'pc',
3298     aarch64 => 'virt',
3299 };
3300
3301 sub get_basic_machine_info {
3302     my ($conf, $forcemachine) = @_;
3303
3304     my $arch = $conf->{arch} // get_host_arch();
3305     my $machine = $forcemachine || $conf->{machine} || $default_machines->{$arch};
3306     return ($arch, $machine);
3307 }
3308
3309 sub get_ovmf_files($) {
3310     my ($arch) = @_;
3311
3312     my $ovmf = $OVMF->{$arch}
3313         or die "no OVMF images known for architecture '$arch'\n";
3314
3315     return @$ovmf;
3316 }
3317
3318 my $Arch2Qemu = {
3319     aarch64 => '/usr/bin/qemu-system-aarch64',
3320     x86_64 => '/usr/bin/qemu-system-x86_64',
3321 };
3322 sub get_command_for_arch($) {
3323     my ($arch) = @_;
3324     return '/usr/bin/kvm' if is_native($arch);
3325
3326     my $cmd = $Arch2Qemu->{$arch}
3327         or die "don't know how to emulate architecture '$arch'\n";
3328     return $cmd;
3329 }
3330
3331 sub get_cpu_options {
3332     my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3333
3334     my $cpuFlags = [];
3335     my $ostype = $conf->{ostype};
3336
3337     my $cpu = $kvm ? "kvm64" : "qemu64";
3338     if ($arch eq 'aarch64') {
3339         $cpu = 'cortex-a57';
3340     }
3341     my $hv_vendor_id;
3342     if (my $cputype = $conf->{cpu}) {
3343         my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
3344             or die "Cannot parse cpu description: $cputype\n";
3345         $cpu = $cpuconf->{cputype};
3346         $kvm_off = 1 if $cpuconf->{hidden};
3347         $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
3348
3349         if (defined(my $flags = $cpuconf->{flags})) {
3350             push @$cpuFlags, split(";", $flags);
3351         }
3352     }
3353
3354     push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3355
3356     push @$cpuFlags , '-x2apic'
3357         if $conf->{ostype} && $conf->{ostype} eq 'solaris';
3358
3359     push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3360
3361     push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3362
3363     if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3364
3365         push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3366         push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3367     }
3368
3369     add_hyperv_enlightenments($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios}, $gpu_passthrough, $hv_vendor_id) if $kvm;
3370
3371     push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3372
3373     push @$cpuFlags, 'kvm=off' if $kvm_off;
3374
3375     if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3376         push @$cpuFlags, "vendor=${cpu_vendor}"
3377             if $cpu_vendor ne 'default';
3378     } elsif ($arch ne 'aarch64') {
3379         die "internal error"; # should not happen
3380     }
3381
3382     $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3383
3384     return ('-cpu', $cpu);
3385 }
3386
3387 sub config_to_command {
3388     my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3389
3390     my $cmd = [];
3391     my $globalFlags = [];
3392     my $machineFlags = [];
3393     my $rtcFlags = [];
3394     my $devices = [];
3395     my $pciaddr = '';
3396     my $bridges = {};
3397     my $kvmver = kvm_user_version();
3398     my $vernum = 0; # unknown
3399     my $ostype = $conf->{ostype};
3400     my $winversion = windows_version($ostype);
3401     my $kvm = $conf->{kvm};
3402
3403     my ($arch, $machine_type) = get_basic_machine_info($conf, $forcemachine);
3404     $kvm //= 1 if is_native($arch);
3405
3406     if ($kvm) {
3407         die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3408             if !defined kvm_version();
3409     }
3410
3411     if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3412         $vernum = $1*1000000+$2*1000;
3413     } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3414         $vernum = $1*1000000+$2*1000+$3;
3415     }
3416
3417     die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3418
3419     my $have_ovz = -f '/proc/vz/vestat';
3420
3421     my $q35 = machine_type_is_q35($conf);
3422     my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
3423     my $use_old_bios_files = undef;
3424     ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
3425
3426     my $cpuunits = defined($conf->{cpuunits}) ?
3427             $conf->{cpuunits} : $defaults->{cpuunits};
3428
3429     push @$cmd, get_command_for_arch($arch);
3430
3431     push @$cmd, '-id', $vmid;
3432
3433     my $vmname = $conf->{name} || "vm$vmid";
3434
3435     push @$cmd, '-name', $vmname;
3436
3437     my $use_virtio = 0;
3438
3439     my $qmpsocket = qmp_socket($vmid);
3440     push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3441     push @$cmd, '-mon', "chardev=qmp,mode=control";
3442
3443     if (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 12)) {
3444         push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3445         push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3446     }
3447
3448     push @$cmd, '-pidfile' , pidfile_name($vmid);
3449
3450     push @$cmd, '-daemonize';
3451
3452     if ($conf->{smbios1}) {
3453         push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3454     }
3455
3456     if ($conf->{vmgenid}) {
3457         push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid};
3458     }
3459
3460     my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch);
3461     if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
3462         die "uefi base image not found\n" if ! -f $ovmf_code;
3463
3464         my $path;
3465         my $format;
3466         if (my $efidisk = $conf->{efidisk0}) {
3467             my $d = PVE::JSONSchema::parse_property_string($efidisk_fmt, $efidisk);
3468             my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
3469             $format = $d->{format};
3470             if ($storeid) {
3471                 $path = PVE::Storage::path($storecfg, $d->{file});
3472                 if (!defined($format)) {
3473                     my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
3474                     $format = qemu_img_format($scfg, $volname);
3475                 }
3476             } else {
3477                 $path = $d->{file};
3478                 die "efidisk format must be specified\n"
3479                     if !defined($format);
3480             }
3481         } else {
3482             warn "no efidisk configured! Using temporary efivars disk.\n";
3483             $path = "/tmp/$vmid-ovmf.fd";
3484             PVE::Tools::file_copy($ovmf_vars, $path, -s $ovmf_vars);
3485             $format = 'raw';
3486         }
3487
3488         push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3489         push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3490     }
3491
3492
3493     # add usb controllers
3494     my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
3495     push @$devices, @usbcontrollers if @usbcontrollers;
3496     my $vga = parse_vga($conf->{vga});
3497
3498     my $qxlnum = vga_conf_has_spice($conf->{vga});
3499     $vga->{type} = 'qxl' if $qxlnum;
3500
3501     if (!$vga->{type}) {
3502         if ($arch eq 'aarch64') {
3503             $vga->{type} = 'virtio';
3504         } elsif (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 9)) {
3505             $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
3506         } else {
3507             $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
3508         }
3509     }
3510
3511     # enable absolute mouse coordinates (needed by vnc)
3512     my $tablet;
3513     if (defined($conf->{tablet})) {
3514         $tablet = $conf->{tablet};
3515     } else {
3516         $tablet = $defaults->{tablet};
3517         $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3518         $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3519     }
3520
3521     if ($tablet) {
3522         push @$devices, '-device', print_tabletdevice_full($conf, $arch) if $tablet;
3523         my $kbd = print_keyboarddevice_full($conf, $arch);
3524         push @$devices, '-device', $kbd if defined($kbd);
3525     }
3526
3527     my $kvm_off = 0;
3528     my $gpu_passthrough;
3529
3530     # host pci devices
3531     for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
3532         my $d = parse_hostpci($conf->{"hostpci$i"});
3533         next if !$d;
3534
3535         my $pcie = $d->{pcie};
3536         if($pcie){
3537             die "q35 machine model is not enabled" if !$q35;
3538             # win7 wants to have the pcie devices directly on the pcie bus
3539             # instead of in the root port
3540             if ($winversion == 7) {
3541                 $pciaddr = print_pcie_addr("hostpci${i}bus0");
3542             } else {
3543                 $pciaddr = print_pcie_addr("hostpci$i");
3544             }
3545         }else{
3546             $pciaddr = print_pci_addr("hostpci$i", $bridges, $arch, $machine_type);
3547         }
3548
3549         my $rombar = defined($d->{rombar}) && !$d->{rombar} ? ',rombar=0' : '';
3550         my $romfile = $d->{romfile};
3551
3552         my $xvga = '';
3553         if ($d->{'x-vga'}) {
3554             $xvga = ',x-vga=on';
3555             $kvm_off = 1;
3556             $vga->{type} = 'none' if !defined($conf->{vga});
3557             $gpu_passthrough = 1;
3558
3559             if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
3560                 $xvga = "";
3561             }
3562         }
3563         my $pcidevices = $d->{pciid};
3564         my $multifunction = 1 if @$pcidevices > 1;
3565         my $sysfspath;
3566         if ($d->{mdev} && scalar(@$pcidevices) == 1) {
3567             my $id = $pcidevices->[0]->{id};
3568             my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
3569             $sysfspath = "/sys/bus/pci/devices/0000:$id/$uuid";
3570         } elsif ($d->{mdev}) {
3571             warn "ignoring mediated device with multifunction device\n";
3572         }
3573
3574         my $j=0;
3575         foreach my $pcidevice (@$pcidevices) {
3576
3577             my $id = "hostpci$i";
3578             $id .= ".$j" if $multifunction;
3579             my $addr = $pciaddr;
3580             $addr .= ".$j" if $multifunction;
3581             my $devicestr = "vfio-pci";
3582             if ($sysfspath) {
3583                 $devicestr .= ",sysfsdev=$sysfspath";
3584             } else {
3585                 $devicestr .= ",host=$pcidevice->{id}";
3586             }
3587             $devicestr .= ",id=$id$addr";
3588
3589             if($j == 0){
3590                 $devicestr .= "$rombar$xvga";
3591                 $devicestr .= ",multifunction=on" if $multifunction;
3592                 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3593             }
3594
3595             push @$devices, '-device', $devicestr;
3596             $j++;
3597         }
3598     }
3599
3600     # usb devices
3601     my @usbdevices = PVE::QemuServer::USB::get_usb_devices($conf, $usbdesc->{format}, $MAX_USB_DEVICES);
3602     push @$devices, @usbdevices if @usbdevices;
3603     # serial devices
3604     for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++)  {
3605         if (my $path = $conf->{"serial$i"}) {
3606             if ($path eq 'socket') {
3607                 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3608                 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3609                 # On aarch64, serial0 is the UART device. Qemu only allows
3610                 # connecting UART devices via the '-serial' command line, as
3611                 # the device has a fixed slot on the hardware...
3612                 if ($arch eq 'aarch64' && $i == 0) {
3613                     push @$devices, '-serial', "chardev:serial$i";
3614                 } else {
3615                     push @$devices, '-device', "isa-serial,chardev=serial$i";
3616                 }
3617             } else {
3618                 die "no such serial device\n" if ! -c $path;
3619                 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3620                 push @$devices, '-device', "isa-serial,chardev=serial$i";
3621             }
3622         }
3623     }
3624
3625     # parallel devices
3626     for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++)  {
3627         if (my $path = $conf->{"parallel$i"}) {
3628             die "no such parallel device\n" if ! -c $path;
3629             my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
3630             push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3631             push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3632         }
3633     }
3634
3635
3636     my $sockets = 1;
3637     $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3638     $sockets = $conf->{sockets} if  $conf->{sockets};
3639
3640     my $cores = $conf->{cores} || 1;
3641
3642     my $maxcpus = $sockets * $cores;
3643
3644     my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
3645
3646     my $allowed_vcpus = $cpuinfo->{cpus};
3647
3648     die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3649         if ($allowed_vcpus < $maxcpus);
3650
3651     if($hotplug_features->{cpu} && qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 7)) {
3652
3653         push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3654         for (my $i = 2; $i <= $vcpus; $i++)  {
3655             my $cpustr = print_cpu_device($conf,$i);
3656             push @$cmd, '-device', $cpustr;
3657         }
3658
3659     } else {
3660
3661         push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3662     }
3663     push @$cmd, '-nodefaults';
3664
3665     my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
3666
3667     my $bootindex_hash = {};
3668     my $i = 1;
3669     foreach my $o (split(//, $bootorder)) {
3670         $bootindex_hash->{$o} = $i*100;
3671         $i++;
3672     }
3673
3674     push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3675
3676     push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
3677
3678     push @$cmd, '-no-reboot' if  defined($conf->{reboot}) && $conf->{reboot} == 0;
3679
3680     if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
3681         push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3682         my $socket = vnc_socket($vmid);
3683         push @$cmd,  '-vnc', "unix:$socket,x509,password";
3684     } else {
3685         push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
3686         push @$cmd, '-nographic';
3687     }
3688
3689     # time drift fix
3690     my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
3691
3692     my $useLocaltime = $conf->{localtime};
3693
3694     if ($winversion >= 5) { # windows
3695         $useLocaltime = 1 if !defined($conf->{localtime});
3696
3697         # use time drift fix when acpi is enabled
3698         if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3699             $tdf = 1 if !defined($conf->{tdf});
3700         }
3701     }
3702
3703     if ($winversion >= 6) {
3704         push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3705         push @$cmd, '-no-hpet';
3706     }
3707
3708     push @$rtcFlags, 'driftfix=slew' if $tdf;
3709
3710     if (!$kvm) {
3711         push @$machineFlags, 'accel=tcg';
3712     }
3713
3714     if ($machine_type) {