]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
Simplify schema for serial/parallel options (use pattern)
[qemu-server.git] / PVE / QemuServer.pm
CommitLineData
1e3baf05
DM
1package PVE::QemuServer;
2
3use strict;
4use POSIX;
5use IO::Handle;
6use IO::Select;
7use IO::File;
8use IO::Dir;
9use IO::Socket::UNIX;
10use File::Basename;
11use File::Path;
12use File::stat;
13use Getopt::Long;
14use Digest::SHA1;
15use Fcntl ':flock';
16use Cwd 'abs_path';
17use IPC::Open3;
18use Fcntl;
19use PVE::SafeSyslog;
20use Storable qw(dclone);
21use PVE::Exception qw(raise raise_param_exc);
22use PVE::Storage;
23use PVE::Tools qw(run_command lock_file file_read_firstline);
24use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
25use PVE::INotify;
26use PVE::ProcFSTools;
27use Time::HiRes qw (gettimeofday);
28
29my $clock_ticks = POSIX::sysconf(&POSIX::_SC_CLK_TCK);
30
31# Note about locking: we use flock on the config file protect
32# against concurent actions.
33# Aditionaly, we have a 'lock' setting in the config file. This
34# can be set to 'migrate' or 'backup'. Most actions are not
35# allowed when such lock is set. But you can ignore this kind of
36# lock with the --skiplock flag.
37
38cfs_register_file('/qemu-server/', \&parse_vm_config);
39
40#no warnings 'redefine';
41
42unless(defined(&_VZSYSCALLS_H_)) {
43 eval 'sub _VZSYSCALLS_H_ () {1;}' unless defined(&_VZSYSCALLS_H_);
44 require 'sys/syscall.ph';
45 if(defined(&__x86_64__)) {
46 eval 'sub __NR_fairsched_vcpus () {499;}' unless defined(&__NR_fairsched_vcpus);
47 eval 'sub __NR_fairsched_mknod () {504;}' unless defined(&__NR_fairsched_mknod);
48 eval 'sub __NR_fairsched_rmnod () {505;}' unless defined(&__NR_fairsched_rmnod);
49 eval 'sub __NR_fairsched_chwt () {506;}' unless defined(&__NR_fairsched_chwt);
50 eval 'sub __NR_fairsched_mvpr () {507;}' unless defined(&__NR_fairsched_mvpr);
51 eval 'sub __NR_fairsched_rate () {508;}' unless defined(&__NR_fairsched_rate);
52 eval 'sub __NR_setluid () {501;}' unless defined(&__NR_setluid);
53 eval 'sub __NR_setublimit () {502;}' unless defined(&__NR_setublimit);
54 }
55 elsif(defined( &__i386__) ) {
56 eval 'sub __NR_fairsched_mknod () {500;}' unless defined(&__NR_fairsched_mknod);
57 eval 'sub __NR_fairsched_rmnod () {501;}' unless defined(&__NR_fairsched_rmnod);
58 eval 'sub __NR_fairsched_chwt () {502;}' unless defined(&__NR_fairsched_chwt);
59 eval 'sub __NR_fairsched_mvpr () {503;}' unless defined(&__NR_fairsched_mvpr);
60 eval 'sub __NR_fairsched_rate () {504;}' unless defined(&__NR_fairsched_rate);
61 eval 'sub __NR_fairsched_vcpus () {505;}' unless defined(&__NR_fairsched_vcpus);
62 eval 'sub __NR_setluid () {511;}' unless defined(&__NR_setluid);
63 eval 'sub __NR_setublimit () {512;}' unless defined(&__NR_setublimit);
64 } else {
65 die("no fairsched syscall for this arch");
66 }
67 require 'asm/ioctl.ph';
68 eval 'sub KVM_GET_API_VERSION () { &_IO(0xAE, 0x);}' unless defined(&KVM_GET_API_VERSION);
69}
70
71sub fairsched_mknod {
72 my ($parent, $weight, $desired) = @_;
73
74 return syscall(&__NR_fairsched_mknod, int ($parent), int ($weight), int ($desired));
75}
76
77sub fairsched_rmnod {
78 my ($id) = @_;
79
80 return syscall(&__NR_fairsched_rmnod, int ($id));
81}
82
83sub fairsched_mvpr {
84 my ($pid, $newid) = @_;
85
86 return syscall(&__NR_fairsched_mvpr, int ($pid), int ($newid));
87}
88
89sub fairsched_vcpus {
90 my ($id, $vcpus) = @_;
91
92 return syscall(&__NR_fairsched_vcpus, int ($id), int ($vcpus));
93}
94
95sub fairsched_rate {
96 my ($id, $op, $rate) = @_;
97
98 return syscall(&__NR_fairsched_rate, int ($id), int ($op), int ($rate));
99}
100
101use constant FAIRSCHED_SET_RATE => 0;
102use constant FAIRSCHED_DROP_RATE => 1;
103use constant FAIRSCHED_GET_RATE => 2;
104
105sub fairsched_cpulimit {
106 my ($id, $limit) = @_;
107
108 my $cpulim1024 = int ($limit * 1024 / 100);
109 my $op = $cpulim1024 ? FAIRSCHED_SET_RATE : FAIRSCHED_DROP_RATE;
110
111 return fairsched_rate ($id, $op, $cpulim1024);
112}
113
114my $nodename = PVE::INotify::nodename();
115
116mkdir "/etc/pve/nodes/$nodename";
117my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
118mkdir $confdir;
119
120my $var_run_tmpdir = "/var/run/qemu-server";
121mkdir $var_run_tmpdir;
122
123my $lock_dir = "/var/lock/qemu-server";
124mkdir $lock_dir;
125
126my $pcisysfs = "/sys/bus/pci";
127
128my $keymaphash = PVE::Tools::kvmkeymaps();
129
130my $confdesc = {
131 onboot => {
132 optional => 1,
133 type => 'boolean',
134 description => "Specifies whether a VM will be started during system bootup.",
135 default => 0,
136 },
137 autostart => {
138 optional => 1,
139 type => 'boolean',
140 description => "Automatic restart after crash (currently ignored).",
141 default => 0,
142 },
143 reboot => {
144 optional => 1,
145 type => 'boolean',
146 description => "Allow reboot. If set to '0' the VM exit on reboot.",
147 default => 1,
148 },
149 lock => {
150 optional => 1,
151 type => 'string',
152 description => "Lock/unlock the VM.",
153 enum => [qw(migrate backup)],
154 },
155 cpulimit => {
156 optional => 1,
157 type => 'integer',
158 description => "Limit of CPU usage in per cent. Note if the computer has 2 CPUs, it has total of 200% CPU time. Value '0' indicates no CPU limit.\n\nNOTE: This option is currently ignored.",
159 minimum => 0,
160 default => 0,
161 },
162 cpuunits => {
163 optional => 1,
164 type => 'integer',
165 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.\n\nNOTE: You can disable fair-scheduler configuration by setting this to 0.",
166 minimum => 0,
167 maximum => 500000,
168 default => 1000,
169 },
170 memory => {
171 optional => 1,
172 type => 'integer',
173 description => "Amount of RAM for the VM in MB.",
174 minimum => 16,
175 default => 512,
176 },
177 keyboard => {
178 optional => 1,
179 type => 'string',
180 description => "Keybord layout for vnc server. Default is read from the datacenter configuration file.",
181 enum => [ keys %$keymaphash ],
182 default => 'en-us',
183 },
184 name => {
185 optional => 1,
186 type => 'string',
187 description => "Set a name for the VM. Only used on the configuration web interface.",
188 },
189 description => {
190 optional => 1,
191 type => 'string',
192 description => "Description for the VM. Only used on the configuration web interface.",
193 },
194 ostype => {
195 optional => 1,
196 type => 'string',
197 enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 l24 l26)],
198 description => <<EODESC,
199Used to enable special optimization/features for specific
200operating systems:
201
202other => unspecified OS
203wxp => Microsoft Windows XP
204w2k => Microsoft Windows 2000
205w2k3 => Microsoft Windows 2003
206w2k8 => Microsoft Windows 2008
207wvista => Microsoft Windows Vista
208win7 => Microsoft Windows 7
209l24 => Linux 2.4 Kernel
210l26 => Linux 2.6/3.X Kernel
211
212other|l24|l26 ... no special behaviour
213wxp|w2k|w2k3|w2k8|wvista|win7 ... use --localtime switch
214EODESC
215 },
216 boot => {
217 optional => 1,
218 type => 'string',
219 description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
220 pattern => '[acdn]{1,4}',
221 default => 'cad',
222 },
223 bootdisk => {
224 optional => 1,
225 type => 'string', format => 'pve-qm-bootdisk',
226 description => "Enable booting from specified disk.",
227 pattern => '(ide|scsi|virtio)\d+',
228 },
229 smp => {
230 optional => 1,
231 type => 'integer',
232 description => "The number of CPUs. Please use option -sockets instead.",
233 minimum => 1,
234 default => 1,
235 },
236 sockets => {
237 optional => 1,
238 type => 'integer',
239 description => "The number of CPU sockets.",
240 minimum => 1,
241 default => 1,
242 },
243 cores => {
244 optional => 1,
245 type => 'integer',
246 description => "The number of cores per socket.",
247 minimum => 1,
248 default => 1,
249 },
250 acpi => {
251 optional => 1,
252 type => 'boolean',
253 description => "Enable/disable ACPI.",
254 default => 1,
255 },
256 kvm => {
257 optional => 1,
258 type => 'boolean',
259 description => "Enable/disable KVM hardware virtualization.",
260 default => 1,
261 },
262 tdf => {
263 optional => 1,
264 type => 'boolean',
265 description => "Enable/disable time drift fix.",
266 default => 1,
267 },
268 localtime => {
269 optional => 1,
270 type => 'boolean',
271 description => "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
272 },
273 freeze => {
274 optional => 1,
275 type => 'boolean',
276 description => "Freeze CPU at startup (use 'c' monitor command to start execution).",
277 },
278 vga => {
279 optional => 1,
280 type => 'string',
281 description => "Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'. Default is 'std' for win7/w2k8, and 'cirrur' for other OS types",
282 enum => [qw(std cirrus vmware)],
283 },
0ea9541d
DM
284 watchdog => {
285 optional => 1,
286 type => 'string', format => 'pve-qm-watchdog',
287 typetext => '[[model=]i6300esb|ib700] [,[action=]reset|shutdown|poweroff|pause|debug|none]',
288 description => "Create a virtual hardware watchdog device. Once enabled (by a guest action), the watchdog must be periodically polled by an agent inside the guest or else the guest will be restarted (or execute the action specified)",
289 },
1e3baf05
DM
290 startdate => {
291 optional => 1,
292 type => 'string',
293 typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
294 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'.",
295 pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
296 default => 'now',
297 },
298 args => {
299 optional => 1,
300 type => 'string',
301 description => <<EODESCR,
302Note: this option is for experts only. It allows you to pass arbitrary arguments to kvm, for example:
303
304args: -no-reboot -no-hpet
305EODESCR
306 },
307 tablet => {
308 optional => 1,
309 type => 'boolean',
310 default => 1,
311 description => "Enable/disable the usb tablet device. This device is usually needed to allow absolute mouse positioning. Else the mouse runs out of sync with normal vnc clients. If you're running lots of console-only guests on one host, you may consider disabling this to save some context switches.",
312 },
313 migrate_speed => {
314 optional => 1,
315 type => 'integer',
316 description => "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
317 minimum => 0,
318 default => 0,
319 },
320 migrate_downtime => {
321 optional => 1,
322 type => 'integer',
323 description => "Set maximum tolerated downtime (in seconds) for migrations.",
324 minimum => 0,
325 default => 1,
326 },
327 cdrom => {
328 optional => 1,
329 type => 'string', format => 'pve-qm-drive',
330 typetext => 'volume',
331 description => "This is an alias for option -ide2",
332 },
333 cpu => {
334 optional => 1,
335 description => "Emulated CPU type.",
336 type => 'string',
337 enum => [ qw(486 athlon pentium pentium2 pentium3 coreduo core2duo kvm32 kvm64 qemu32 qemu64 phenom host) ],
338 default => 'qemu64',
339 },
340};
341
342# what about other qemu settings ?
343#cpu => 'string',
344#machine => 'string',
345#fda => 'file',
346#fdb => 'file',
347#mtdblock => 'file',
348#sd => 'file',
349#pflash => 'file',
350#snapshot => 'bool',
351#bootp => 'file',
352##tftp => 'dir',
353##smb => 'dir',
354#kernel => 'file',
355#append => 'string',
356#initrd => 'file',
357##soundhw => 'string',
358
359while (my ($k, $v) = each %$confdesc) {
360 PVE::JSONSchema::register_standard_option("pve-qm-$k", $v);
361}
362
363my $MAX_IDE_DISKS = 4;
f62db2a4
DA
364my $MAX_SCSI_DISKS = 14;
365my $MAX_VIRTIO_DISKS = 6;
1e3baf05 366my $MAX_USB_DEVICES = 5;
f62db2a4 367my $MAX_NETS = 6;
1e3baf05 368my $MAX_UNUSED_DISKS = 8;
040b06b7 369my $MAX_HOSTPCI_DEVICES = 2;
bae179aa 370my $MAX_SERIAL_PORTS = 4;
1989a89c 371my $MAX_PARALLEL_PORTS = 3;
1e3baf05
DM
372
373my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
374 'ne2k_isa', 'i82551', 'i82557b', 'i82559er'];
375my $nic_model_list_txt = join (' ', sort @$nic_model_list);
376
377# fixme:
378my $netdesc = {
379 optional => 1,
380 type => 'string', format => 'pve-qm-net',
381 typetext => "MODEL=XX:XX:XX:XX:XX:XX [,bridge=<dev>][,rate=<mbps>]",
382 description => <<EODESCR,
383Specify network devices.
384
385MODEL is one of: $nic_model_list_txt
386
387XX:XX:XX:XX:XX:XX should be an unique MAC address. This is
388automatically generated if not specified.
389
390The bridge parameter can be used to automatically add the interface to a bridge device. The Proxmox VE standard bridge is called 'vmbr0'.
391
392Option 'rate' is used to limit traffic bandwidth from and to this interface. It is specified as floating point number, unit is 'Megabytes per second'.
393
394If you specify no bridge, we create a kvm 'user' (NATed) network device, which provides DHCP and DNS services. The following addresses are used:
395
39610.0.2.2 Gateway
39710.0.2.3 DNS Server
39810.0.2.4 SMB Server
399
400The DHCP server assign addresses to the guest starting from 10.0.2.15.
401
402EODESCR
403};
404PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
405
406for (my $i = 0; $i < $MAX_NETS; $i++) {
407 $confdesc->{"net$i"} = $netdesc;
408}
409
410my $drivename_hash;
411
412my $idedesc = {
413 optional => 1,
414 type => 'string', format => 'pve-qm-drive',
415 typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback] [,format=f] [,backup=yes|no] [,aio=native|threads]',
416 description => "Use volume as IDE hard disk or CD-ROM (n is 0 to 3).",
417};
418PVE::JSONSchema::register_standard_option("pve-qm-ide", $idedesc);
419
420my $scsidesc = {
421 optional => 1,
422 type => 'string', format => 'pve-qm-drive',
423 typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback] [,format=f] [,backup=yes|no] [,aio=native|threads]',
2fe1a152 424 description => "Use volume as SCSI hard disk or CD-ROM (n is 0 to 13).",
1e3baf05
DM
425};
426PVE::JSONSchema::register_standard_option("pve-qm-scsi", $scsidesc);
427
428my $virtiodesc = {
429 optional => 1,
430 type => 'string', format => 'pve-qm-drive',
431 typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback] [,format=f] [,backup=yes|no] [,aio=native|threads]',
2fe1a152 432 description => "Use volume as VIRTIO hard disk (n is 0 to 5).",
1e3baf05
DM
433};
434PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc);
435
436my $usbdesc = {
437 optional => 1,
438 type => 'string', format => 'pve-qm-usb-device',
439 typetext => 'host=HOSTUSBDEVICE',
440 description => <<EODESCR,
2fe1a152 441Configure an USB device (n is 0 to 4). This can be used to
1e3baf05
DM
442pass-through usb devices to the guest. HOSTUSBDEVICE syntax is:
443
444'bus-port(.port)*' (decimal numbers) or
445'vendor_id:product_id' (hexadeciaml numbers)
446
447You can use the 'lsusb -t' command to list existing usb devices.
448
449Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
450
451EODESCR
452};
453PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
454
040b06b7
DA
455my $hostpcidesc = {
456 optional => 1,
457 type => 'string', format => 'pve-qm-hostpci',
458 typetext => "HOSTPCIDEVICE",
459 description => <<EODESCR,
460Map host pci devices. HOSTPCIDEVICE syntax is:
461
462'bus:dev.func' (hexadecimal numbers)
463
464You can us the 'lspci' command to list existing pci devices.
465
466Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
467
468Experimental: user reported problems with this option.
469EODESCR
470};
471PVE::JSONSchema::register_standard_option("pve-qm-hostpci", $hostpcidesc);
472
bae179aa
DA
473my $serialdesc = {
474 optional => 1,
475 type => 'string', format => 'pve-qm-serial',
2fe1a152 476 pattern => '/dev/ttyS\d+',
bae179aa 477 description => <<EODESCR,
2fe1a152 478Map host serial devices (n is 0 to 3).
bae179aa
DA
479
480Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
481
482Experimental: user reported problems with this option.
483EODESCR
484};
485PVE::JSONSchema::register_standard_option("pve-qm-serial", $serialdesc);
486
1989a89c
DA
487my $paralleldesc= {
488 optional => 1,
489 type => 'string', format => 'pve-qm-parallel',
2fe1a152 490 pattern => '/dev/parport\d+',
1989a89c 491 description => <<EODESCR,
2fe1a152 492Map host parallel devices (n is 0 to 2).
1989a89c
DA
493
494Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
495
496Experimental: user reported problems with this option.
497EODESCR
498};
499PVE::JSONSchema::register_standard_option("pve-qm-parallel", $paralleldesc);
500
501for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
502 $confdesc->{"parallel$i"} = $paralleldesc;
503}
504
bae179aa
DA
505for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
506 $confdesc->{"serial$i"} = $serialdesc;
507}
508
040b06b7
DA
509for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
510 $confdesc->{"hostpci$i"} = $hostpcidesc;
511}
1e3baf05
DM
512
513for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
514 $drivename_hash->{"ide$i"} = 1;
515 $confdesc->{"ide$i"} = $idedesc;
516}
517
518for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
519 $drivename_hash->{"scsi$i"} = 1;
520 $confdesc->{"scsi$i"} = $scsidesc ;
521}
522
523for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
524 $drivename_hash->{"virtio$i"} = 1;
525 $confdesc->{"virtio$i"} = $virtiodesc;
526}
527
528for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
529 $confdesc->{"usb$i"} = $usbdesc;
530}
531
532my $unuseddesc = {
533 optional => 1,
534 type => 'string', format => 'pve-volume-id',
535 description => "Reference to unused volumes.",
536};
537
538for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
539 $confdesc->{"unused$i"} = $unuseddesc;
540}
541
542my $kvm_api_version = 0;
543
544sub kvm_version {
545
546 return $kvm_api_version if $kvm_api_version;
547
548 my $fh = IO::File->new ("</dev/kvm") ||
549 return 0;
550
551 if (my $v = $fh->ioctl (KVM_GET_API_VERSION(), 0)) {
552 $kvm_api_version = $v;
553 }
554
555 $fh->close();
556
557 return $kvm_api_version;
558}
559
560my $kvm_user_version;
561
562sub kvm_user_version {
563
564 return $kvm_user_version if $kvm_user_version;
565
566 $kvm_user_version = 'unknown';
567
568 my $tmp = `kvm -help 2>/dev/null`;
569
570 if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+\.\d+) /) {
571 $kvm_user_version = $2;
572 }
573
574 return $kvm_user_version;
575
576}
577
578my $kernel_has_vhost_net = -c '/dev/vhost-net';
579
580sub disknames {
581 # order is important - used to autoselect boot disk
582 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
583 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
584 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))));
585}
586
587sub valid_drivename {
588 my $dev = shift;
589
590 return defined ($drivename_hash->{$dev});
591}
592
593sub option_exists {
594 my $key = shift;
595 return defined($confdesc->{$key});
596}
597
598sub nic_models {
599 return $nic_model_list;
600}
601
602sub os_list_description {
603
604 return {
605 other => 'Other',
606 wxp => 'Windows XP',
607 w2k => 'Windows 2000',
608 w2k3 =>, 'Windows 2003',
609 w2k8 => 'Windows 2008',
610 wvista => 'Windows Vista',
611 win7 => 'Windows 7',
612 l24 => 'Linux 2.4',
613 l26 => 'Linux 2.6',
614 };
615}
616
617# a clumsy way to split an argument string into an array,
618# we simply pass it to the cli (exec call)
619# fixme: use Text::ParseWords::shellwords() ?
620sub split_args {
621 my ($str) = @_;
622
623 my $args = [];
624
625 return $args if !$str;
626
627 my $cmd = 'perl -e \'foreach my $a (@ARGV) { print "$a\n"; } \' -- ' . $str;
628
629 eval {
630 run_command ($cmd, outfunc => sub {
631 my $data = shift;
632 push @$args, $data;
633 });
634 };
635
636 my $err = $@;
637
638 die "unable to parse args: $str\n" if $err;
639
640 return $args;
641}
642
643sub disk_devive_info {
644 my $dev = shift;
645
646 die "unknown disk device format '$dev'" if $dev !~ m/^(ide|scsi|virtio)(\d+)$/;
647
648 my $bus = $1;
649 my $index = $2;
650 my $maxdev = 1024;
651
652 if ($bus eq 'ide') {
653 $maxdev = 2;
654 } elsif ($bus eq 'scsi') {
f62db2a4 655 $maxdev = 7;
1e3baf05
DM
656 }
657
658 my $controller = int ($index / $maxdev);
659 my $unit = $index % $maxdev;
660
661
662 return { bus => $bus, desc => uc($bus) . " $controller:$unit",
663 controller => $controller, unit => $unit, index => $index };
664
665}
666
667sub qemu_drive_name {
668 my ($dev, $media) = @_;
669
670 my $info = disk_devive_info ($dev);
671 my $mediastr = '';
672
673 if (($info->{bus} eq 'ide') || ($info->{bus} eq 'scsi')) {
674 $mediastr = ($media eq 'cdrom') ? "-cd" : "-hd";
675 return sprintf("%s%i%s%i", $info->{bus}, $info->{controller},
676 $mediastr, $info->{unit});
677 } else {
678 return sprintf("%s%i", $info->{bus}, $info->{index});
679 }
680}
681
682my $cdrom_path;
683
684sub get_cdrom_path {
685
686 return $cdrom_path if $cdrom_path;
687
688 return $cdrom_path = "/dev/cdrom" if -l "/dev/cdrom";
689 return $cdrom_path = "/dev/cdrom1" if -l "/dev/cdrom1";
690 return $cdrom_path = "/dev/cdrom2" if -l "/dev/cdrom2";
691}
692
693sub get_iso_path {
694 my ($storecfg, $vmid, $cdrom) = @_;
695
696 if ($cdrom eq 'cdrom') {
697 return get_cdrom_path();
698 } elsif ($cdrom eq 'none') {
699 return '';
700 } elsif ($cdrom =~ m|^/|) {
701 return $cdrom;
702 } else {
703 return PVE::Storage::path ($storecfg, $cdrom);
704 }
705}
706
707# try to convert old style file names to volume IDs
708sub filename_to_volume_id {
709 my ($vmid, $file, $media) = @_;
710
711 if (!($file eq 'none' || $file eq 'cdrom' ||
712 $file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
713
714 return undef if $file =~ m|/|;
715
716 if ($media && $media eq 'cdrom') {
717 $file = "local:iso/$file";
718 } else {
719 $file = "local:$vmid/$file";
720 }
721 }
722
723 return $file;
724}
725
726sub verify_media_type {
727 my ($opt, $vtype, $media) = @_;
728
729 return if !$media;
730
731 my $etype;
732 if ($media eq 'disk') {
733 $etype = 'image';
734 } elsif ($media eq 'cdrom') {
735 $etype = 'iso';
736 } else {
737 die "internal error";
738 }
739
740 return if ($vtype eq $etype);
741
742 raise_param_exc({ $opt => "unexpected media type ($vtype != $etype)" });
743}
744
745sub cleanup_drive_path {
746 my ($opt, $storecfg, $drive) = @_;
747
748 # try to convert filesystem paths to volume IDs
749
750 if (($drive->{file} !~ m/^(cdrom|none)$/) &&
751 ($drive->{file} !~ m|^/dev/.+|) &&
752 ($drive->{file} !~ m/^([^:]+):(.+)$/) &&
753 ($drive->{file} !~ m/^\d+$/)) {
754 my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
755 raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
756 $drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
757 verify_media_type($opt, $vtype, $drive->{media});
758 $drive->{file} = $volid;
759 }
760
761 $drive->{media} = 'cdrom' if !$drive->{media} && $drive->{file} =~ m/^(cdrom|none)$/;
762}
763
764sub create_conf_nolock {
765 my ($vmid, $settings) = @_;
766
767 my $filename = config_file ($vmid);
768
769 die "configuration file '$filename' already exists\n" if -f $filename;
770
771 my $defaults = load_defaults();
772
773 $settings->{name} = "vm$vmid" if !$settings->{name};
774 $settings->{memory} = $defaults->{memory} if !$settings->{memory};
775
776 my $data = '';
777 foreach my $opt (keys %$settings) {
778 next if !$confdesc->{$opt};
779
780 my $value = $settings->{$opt};
781 next if !$value;
782
783 $data .= "$opt: $value\n";
784 }
785
786 PVE::Tools::file_set_contents($filename, $data);
787}
788
789# ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
790# [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
791# [,aio=native|threads]
792
793sub parse_drive {
794 my ($key, $data) = @_;
795
796 my $res = {};
797
798 # $key may be undefined - used to verify JSON parameters
799 if (!defined($key)) {
800 $res->{interface} = 'unknown'; # should not harm when used to verify parameters
801 $res->{index} = 0;
802 } elsif ($key =~ m/^([^\d]+)(\d+)$/) {
803 $res->{interface} = $1;
804 $res->{index} = $2;
805 } else {
806 return undef;
807 }
808
809 foreach my $p (split (/,/, $data)) {
810 next if $p =~ m/^\s*$/;
811
812 if ($p =~ m/^(file|volume|cyls|heads|secs|trans|media|snapshot|cache|format|rerror|werror|backup|aio)=(.+)$/) {
813 my ($k, $v) = ($1, $2);
814
815 $k = 'file' if $k eq 'volume';
816
817 return undef if defined $res->{$k};
818
819 $res->{$k} = $v;
820 } else {
821 if (!$res->{file} && $p !~ m/=/) {
822 $res->{file} = $p;
823 } else {
824 return undef;
825 }
826 }
827 }
828
829 return undef if !$res->{file};
830
831 return undef if $res->{cache} &&
832 $res->{cache} !~ m/^(off|none|writethrough|writeback)$/;
833 return undef if $res->{snapshot} && $res->{snapshot} !~ m/^(on|off)$/;
834 return undef if $res->{cyls} && $res->{cyls} !~ m/^\d+$/;
835 return undef if $res->{heads} && $res->{heads} !~ m/^\d+$/;
836 return undef if $res->{secs} && $res->{secs} !~ m/^\d+$/;
837 return undef if $res->{media} && $res->{media} !~ m/^(disk|cdrom)$/;
838 return undef if $res->{trans} && $res->{trans} !~ m/^(none|lba|auto)$/;
839 return undef if $res->{format} && $res->{format} !~ m/^(raw|cow|qcow|qcow2|vmdk|cloop)$/;
840 return undef if $res->{rerror} && $res->{rerror} !~ m/^(ignore|report|stop)$/;
841 return undef if $res->{werror} && $res->{werror} !~ m/^(enospc|ignore|report|stop)$/;
842 return undef if $res->{backup} && $res->{backup} !~ m/^(yes|no)$/;
843 return undef if $res->{aio} && $res->{aio} !~ m/^(native|threads)$/;
844
845 if ($res->{media} && ($res->{media} eq 'cdrom')) {
846 return undef if $res->{snapshot} || $res->{trans} || $res->{format};
847 return undef if $res->{heads} || $res->{secs} || $res->{cyls};
848 return undef if $res->{interface} eq 'virtio';
849 }
850
851 # rerror does not work with scsi drives
852 if ($res->{rerror}) {
853 return undef if $res->{interface} eq 'scsi';
854 }
855
856 return $res;
857}
858
859my @qemu_drive_options = qw(heads secs cyls trans media format cache snapshot rerror werror aio);
860
861sub print_drive {
862 my ($vmid, $drive) = @_;
863
864 my $opts = '';
865 foreach my $o (@qemu_drive_options, 'backup') {
866 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
867 }
868
869 return "$drive->{file}$opts";
870}
871
ca916ecc
DA
872sub print_drivedevice_full {
873 my ($storecfg, $vmid, $drive) = @_;
874
875 my $device = '';
876 my $maxdev = 0;
877
878 if ($drive->{interface} eq 'virtio') {
879
880 $device="virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=device-$drive->{interface}$drive->{index}";
881 }
882
883 elsif ($drive->{interface} eq 'scsi') {
884
885 $maxdev = 7;
886 my $controller = int ($drive->{index} / $maxdev);
887 my $unit = $drive->{index} % $maxdev;
888
889 $device="scsi-disk,bus=scsi$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=device-$drive->{interface}$drive->{index}";
890 }
891
892 elsif ($drive->{interface} eq 'ide'){
893
894 $maxdev = 2;
895 my $controller = int ($drive->{index} / $maxdev);
896 my $unit = $drive->{index} % $maxdev;
897
898 $device="ide-drive,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=device-$drive->{interface}$drive->{index}";
899 }
900
901 if ($drive->{interface} eq 'usb'){
902 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
903 }
904
905 return $device;
906}
907
1e3baf05
DM
908sub print_drive_full {
909 my ($storecfg, $vmid, $drive) = @_;
910
911 my $opts = '';
912 foreach my $o (@qemu_drive_options) {
913 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
914 }
915
916 # use linux-aio by default (qemu default is threads)
917 $opts .= ",aio=native" if !$drive->{aio};
918
919 my $path;
920 my $volid = $drive->{file};
921 if (drive_is_cdrom ($drive)) {
922 $path = get_iso_path ($storecfg, $vmid, $volid);
923 } else {
924 if ($volid =~ m|^/|) {
925 $path = $volid;
926 } else {
927 $path = PVE::Storage::path ($storecfg, $volid);
928 }
929 }
930
931 my $pathinfo = $path ? "file=$path," : '';
932
3ebfcc86 933 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1e3baf05
DM
934}
935
936
937sub drive_is_cdrom {
938 my ($drive) = @_;
939
940 return $drive && $drive->{media} && ($drive->{media} eq 'cdrom');
941
942}
943
040b06b7
DA
944sub parse_hostpci {
945 my ($value) = @_;
946
947 return undef if !$value;
948
949 my $res = {};
950
951 if ($value =~ m/^[a-f0-9]{2}:[a-f0-9]{2}\.[a-f0-9]$/) {
952 $res->{pciid} = $value;
953 } else {
954 return undef;
955 }
956
957 return $res;
958}
959
1e3baf05
DM
960# netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
961sub parse_net {
962 my ($data) = @_;
963
964 my $res = {};
965
966 foreach my $kvp (split (/,/, $data)) {
967
968 if ($kvp =~ m/^(ne2k_pci|e1000|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i) {
969 my $model = lc ($1);
970 my $mac = uc($3) || random_ether_addr ();
971 $res->{model} = $model;
972 $res->{macaddr} = $mac;
973 } elsif ($kvp =~ m/^bridge=(\S+)$/) {
974 $res->{bridge} = $1;
975 } elsif ($kvp =~ m/^rate=(\d+(\.\d+)?)$/) {
976 $res->{rate} = $1;
977 } else {
978 return undef;
979 }
980
981 }
982
983 return undef if !$res->{model};
984
985 return $res;
986}
987
988sub print_net {
989 my $net = shift;
990
991 my $res = "$net->{model}";
992 $res .= "=$net->{macaddr}" if $net->{macaddr};
993 $res .= ",bridge=$net->{bridge}" if $net->{bridge};
994 $res .= ",rate=$net->{rate}" if $net->{rate};
995
996 return $res;
997}
998
999sub add_random_macs {
1000 my ($settings) = @_;
1001
1002 foreach my $opt (keys %$settings) {
1003 next if $opt !~ m/^net(\d+)$/;
1004 my $net = parse_net($settings->{$opt});
1005 next if !$net;
1006 $settings->{$opt} = print_net($net);
1007 }
1008}
1009
1010sub add_unused_volume {
1011 my ($config, $res, $volid) = @_;
1012
1013 my $key;
1014 for (my $ind = $MAX_UNUSED_DISKS - 1; $ind >= 0; $ind--) {
1015 my $test = "unused$ind";
1016 if (my $vid = $config->{$test}) {
1017 return if $vid eq $volid; # do not add duplicates
1018 } else {
1019 $key = $test;
1020 }
1021 }
1022
1023 die "To many unused volume - please delete them first.\n" if !$key;
1024
1025 $res->{$key} = $volid;
1026}
1027
1028# fixme: remove all thos $noerr parameters?
1029
1030PVE::JSONSchema::register_format('pve-qm-bootdisk', \&verify_bootdisk);
1031sub verify_bootdisk {
1032 my ($value, $noerr) = @_;
1033
1034 return $value if valid_drivename($value);
1035
1036 return undef if $noerr;
1037
1038 die "invalid boot disk '$value'\n";
1039}
1040
1041PVE::JSONSchema::register_format('pve-qm-net', \&verify_net);
1042sub verify_net {
1043 my ($value, $noerr) = @_;
1044
1045 return $value if parse_net($value);
1046
1047 return undef if $noerr;
1048
1049 die "unable to parse network options\n";
1050}
1051
1052PVE::JSONSchema::register_format('pve-qm-drive', \&verify_drive);
1053sub verify_drive {
1054 my ($value, $noerr) = @_;
1055
1056 return $value if parse_drive (undef, $value);
1057
1058 return undef if $noerr;
1059
1060 die "unable to parse drive options\n";
1061}
1062
1063PVE::JSONSchema::register_format('pve-qm-hostpci', \&verify_hostpci);
1064sub verify_hostpci {
1065 my ($value, $noerr) = @_;
1066
040b06b7
DA
1067 return $value if parse_hostpci($value);
1068
1069 return undef if $noerr;
1070
1071 die "unable to parse pci id\n";
1e3baf05
DM
1072}
1073
0ea9541d
DM
1074PVE::JSONSchema::register_format('pve-qm-watchdog', \&verify_watchdog);
1075sub verify_watchdog {
1076 my ($value, $noerr) = @_;
1077
1078 return $value if parse_watchdog($value);
1079
1080 return undef if $noerr;
1081
1082 die "unable to parse watchdog options\n";
1083}
1084
1085sub parse_watchdog {
1086 my ($value) = @_;
1087
1088 return undef if !$value;
1089
1090 my $res = {};
1091
1092 foreach my $p (split (/,/, $value)) {
1093 next if $p =~ m/^\s*$/;
1094
1095 if ($p =~ m/^(model=)?(i6300esb|ib700)$/) {
1096 $res->{model} = $2;
1097 } elsif ($p =~ m/^(action=)?(reset|shutdown|poweroff|pause|debug|none)$/) {
1098 $res->{action} = $2;
1099 } else {
1100 return undef;
1101 }
1102 }
1103
1104 return $res;
1105}
1106
1e3baf05
DM
1107sub parse_usb_device {
1108 my ($value) = @_;
1109
1110 return undef if !$value;
1111
1112 my @dl = split (/,/, $value);
1113 my $found;
1114
1115 my $res = {};
1116 foreach my $v (@dl) {
1117 if ($v =~ m/^host=([0-9A-Fa-f]{4}):([0-9A-Fa-f]{4})$/) {
1118 $found = 1;
1119 $res->{vendorid} = $1;
1120 $res->{productid} = $2;
1121 } elsif ($v =~ m/^host=(\d+)\-(\d+(\.\d+)*)$/) {
1122 $found = 1;
1123 $res->{hostbus} = $1;
1124 $res->{hostport} = $2;
1125 } else {
1126 return undef;
1127 }
1128 }
1129 return undef if !$found;
1130
1131 return $res;
1132}
1133
1134PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
1135sub verify_usb_device {
1136 my ($value, $noerr) = @_;
1137
1138 return $value if parse_usb_device($value);
1139
1140 return undef if $noerr;
1141
1142 die "unable to parse usb device\n";
1143}
1144
1145PVE::JSONSchema::register_format('pve-qm-parallel', \&verify_parallel);
1146sub verify_parallel {
1147 my ($value, $noerr) = @_;
1148
1989a89c
DA
1149 return $value if parse_parallel($value);
1150
1151 return undef if $noerr;
1152
1153 die "invalid device name\n";
1154}
1155
1156sub parse_parallel {
1157 my ($value) = @_;
1158
1159 return undef if !$value;
1160
1161 my $res = {};
1162 if ($value =~ m|^/dev/parport\d+$|) {
1163 $res->{dev} = $value;
1164 } else {
1165 return undef;
1e3baf05 1166 }
1989a89c
DA
1167
1168 return $res;
1e3baf05
DM
1169}
1170
1171PVE::JSONSchema::register_format('pve-qm-serial', \&verify_serial);
1172sub verify_serial {
1173 my ($value, $noerr) = @_;
1174
bae179aa
DA
1175 return $value if parse_serial($value);
1176
1177 return undef if $noerr;
1178
1179 die "invalid device name\n";
1180
1181}
1182
1183sub parse_serial {
1184 my ($value) = @_;
1185
1186 return undef if !$value;
1187
1188 my $res = {};
1189 if ($value =~ m|^/dev/ttyS\d+$|) {
1190 $res->{dev} = $value;
1191 } else {
1192 return undef;
1e3baf05 1193 }
bae179aa
DA
1194
1195 return $res;
1e3baf05
DM
1196}
1197
1198# add JSON properties for create and set function
1199sub json_config_properties {
1200 my $prop = shift;
1201
1202 foreach my $opt (keys %$confdesc) {
1203 $prop->{$opt} = $confdesc->{$opt};
1204 }
1205
1206 return $prop;
1207}
1208
1209sub check_type {
1210 my ($key, $value) = @_;
1211
1212 die "unknown setting '$key'\n" if !$confdesc->{$key};
1213
1214 my $type = $confdesc->{$key}->{type};
1215
1216 if (!defined ($value)) {
1217 die "got undefined value\n";
1218 }
1219
1220 if ($value =~ m/[\n\r]/) {
1221 die "property contains a line feed\n";
1222 }
1223
1224 if ($type eq 'boolean') {
1225 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
1226 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
1227 die "type check ('boolean') failed - got '$value'\n";
1228 } elsif ($type eq 'integer') {
1229 return int($1) if $value =~ m/^(\d+)$/;
1230 die "type check ('integer') failed - got '$value'\n";
1231 } elsif ($type eq 'string') {
1232 if (my $fmt = $confdesc->{$key}->{format}) {
1233 if ($fmt eq 'pve-qm-drive') {
1234 # special case - we need to pass $key to parse_drive()
1235 my $drive = parse_drive ($key, $value);
1236 return $value if $drive;
1237 die "unable to parse drive options\n";
1238 }
1239 PVE::JSONSchema::check_format($fmt, $value);
1240 return $value;
1241 }
1242 $value =~ s/^\"(.*)\"$/$1/;
1243 return $value;
1244 } else {
1245 die "internal error"
1246 }
1247}
1248
1249sub lock_config {
1250 my ($vmid, $code, @param) = @_;
1251
1252 my $filename = config_file_lock ($vmid);
1253
1254 lock_file($filename, 10, $code, @param);
1255
1256 die $@ if $@;
1257}
1258
1259sub cfs_config_path {
a78ccf26 1260 my ($vmid, $node) = @_;
1e3baf05 1261
a78ccf26
DM
1262 $node = $nodename if !$node;
1263 return "nodes/$node/qemu-server/$vmid.conf";
1e3baf05
DM
1264}
1265
040b06b7
DA
1266sub check_iommu_support{
1267 #fixme : need to check IOMMU support
1268 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
1269
1270 my $iommu=1;
1271 return $iommu;
1272
1273}
1274
1e3baf05 1275sub config_file {
a78ccf26 1276 my ($vmid, $node) = @_;
1e3baf05 1277
a78ccf26 1278 my $cfspath = cfs_config_path($vmid, $node);
1e3baf05
DM
1279 return "/etc/pve/$cfspath";
1280}
1281
1282sub config_file_lock {
1283 my ($vmid) = @_;
1284
1285 return "$lock_dir/lock-$vmid.conf";
1286}
1287
1288sub touch_config {
1289 my ($vmid) = @_;
1290
1291 my $conf = config_file ($vmid);
1292 utime undef, undef, $conf;
1293}
1294
1295sub create_disks {
1296 my ($storecfg, $vmid, $settings) = @_;
1297
1298 my $vollist = [];
1299
1300 eval {
1301 foreach_drive($settings, sub {
1302 my ($ds, $disk) = @_;
1303
1304 return if drive_is_cdrom ($disk);
1305
1306 my $file = $disk->{file};
1307
1308 if ($file =~ m/^(([^:\s]+):)?(\d+(\.\d+)?)$/) {
1309 my $storeid = $2 || 'local';
1310 my $size = $3;
1311 my $defformat = PVE::Storage::storage_default_format ($storecfg, $storeid);
1312 my $fmt = $disk->{format} || $defformat;
1313 syslog ('info', "VM $vmid creating new disk - size is $size GB");
1314
1315 my $volid = PVE::Storage::vdisk_alloc ($storecfg, $storeid, $vmid,
1316 $fmt, undef, $size*1024*1024);
1317
1318 $disk->{file} = $volid;
1319 delete ($disk->{format}); # no longer needed
1320 push @$vollist, $volid;
1321 $settings->{$ds} = PVE::QemuServer::print_drive ($vmid, $disk);
1322 } else {
1323 my $path;
1324 if ($disk->{file} =~ m|^/dev/.+|) {
1325 $path = $disk->{file};
1326 } else {
1327 $path = PVE::Storage::path ($storecfg, $disk->{file});
1328 }
1329 if (!(-f $path || -b $path)) {
1330 die "image '$path' does not exists\n";
1331 }
1332 }
1333 });
1334 };
1335
1336 my $err = $@;
1337
1338 if ($err) {
1339 syslog ('err', "VM $vmid creating disks failed");
1340 foreach my $volid (@$vollist) {
1341 eval { PVE::Storage::vdisk_free ($storecfg, $volid); };
1342 warn $@ if $@;
1343 }
1344 die $err;
1345 }
1346
1347 return $vollist;
1348}
1349
1350sub unlink_image {
1351 my ($storecfg, $vmid, $volid) = @_;
1352
1353 die "reject to unlink absolute path '$volid'"
1354 if $volid =~ m|^/|;
1355
1356 my ($path, $owner) = PVE::Storage::path ($storecfg, $volid);
1357
1358 die "reject to unlink '$volid' - not owned by this VM"
1359 if !$owner || ($owner != $vmid);
1360
1361 syslog ('info', "VM $vmid deleting volume '$volid'");
1362
1363 PVE::Storage::vdisk_free ($storecfg, $volid);
1364
1365 touch_config ($vmid);
1366}
1367
1368sub destroy_vm {
1369 my ($storecfg, $vmid) = @_;
1370
1371 my $conffile = config_file ($vmid);
1372
1373 my $conf = load_config ($vmid);
1374
1375 check_lock ($conf);
1376
1377 # only remove disks owned by this VM
1378 foreach_drive($conf, sub {
1379 my ($ds, $drive) = @_;
1380
1381 return if drive_is_cdrom ($drive);
1382
1383 my $volid = $drive->{file};
1384 next if !$volid || $volid =~ m|^/|;
1385
1386 my ($path, $owner) = PVE::Storage::path ($storecfg, $volid);
1387 next if !$path || !$owner || ($owner != $vmid);
1388
1389 PVE::Storage::vdisk_free ($storecfg, $volid);
1390 });
1391
1392 unlink $conffile;
1393
1394 # also remove unused disk
1395 eval {
1396 my $dl = PVE::Storage::vdisk_list ($storecfg, undef, $vmid);
1397
1398 eval {
1399 PVE::Storage::foreach_volid ($dl, sub {
1400 my ($volid, $sid, $volname, $d) = @_;
1401 PVE::Storage::vdisk_free ($storecfg, $volid);
1402 });
1403 };
1404 warn $@ if $@;
1405
1406 };
1407 warn $@ if $@;
1408}
1409
1410# fixme: remove?
1411sub load_diskinfo_old {
1412 my ($storecfg, $vmid, $conf) = @_;
1413
1414 my $info = {};
1415 my $res = {};
1416 my $vollist;
1417
1418 foreach_drive($conf, sub {
1419 my ($ds, $di) = @_;
1420
1421 $res->{$ds} = $di;
1422
1423 return if drive_is_cdrom ($di);
1424
1425 if ($di->{file} =~ m|^/dev/.+|) {
1426 $info->{$di->{file}}->{size} = PVE::Storage::file_size_info ($di->{file});
1427 } else {
1428 push @$vollist, $di->{file};
1429 }
1430 });
1431
1432 eval {
1433 my $dl = PVE::Storage::vdisk_list ($storecfg, undef, $vmid, $vollist);
1434
1435 PVE::Storage::foreach_volid ($dl, sub {
1436 my ($volid, $sid, $volname, $d) = @_;
1437 $info->{$volid} = $d;
1438 });
1439 };
1440 warn $@ if $@;
1441
1442 foreach my $ds (keys %$res) {
1443 my $di = $res->{$ds};
1444
1445 $res->{$ds}->{disksize} = $info->{$di->{file}} ?
1446 $info->{$di->{file}}->{size} / (1024*1024) : 0;
1447 }
1448
1449 return $res;
1450}
1451
1452sub load_config {
1453 my ($vmid) = @_;
1454
1455 my $cfspath = cfs_config_path($vmid);
1456
1457 my $conf = PVE::Cluster::cfs_read_file($cfspath);
1458
1459 die "no such VM ('$vmid')\n" if !defined($conf);
1460
1461 return $conf;
1462}
1463
1464sub parse_vm_config {
1465 my ($filename, $raw) = @_;
1466
1467 return undef if !defined($raw);
1468
554ac7e7
DM
1469 my $res = {
1470 digest => Digest::SHA1::sha1_hex($raw),
1471 };
1e3baf05
DM
1472
1473 $filename =~ m|/qemu-server/(\d+)\.conf$|
1474 || die "got strange filename '$filename'";
1475
1476 my $vmid = $1;
1477
1478 while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
1479 my $line = $1;
1480
1481 next if $line =~ m/^\#/;
1482
1483 next if $line =~ m/^\s*$/;
1484
1485 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
1486 my $key = $1;
1487 my $value = PVE::Tools::decode_text($2);
1488 $res->{$key} = $value;
1489 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
1490 my $key = $1;
1491 my $value = $2;
1492 $res->{$key} = $value;
1493 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
1494 my $key = $1;
1495 my $value = $2;
1496 eval { $value = check_type($key, $value); };
1497 if ($@) {
1498 warn "vm $vmid - unable to parse value of '$key' - $@";
1499 } else {
1500 my $fmt = $confdesc->{$key}->{format};
1501 if ($fmt && $fmt eq 'pve-qm-drive') {
1502 my $v = parse_drive($key, $value);
1503 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
1504 $v->{file} = $volid;
1505 $value = print_drive ($vmid, $v);
1506 } else {
1507 warn "vm $vmid - unable to parse value of '$key'\n";
1508 next;
1509 }
1510 }
1511
1512 if ($key eq 'cdrom') {
1513 $res->{ide2} = $value;
1514 } else {
1515 $res->{$key} = $value;
1516 }
1517 }
1518 }
1519 }
1520
1521 # convert old smp to sockets
1522 if ($res->{smp} && !$res->{sockets}) {
1523 $res->{sockets} = $res->{smp};
1524 }
1525 delete $res->{smp};
1526
1527 return $res;
1528}
1529
1530sub change_config {
1531 my ($vmid, $settings, $unset, $skiplock) = @_;
1532
1533 lock_config ($vmid, &change_config_nolock, $settings, $unset, $skiplock);
1534}
1535
1536sub change_config_nolock {
1537 my ($vmid, $settings, $unset, $skiplock) = @_;
1538
1539 my $res = {};
1540
1541 $unset->{ide2} = $unset->{cdrom} if $unset->{cdrom};
1542
1543 check_lock($settings) if !$skiplock;
1544
1545 # we do not use 'smp' any longer
1546 if ($settings->{sockets}) {
1547 $unset->{smp} = 1;
1548 } elsif ($settings->{smp}) {
1549 $settings->{sockets} = $settings->{smp};
1550 $unset->{smp} = 1;
1551 }
1552
1553 my $new_volids = {};
1554
1555 foreach my $key (keys %$settings) {
554ac7e7 1556 next if $key eq 'digest';
1e3baf05
DM
1557 my $value = $settings->{$key};
1558 if ($key eq 'description') {
1559 $value = PVE::Tools::encode_text($value);
1560 }
1561 eval { $value = check_type($key, $value); };
1562 die "unable to parse value of '$key' - $@" if $@;
1563 if ($key eq 'cdrom') {
1564 $res->{ide2} = $value;
1565 } else {
1566 $res->{$key} = $value;
1567 }
1568 if (valid_drivename($key)) {
1569 my $drive = PVE::QemuServer::parse_drive($key, $value);
1570 $new_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
1571 }
1572 }
1573
1574 my $filename = config_file($vmid);
1575 my $tmpfn = "$filename.$$.tmp";
1576
1577 my $fh = new IO::File ($filename, "r") ||
1578 die "unable to read config for VM $vmid\n";
1579
1580 my $werror = "unable to write config for VM $vmid\n";
1581
1582 my $out = new IO::File ($tmpfn, "w") || die $werror;
1583
1584 eval {
1585
1586 my $done;
1587
1588 while (my $line = <$fh>) {
1589
1590 if (($line =~ m/^\#/) || ($line =~ m/^\s*$/)) {
1591 die $werror unless print $out $line;
1592 next;
1593 }
1594
1595 if ($line =~ m/^([a-z][a-z_]*\d*):\s*(.*\S)\s*$/) {
1596 my $key = $1;
1597 my $value = $2;
1598
1599 # remove 'unusedX' settings if we re-add a volume
1600 next if $key =~ m/^unused/ && $new_volids->{$value};
1601
1602 # convert 'smp' to 'sockets'
1603 $key = 'sockets' if $key eq 'smp';
1604
1605 next if $done->{$key};
1606 $done->{$key} = 1;
1607
1608 if (defined ($res->{$key})) {
1609 $value = $res->{$key};
1610 delete $res->{$key};
1611 }
1612 if (!defined ($unset->{$key})) {
1613 die $werror unless print $out "$key: $value\n";
1614 }
1615
1616 next;
1617 }
1618
1619 die "unable to parse config file: $line\n";
1620 }
1621
1622 foreach my $key (keys %$res) {
1623
1624 if (!defined ($unset->{$key})) {
1625 die $werror unless print $out "$key: $res->{$key}\n";
1626 }
1627 }
1628 };
1629
1630 my $err = $@;
1631
1632 $fh->close();
1633
1634 if ($err) {
1635 $out->close();
1636 unlink $tmpfn;
1637 die $err;
1638 }
1639
1640 if (!$out->close()) {
1641 $err = "close failed - $!\n";
1642 unlink $tmpfn;
1643 die $err;
1644 }
1645
1646 if (!rename($tmpfn, $filename)) {
1647 $err = "rename failed - $!\n";
1648 unlink $tmpfn;
1649 die $err;
1650 }
1651}
1652
1653sub load_defaults {
1654
1655 my $res = {};
1656
1657 # we use static defaults from our JSON schema configuration
1658 foreach my $key (keys %$confdesc) {
1659 if (defined(my $default = $confdesc->{$key}->{default})) {
1660 $res->{$key} = $default;
1661 }
1662 }
1663
1664 my $conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
1665 $res->{keyboard} = $conf->{keyboard} if $conf->{keyboard};
1666
1667 return $res;
1668}
1669
1670sub config_list {
1671 my $vmlist = PVE::Cluster::get_vmlist();
1672 my $res = {};
1673 return $res if !$vmlist || !$vmlist->{ids};
1674 my $ids = $vmlist->{ids};
1675
1e3baf05
DM
1676 foreach my $vmid (keys %$ids) {
1677 my $d = $ids->{$vmid};
1678 next if !$d->{node} || $d->{node} ne $nodename;
1679 $res->{$vmid}->{exists} = 1;
1680 }
1681 return $res;
1682}
1683
64e13401
DM
1684# test if VM uses local resources (to prevent migration)
1685sub check_local_resources {
1686 my ($conf, $noerr) = @_;
1687
1688 my $loc_res = 0;
1689 # fixme:
1690 die "implement me";
1691 $loc_res = 1 if $conf->{hostusb};
1692 $loc_res = 1 if $conf->{hostpci};
64e13401 1693
0d29ab3b 1694 foreach my $k (keys %$conf) {
2fe1a152 1695 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
64e13401
DM
1696 }
1697
1698 die "VM uses local resources\n" if $loc_res && !$noerr;
1699
1700 return $loc_res;
1701}
1702
1e3baf05
DM
1703sub check_lock {
1704 my ($conf) = @_;
1705
1706 die "VM is locked ($conf->{lock})\n" if $conf->{lock};
1707}
1708
1709sub check_cmdline {
1710 my ($pidfile, $pid) = @_;
1711
1712 my $fh = IO::File->new ("/proc/$pid/cmdline", "r");
1713 if (defined ($fh)) {
1714 my $line = <$fh>;
1715 $fh->close;
1716 return undef if !$line;
1717 my @param = split (/\0/, $line);
1718
1719 my $cmd = $param[0];
1720 return if !$cmd || ($cmd !~ m|kvm$|);
1721
1722 for (my $i = 0; $i < scalar (@param); $i++) {
1723 my $p = $param[$i];
1724 next if !$p;
1725 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
1726 my $p = $param[$i+1];
1727 return 1 if $p && ($p eq $pidfile);
1728 return undef;
1729 }
1730 }
1731 }
1732 return undef;
1733}
1734
1735sub check_running {
1736 my ($vmid) = @_;
1737
1738 my $filename = config_file ($vmid);
1739
1740 die "unable to find configuration file for VM $vmid - no such machine\n"
1741 if ! -f $filename;
1742
1743 my $pidfile = pidfile_name ($vmid);
1744
1745 if (my $fd = IO::File->new ("<$pidfile")) {
1746 my $st = stat ($fd);
1747 my $line = <$fd>;
1748 close ($fd);
1749
1750 my $mtime = $st->mtime;
1751 if ($mtime > time()) {
1752 warn "file '$filename' modified in future\n";
1753 }
1754
1755 if ($line =~ m/^(\d+)$/) {
1756 my $pid = $1;
1757
1758 return $pid if ((-d "/proc/$pid") && check_cmdline ($pidfile, $pid));
1759 }
1760 }
1761
1762 return undef;
1763}
1764
1765sub vzlist {
1766
1767 my $vzlist = config_list();
1768
1769 my $fd = IO::Dir->new ($var_run_tmpdir) || return $vzlist;
1770
1771 while (defined(my $de = $fd->read)) {
1772 next if $de !~ m/^(\d+)\.pid$/;
1773 my $vmid = $1;
1774 next if !defined ($vzlist->{$vmid});
1775 if (my $pid = check_running ($vmid)) {
1776 $vzlist->{$vmid}->{pid} = $pid;
1777 }
1778 }
1779
1780 return $vzlist;
1781}
1782
1783my $storage_timeout_hash = {};
1784
1785sub disksize {
1786 my ($storecfg, $conf) = @_;
1787
1788 my $bootdisk = $conf->{bootdisk};
1789 return undef if !$bootdisk;
1790 return undef if !valid_drivename($bootdisk);
1791
1792 return undef if !$conf->{$bootdisk};
1793
1794 my $drive = parse_drive($bootdisk, $conf->{$bootdisk});
1795 return undef if !defined($drive);
1796
1797 return undef if drive_is_cdrom($drive);
1798
1799 my $volid = $drive->{file};
1800 return undef if !$volid;
1801
1802 my $path;
1803 my $storeid;
1804 my $timeoutid;
1805
1806 if ($volid =~ m|^/|) {
1807 $path = $timeoutid = $volid;
1808 } else {
1809 $storeid = $timeoutid = PVE::Storage::parse_volume_id ($volid);
1810 $path = PVE::Storage::path($storecfg, $volid);
1811 }
1812
1813 my $last_timeout = $storage_timeout_hash->{$timeoutid};
1814 if ($last_timeout) {
1815 if ((time() - $last_timeout) < 30) {
1816 # skip storage with errors
1817 return undef ;
1818 }
1819 delete $storage_timeout_hash->{$timeoutid};
1820 }
1821
1822 my ($size, $format, $used);
1823
1824 ($size, $format, $used) = PVE::Storage::file_size_info($path, 1);
1825
1826 if (!defined($format)) {
1827 # got timeout
1828 $storage_timeout_hash->{$timeoutid} = time();
1829 return undef;
1830 }
1831
1832 return wantarray ? ($size, $used) : $size;
1833}
1834
1835my $last_proc_pid_stat;
1836
1837sub vmstatus {
1838 my ($opt_vmid) = @_;
1839
1840 my $res = {};
1841
1842 my $storecfg = PVE::Storage::config();
1843
1844 my $list = vzlist();
1845 my ($uptime) = PVE::ProcFSTools::read_proc_uptime();
1846
1847 foreach my $vmid (keys %$list) {
1848 next if $opt_vmid && ($vmid ne $opt_vmid);
1849
1850 my $cfspath = cfs_config_path($vmid);
1851 my $conf = PVE::Cluster::cfs_read_file($cfspath) || {};
1852
1853 my $d = {};
1854 $d->{pid} = $list->{$vmid}->{pid};
1855
1856 # fixme: better status?
1857 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
1858
1859 my ($size, $used) = disksize($storecfg, $conf);
1860 if (defined($size) && defined($used)) {
1861 $d->{disk} = $used;
1862 $d->{maxdisk} = $size;
1863 } else {
1864 $d->{disk} = 0;
1865 $d->{maxdisk} = 0;
1866 }
1867
1868 $d->{cpus} = ($conf->{sockets} || 1) * ($conf->{cores} || 1);
1869 $d->{name} = $conf->{name} || "VM $vmid";
1870 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024) : 0;
1871
1872
1873 $d->{uptime} = 0;
1874 $d->{cpu} = 0;
1875 $d->{relcpu} = 0;
1876 $d->{mem} = 0;
1877
1878 $d->{netout} = 0;
1879 $d->{netin} = 0;
1880
1881 $d->{diskread} = 0;
1882 $d->{diskwrite} = 0;
1883
1884 $res->{$vmid} = $d;
1885 }
1886
1887 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
1888 foreach my $dev (keys %$netdev) {
1889 next if $dev !~ m/^tap([1-9]\d*)i/;
1890 my $vmid = $1;
1891 my $d = $res->{$vmid};
1892 next if !$d;
1893
1894 $d->{netout} += $netdev->{$dev}->{receive};
1895 $d->{netin} += $netdev->{$dev}->{transmit};
1896 }
1897
1898 my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
1899 my $cpucount = $cpuinfo->{cpus} || 1;
1900 my $ctime = gettimeofday;
1901
1902 foreach my $vmid (keys %$list) {
1903
1904 my $d = $res->{$vmid};
1905 my $pid = $d->{pid};
1906 next if !$pid;
1907
1908 if (my $fh = IO::File->new("/proc/$pid/io", "r")) {
1909 my $data = {};
1910 while (defined (my $line = <$fh>)) {
1911 if ($line =~ m/^([rw]char):\s+(\d+)$/) {
1912 $data->{$1} = $2;
1913 }
1914 }
1915 close($fh);
1916 $d->{diskread} = $data->{rchar} || 0;
1917 $d->{diskwrite} = $data->{wchar} || 0;
1918 }
1919
1920 my $statstr = file_read_firstline("/proc/$pid/stat");
1921 next if !$statstr;
1922
1923 my ($utime, $stime, $vsize, $rss, $starttime);
1924 if ($statstr =~ m/^$pid \(.*\) \S (-?\d+) -?\d+ -?\d+ -?\d+ -?\d+ \d+ \d+ \d+ \d+ \d+ (\d+) (\d+) (-?\d+) (-?\d+) -?\d+ -?\d+ -?\d+ 0 (\d+) (\d+) (-?\d+) \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ -?\d+ -?\d+ \d+ \d+ \d+/) {
1925 ($utime, $stime, $vsize, $rss, $starttime) = ($2, $3, $7, $8 * 4096, $6);
1926 } else {
1927 next;
1928 }
1929
1930 my $used = $utime + $stime;
1931
1932 my $vcpus = $d->{cpus} > $cpucount ? $cpucount : $d->{cpus};
1933
1934 $d->{uptime} = int ($uptime - ($starttime/100));
1935
1936 if ($vsize) {
1937 $d->{mem} = int (($rss/$vsize)*$d->{maxmem});
1938 }
1939
1940 my $old = $last_proc_pid_stat->{$pid};
1941 if (!$old) {
1942 $last_proc_pid_stat->{$pid} = {
1943 time => $ctime,
1944 used => $used,
1945 cpu => 0,
1946 relcpu => 0,
1947 };
1948 next;
1949 }
1950
1951 my $dtime = ($ctime - $old->{time}) * $cpucount * $clock_ticks;
1952
1953 if ($dtime > 1000) {
1954 my $dutime = $used - $old->{used};
1955
1956 $d->{cpu} = $dutime/$dtime;
1957 $d->{relcpu} = ($d->{cpu} * $cpucount) / $vcpus;
1958 $last_proc_pid_stat->{$pid} = {
1959 time => $ctime,
1960 used => $used,
1961 cpu => $d->{cpu},
1962 relcpu => $d->{relcpu},
1963 };
1964 } else {
1965 $d->{cpu} = $old->{cpu};
1966 $d->{relcpu} = $old->{relcpu};
1967 }
1968 }
1969
1970 return $res;
1971}
1972
1973sub foreach_drive {
1974 my ($conf, $func) = @_;
1975
1976 foreach my $ds (keys %$conf) {
1977 next if !valid_drivename($ds);
1978
1979 my $drive = parse_drive ($ds, $conf->{$ds});
1980 next if !$drive;
1981
1982 &$func($ds, $drive);
1983 }
1984}
1985
1986sub config_to_command {
1987 my ($storecfg, $vmid, $conf, $defaults, $migrate_uri) = @_;
1988
1989 my $cmd = [];
1990
1991 my $kvmver = kvm_user_version();
1992 my $vernum = 0; # unknown
1993 if ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
1994 $vernum = $1*1000000+$2*1000+$3;
1995 }
1996
1997 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 14000;
1998
1999 my $have_ovz = -f '/proc/vz/vestat';
2000
2001 push @$cmd, '/usr/bin/kvm';
2002
2003 push @$cmd, '-id', $vmid;
2004
2005 my $use_virtio = 0;
2006
2007 my $socket = monitor_socket ($vmid);
abb39b66
DA
2008 push @$cmd, '-chardev', "socket,id=monitor,path=$socket,server,nowait";
2009 push @$cmd, '-mon', "chardev=monitor,mode=readline";
1e3baf05
DM
2010
2011 $socket = vnc_socket ($vmid);
2012 push @$cmd, '-vnc', "unix:$socket,x509,password";
2013
2014 push @$cmd, '-pidfile' , pidfile_name ($vmid);
2015
2016 push @$cmd, '-daemonize';
2017
2018 push @$cmd, '-incoming', $migrate_uri if $migrate_uri;
2019
2020 # include usb device config
2021 push @$cmd, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg';
2022
2023 # enable absolute mouse coordinates (needed by vnc)
2024 my $tablet = defined ($conf->{tablet}) ? $conf->{tablet} : $defaults->{tablet};
2025 push @$cmd, '-device', 'usb-tablet,bus=ehci.0,port=6' if $tablet;
2026
2027 # host pci devices
040b06b7
DA
2028 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
2029 my $d = parse_hostpci($conf->{"hostpci$i"});
2030 next if !$d;
2031 push @$cmd, '-device', "pci-assign,host=$d->{pciid},id=hostpci$i";
1e3baf05
DM
2032 }
2033
2034 # usb devices
2035 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
2036 my $d = parse_usb_device($conf->{"usb$i"});
2037 next if !$d;
2038 if ($d->{vendorid} && $d->{productid}) {
2039 push @$cmd, '-device', "usb-host,vendorid=$d->{vendorid},productid=$d->{productid}";
2040 } elsif (defined($d->{hostbus}) && defined($d->{hostport})) {
2041 push @$cmd, '-device', "usb-host,hostbus=$d->{hostbus},hostport=$d->{hostport}";
2042 }
2043 }
2044
2045 if (my $usbdl = $conf->{hostusb}) {
2046 my @dl = split (/,/, $usbdl);
2047 foreach my $dev (@dl) {
2048 push @$cmd, '-usbdevice', "host:$dev" if $dev;
2049 }
2050 }
2051
2052 # serial devices
bae179aa
DA
2053 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2054 my $d = parse_serial($conf->{"serial$i"});
2055 next if !$d;
2056 push @$cmd, '-chardev', "tty,id=serial$i,path=$d->{dev}";
2057 push @$cmd, '-device', "isa-serial,chardev=serial$i";
1e3baf05
DM
2058 }
2059
2060 # parallel devices
1989a89c
DA
2061 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
2062 my $d = parse_parallel($conf->{"parallel$i"});
2063 next if !$d;
2064 push @$cmd, '-chardev', "parport,id=parallel$i,path=$d->{dev}";
2065 push @$cmd, '-device', "isa-parallel,chardev=parallel$i";
1e3baf05
DM
2066 }
2067
2068 my $vmname = $conf->{name} || "vm$vmid";
2069
2070 push @$cmd, '-name', $vmname;
2071
2072 my $sockets = 1;
2073 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
2074 $sockets = $conf->{sockets} if $conf->{sockets};
2075
2076 my $cores = $conf->{cores} || 1;
2077
2078 my $boot_opt;
2079
2080 push @$cmd, '-smp', "sockets=$sockets,cores=$cores";
2081
2082 push @$cmd, '-cpu', $conf->{cpu} if $conf->{cpu};
2083
2084 $boot_opt = "menu=on";
2085 if ($conf->{boot}) {
2086 $boot_opt .= ",order=$conf->{boot}";
2087 }
2088
2089 push @$cmd, '-nodefaults';
2090
2091 push @$cmd, '-boot', $boot_opt if $boot_opt;
2092
2093 push @$cmd, '-no-acpi' if defined ($conf->{acpi}) && $conf->{acpi} == 0;
2094
2095 push @$cmd, '-no-reboot' if defined ($conf->{reboot}) && $conf->{reboot} == 0;
2096
2097 my $vga = $conf->{vga};
2098 if (!$vga) {
2099 if ($conf->{ostype} && ($conf->{ostype} eq 'win7' || $conf->{ostype} eq 'w2k8')) {
2100 $vga = 'std';
2101 } else {
2102 $vga = 'cirrus';
2103 }
2104 }
2105
2106 push @$cmd, '-vga', $vga if $vga; # for kvm 77 and later
2107
2108 # time drift fix
2109 my $tdf = defined ($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
2110 push @$cmd, '-tdf' if $tdf;
2111
2112 my $nokvm = defined ($conf->{kvm}) && $conf->{kvm} == 0 ? 1 : 0;
2113
2114 if (my $ost = $conf->{ostype}) {
2115 # other, wxp, w2k, w2k3, w2k8, wvista, win7, l24, l26
2116
2117 if ($ost =~ m/^w/) { # windows
2118 push @$cmd, '-localtime' if !defined ($conf->{localtime});
2119
2120 # use rtc-td-hack when acpi is enabled
2121 if (!(defined ($conf->{acpi}) && $conf->{acpi} == 0)) {
2122 push @$cmd, '-rtc-td-hack';
2123 }
2124 }
2125
2126 # -tdf ?
2127 # -no-acpi
2128 # -no-kvm
2129 # -win2k-hack ?
2130 }
2131
2132 push @$cmd, '-no-kvm' if $nokvm;
2133
2134 push @$cmd, '-localtime' if $conf->{localtime};
2135
2136 push @$cmd, '-startdate', $conf->{startdate} if $conf->{startdate};
2137
2138 push @$cmd, '-S' if $conf->{freeze};
2139
2140 # set keyboard layout
2141 my $kb = $conf->{keyboard} || $defaults->{keyboard};
2142 push @$cmd, '-k', $kb if $kb;
2143
2144 # enable sound
2145 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
2146 #push @$cmd, '-soundhw', 'es1370';
2147 #push @$cmd, '-soundhw', $soundhw if $soundhw;
2148
0ea9541d
DM
2149 if ($conf->{watchdog}) {
2150 my $wdopts = parse_watchdog($conf->{watchdog});
2151 push @$cmd, '-watchdog', $wdopts->{model} || 'i6300esb';
2152 push @$cmd, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
2153 }
2154
1e3baf05 2155 my $vollist = [];
941e0c42 2156 my $scsicontroller = {};
1e3baf05
DM
2157
2158 foreach_drive($conf, sub {
2159 my ($ds, $drive) = @_;
2160
2161 eval {
2162 PVE::Storage::parse_volume_id ($drive->{file});
2163 push @$vollist, $drive->{file};
2164 }; # ignore errors
2165
2166 $use_virtio = 1 if $ds =~ m/^virtio/;
941e0c42
DA
2167 if ($drive->{interface} eq 'scsi') {
2168 my $maxdev = 7;
2169 my $controller = int ($drive->{index} / $maxdev);
2170 push @$cmd, '-device', "lsi,id=scsi$controller" if !$scsicontroller->{$controller};
2171 my $scsicontroller->{$controller}=1;
2172 }
1e3baf05
DM
2173 my $tmp = print_drive_full ($storecfg, $vmid, $drive);
2174 $tmp .= ",boot=on" if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
2175 push @$cmd, '-drive', $tmp;
ca916ecc 2176 push @$cmd, '-device',print_drivedevice_full ($storecfg,$vmid, $drive);
1e3baf05
DM
2177 });
2178
2179 push @$cmd, '-m', $conf->{memory} || $defaults->{memory};
2180
2181 my $foundnet = 0;
2182
2183 foreach my $k (sort keys %$conf) {
2184 next if $k !~ m/^net(\d+)$/;
2185 my $i = int ($1);
2186
2187 die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
2188
2189 if ($conf->{"net$i"} && (my $net = parse_net($conf->{"net$i"}))) {
2190
2191 $foundnet = 1;
2192
2193 my $ifname = "tap${vmid}i$i";
2194
2195 # kvm uses TUNSETIFF ioctl, and that limits ifname length
2196 die "interface name '$ifname' is too long (max 15 character)\n"
2197 if length($ifname) >= 16;
2198
2199 my $device = $net->{model};
2200 my $vhostparam = '';
2201 if ($net->{model} eq 'virtio') {
2202 $use_virtio = 1;
2203 $device = 'virtio-net-pci';
2204 $vhostparam = ',vhost=on' if $kernel_has_vhost_net;
2205 };
2206
2207 if ($net->{bridge}) {
2208 push @$cmd, '-netdev', "type=tap,id=${k},ifname=${ifname},script=/var/lib/qemu-server/pve-bridge$vhostparam";
2209 } else {
2210 push @$cmd, '-netdev', "type=user,id=${k},hostname=$vmname";
2211 }
2212
2213 # qemu > 0.15 always try to boot from network - we disable that by
2214 # not loading the pxe rom file
2215 my $extra = (!$conf->{boot} || ($conf->{boot} !~ m/n/)) ?
2216 "romfile=," : '';
2217 push @$cmd, '-device', "$device,${extra}mac=$net->{macaddr},netdev=${k}";
2218 }
2219 }
2220
2221 push @$cmd, '-net', 'none' if !$foundnet;
2222
2223 # hack: virtio with fairsched is unreliable, so we do not use fairsched
2224 # when the VM uses virtio devices.
2225 if (!$use_virtio && $have_ovz) {
2226
2227 my $cpuunits = defined ($conf->{cpuunits}) ?
2228 $conf->{cpuunits} : $defaults->{cpuunits};
2229
2230 push @$cmd, '-cpuunits', $cpuunits if $cpuunits;
2231
2232 # fixme: cpulimit is currently ignored
2233 #push @$cmd, '-cpulimit', $conf->{cpulimit} if $conf->{cpulimit};
2234 }
2235
2236 # add custom args
2237 if ($conf->{args}) {
2238 my $aa = split_args ($conf->{args});
2239 push @$cmd, @$aa;
2240 }
2241
2242 return wantarray ? ($cmd, $vollist) : $cmd;
2243}
2244
2245sub vnc_socket {
2246 my ($vmid) = @_;
2247 return "${var_run_tmpdir}/$vmid.vnc";
2248}
2249
2250sub monitor_socket {
2251 my ($vmid) = @_;
2252 return "${var_run_tmpdir}/$vmid.mon";
2253}
2254
2255sub pidfile_name {
2256 my ($vmid) = @_;
2257 return "${var_run_tmpdir}/$vmid.pid";
2258}
2259
2260sub random_ether_addr {
2261
2262 my $rand = Digest::SHA1::sha1_hex (rand(), time());
2263
2264 my $mac = '';
2265 for (my $i = 0; $i < 6; $i++) {
2266 my $ss = hex (substr ($rand, $i*2, 2));
2267 if (!$i) {
2268 $ss &= 0xfe; # clear multicast
2269 $ss |= 2; # set local id
2270 }
2271 $ss = sprintf ("%02X", $ss);
2272
2273 if (!$i) {
2274 $mac .= "$ss";
2275 } else {
2276 $mac .= ":$ss";
2277 }
2278 }
2279
2280 return $mac;
2281}
2282
2283sub next_migrate_port {
2284
2285 for (my $p = 60000; $p < 60010; $p++) {
2286
2287 my $sock = IO::Socket::INET->new (Listen => 5,
2288 LocalAddr => 'localhost',
2289 LocalPort => $p,
2290 ReuseAddr => 1,
2291 Proto => 0);
2292
2293 if ($sock) {
2294 close ($sock);
2295 return $p;
2296 }
2297 }
2298
2299 die "unable to find free migration port";
2300}
2301
2302sub vm_start {
2303 my ($storecfg, $vmid, $statefile, $skiplock) = @_;
2304
2305 lock_config ($vmid, sub {
2306 my $conf = load_config ($vmid);
2307
2308 check_lock ($conf) if !$skiplock;
2309
2310 if (check_running ($vmid)) {
2311 my $msg = "VM $vmid already running - start failed\n" ;
2312 syslog ('err', $msg);
2313 die $msg;
2314 } else {
2315 syslog ('info', "VM $vmid start");
2316 }
2317
2318 my $migrate_uri;
2319 my $migrate_port = 0;
2320
2321 if ($statefile) {
2322 if ($statefile eq 'tcp') {
2323 $migrate_port = next_migrate_port();
2324 $migrate_uri = "tcp:localhost:${migrate_port}";
2325 } else {
2326 if (-f $statefile) {
2327 $migrate_uri = "exec:cat $statefile";
2328 } else {
2329 warn "state file '$statefile' does not exist - doing normal startup\n";
2330 }
2331 }
2332 }
2333
2334 my $defaults = load_defaults();
2335
2336 my ($cmd, $vollist) = config_to_command ($storecfg, $vmid, $conf, $defaults, $migrate_uri);
2337 # host pci devices
040b06b7
DA
2338 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
2339 my $d = parse_hostpci($conf->{"hostpci$i"});
2340 next if !$d;
2341 my $info = pci_device_info("0000:$d->{pciid}");
2342 die "IOMMU not present\n" if !check_iommu_support();
2343 die "no pci device info for device '$d->{pciid}'\n" if !$info;
2344 die "can't unbind pci device '$d->{pciid}'\n" if !pci_dev_bind_to_stub($info);
2345 die "can't reset pci device '$d->{pciid}'\n" if !pci_dev_reset($info);
2346 }
1e3baf05
DM
2347
2348 PVE::Storage::activate_volumes($storecfg, $vollist);
2349
2350 eval { run_command ($cmd, timeout => $migrate_uri ? undef : 30); };
2351
2352 my $err = $@;
2353
2354 if ($err) {
2355 my $msg = "start failed: $err";
2356 syslog ('err', "VM $vmid $msg");
2357 die $msg;
2358 }
2359
2360 if ($statefile) {
2361
2362 if ($statefile eq 'tcp') {
2363 print "migration listens on port $migrate_port\n";
2364 } else {
2365 unlink $statefile;
2366 # fixme: send resume - is that necessary ?
2367 eval { vm_monitor_command ($vmid, "cont", 1) };
2368 }
2369 }
2370
2371 if (my $migrate_speed =
2372 $conf->{migrate_speed} || $defaults->{migrate_speed}) {
2373 my $cmd = "migrate_set_speed ${migrate_speed}m";
2374 eval { vm_monitor_command ($vmid, $cmd, 1); };
2375 }
2376
2377 if (my $migrate_downtime =
2378 $conf->{migrate_downtime} || $defaults->{migrate_downtime}) {
2379 my $cmd = "migrate_set_downtime ${migrate_downtime}";
2380 eval { vm_monitor_command ($vmid, $cmd, 1); };
2381 }
2382 });
2383}
2384
2385sub __read_avail {
2386 my ($fh, $timeout) = @_;
2387
2388 my $sel = new IO::Select;
2389 $sel->add ($fh);
2390
2391 my $res = '';
2392 my $buf;
2393
2394 my @ready;
2395 while (scalar (@ready = $sel->can_read ($timeout))) {
2396 my $count;
2397 if ($count = $fh->sysread ($buf, 8192)) {
2398 if ($buf =~ /^(.*)\(qemu\) $/s) {
2399 $res .= $1;
2400 last;
2401 } else {
2402 $res .= $buf;
2403 }
2404 } else {
2405 if (!defined ($count)) {
2406 die "$!\n";
2407 }
2408 last;
2409 }
2410 }
2411
2412 die "monitor read timeout\n" if !scalar (@ready);
2413
2414 return $res;
2415}
2416
2417sub vm_monitor_command {
2418 my ($vmid, $cmdstr, $nolog) = @_;
2419
2420 my $res;
2421
2422 syslog ("info", "VM $vmid monitor command '$cmdstr'") if !$nolog;
2423
2424 eval {
2425 die "VM not running\n" if !check_running ($vmid);
2426
2427 my $sname = monitor_socket ($vmid);
2428
2429 my $sock = IO::Socket::UNIX->new ( Peer => $sname ) ||
2430 die "unable to connect to VM $vmid socket - $!\n";
2431
2432 my $timeout = 3;
2433
2434 # hack: migrate sometime blocks the monitor (when migrate_downtime
2435 # is set)
2436 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
2437 $timeout = 60*60; # 1 hour
2438 }
2439
2440 # read banner;
2441 my $data = __read_avail ($sock, $timeout);
2442
2443 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
2444 die "got unexpected qemu monitor banner\n";
2445 }
2446
2447 my $sel = new IO::Select;
2448 $sel->add ($sock);
2449
2450 if (!scalar (my @ready = $sel->can_write ($timeout))) {
2451 die "monitor write error - timeout";
2452 }
2453
2454 my $fullcmd = "$cmdstr\r";
2455
2456 my $b;
2457 if (!($b = $sock->syswrite ($fullcmd)) || ($b != length ($fullcmd))) {
2458 die "monitor write error - $!";
2459 }
2460
2461 return if ($cmdstr eq 'q') || ($cmdstr eq 'quit');
2462
2463 $timeout = 20;
2464
2465 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
2466 $timeout = 60*60; # 1 hour
2467 } elsif ($cmdstr =~ m/^(eject|change)/) {
2468 $timeout = 60; # note: cdrom mount command is slow
2469 }
2470 if ($res = __read_avail ($sock, $timeout)) {
2471
2472 my @lines = split ("\r?\n", $res);
2473
2474 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
2475
2476 $res = join ("\n", @lines);
2477 $res .= "\n";
2478 }
2479 };
2480
2481 my $err = $@;
2482
2483 if ($err) {
2484 syslog ("err", "VM $vmid monitor command failed - $err");
2485 die $err;
2486 }
2487
2488 return $res;
2489}
2490
2491sub vm_commandline {
2492 my ($storecfg, $vmid) = @_;
2493
2494 my $conf = load_config ($vmid);
2495
2496 my $defaults = load_defaults();
2497
2498 my $cmd = config_to_command ($storecfg, $vmid, $conf, $defaults);
2499
2500 return join (' ', @$cmd);
2501}
2502
2503sub vm_reset {
2504 my ($vmid, $skiplock) = @_;
2505
2506 lock_config ($vmid, sub {
2507
2508 my $conf = load_config ($vmid);
2509
2510 check_lock ($conf) if !$skiplock;
2511
2512 syslog ("info", "VM $vmid sending 'reset'");
2513
2514 vm_monitor_command ($vmid, "system_reset", 1);
2515 });
2516}
2517
2518sub vm_shutdown {
2519 my ($vmid, $skiplock) = @_;
2520
2521 lock_config ($vmid, sub {
2522
2523 my $conf = load_config ($vmid);
2524
2525 check_lock ($conf) if !$skiplock;
2526
2527 syslog ("info", "VM $vmid sending 'shutdown'");
2528
2529 vm_monitor_command ($vmid, "system_powerdown", 1);
2530 });
2531}
2532
2533sub vm_stop {
2534 my ($vmid, $skiplock) = @_;
2535
2536 lock_config ($vmid, sub {
2537
2538 my $pid = check_running ($vmid);
2539
2540 if (!$pid) {
2541 syslog ('info', "VM $vmid already stopped");
2542 return;
2543 }
2544
2545 my $conf = load_config ($vmid);
2546
2547 check_lock ($conf) if !$skiplock;
2548
2549 syslog ("info", "VM $vmid stopping");
2550
2551 eval { vm_monitor_command ($vmid, "quit", 1); };
2552
2553 my $err = $@;
2554
2555 if (!$err) {
2556 # wait some time
2557 my $timeout = 50; # fixme: how long?
2558
2559 my $count = 0;
2560 while (($count < $timeout) && check_running ($vmid)) {
2561 $count++;
2562 sleep 1;
2563 }
2564
2565 if ($count >= $timeout) {
2566 syslog ('info', "VM $vmid still running - terminating now with SIGTERM");
2567 kill 15, $pid;
2568 }
2569 } else {
2570 syslog ('info', "VM $vmid quit failed - terminating now with SIGTERM");
2571 kill 15, $pid;
2572 }
2573
2574 # wait again
2575 my $timeout = 10;
2576
2577 my $count = 0;
2578 while (($count < $timeout) && check_running ($vmid)) {
2579 $count++;
2580 sleep 1;
2581 }
2582
2583 if ($count >= $timeout) {
2584 syslog ('info', "VM $vmid still running - terminating now with SIGKILL\n");
2585 kill 9, $pid;
2586 }
2587
2588 fairsched_rmnod ($vmid); # try to destroy group
2589 });
2590}
2591
2592sub vm_suspend {
2593 my ($vmid, $skiplock) = @_;
2594
2595 lock_config ($vmid, sub {
2596
2597 my $conf = load_config ($vmid);
2598
2599 check_lock ($conf) if !$skiplock;
2600
2601 syslog ("info", "VM $vmid suspend");
2602
2603 vm_monitor_command ($vmid, "stop", 1);
2604 });
2605}
2606
2607sub vm_resume {
2608 my ($vmid, $skiplock) = @_;
2609
2610 lock_config ($vmid, sub {
2611
2612 my $conf = load_config ($vmid);
2613
2614 check_lock ($conf) if !$skiplock;
2615
2616 syslog ("info", "VM $vmid resume");
2617
2618 vm_monitor_command ($vmid, "cont", 1);
2619 });
2620}
2621
2622sub vm_cad {
2623 my ($vmid, $skiplock) = @_;
2624
2625 lock_config ($vmid, sub {
2626
2627 my $conf = load_config ($vmid);
2628
2629 check_lock ($conf) if !$skiplock;
2630
2631 syslog ("info", "VM $vmid sending cntl-alt-delete");
2632
2633 vm_monitor_command ($vmid, "sendkey ctrl-alt-delete", 1);
2634 });
2635}
2636
2637sub vm_destroy {
2638 my ($storecfg, $vmid, $skiplock) = @_;
2639
2640 lock_config ($vmid, sub {
2641
2642 my $conf = load_config ($vmid);
2643
2644 check_lock ($conf) if !$skiplock;
2645
2646 syslog ("info", "VM $vmid destroy called (removing all data)");
2647
2648 eval {
2649 if (!check_running($vmid)) {
2650 fairsched_rmnod($vmid); # try to destroy group
2651 destroy_vm($storecfg, $vmid);
2652 } else {
2653 die "VM is running\n";
2654 }
2655 };
2656
2657 my $err = $@;
2658
2659 if ($err) {
2660 syslog ("err", "VM $vmid destroy failed - $err");
2661 die $err;
2662 }
2663 });
2664}
2665
2666sub vm_stopall {
2667 my ($timeout) = @_;
2668
2669 $timeout = 3*60 if !$timeout;
2670
2671 my $vzlist = vzlist();
2672 my $count = 0;
2673 foreach my $vmid (keys %$vzlist) {
2674 next if !$vzlist->{$vmid}->{pid};
2675 $count++;
2676 }
2677
2678 if ($count) {
2679
2680 my $msg = "Stopping Qemu Server - sending shutdown requests to all VMs\n";
2681 syslog ('info', $msg);
2682 print STDERR $msg;
2683
2684 foreach my $vmid (keys %$vzlist) {
2685 next if !$vzlist->{$vmid}->{pid};
2686 eval { vm_shutdown ($vmid, 1); };
2687 print STDERR $@ if $@;
2688 }
2689
2690 my $wt = 5;
2691 my $maxtries = int (($timeout + $wt -1)/$wt);
2692 my $try = 0;
2693 while (($try < $maxtries) && $count) {
2694 $try++;
2695 sleep $wt;
2696
2697 $vzlist = vzlist();
2698 $count = 0;
2699 foreach my $vmid (keys %$vzlist) {
2700 next if !$vzlist->{$vmid}->{pid};
2701 $count++;
2702 }
2703 last if !$count;
2704 }
2705
2706 return if !$count;
2707
2708 foreach my $vmid (keys %$vzlist) {
2709 next if !$vzlist->{$vmid}->{pid};
2710
2711 $msg = "VM $vmid still running - sending stop now\n";
2712 syslog ('info', $msg);
2713 print $msg;
2714
2715 eval { vm_monitor_command ($vmid, "quit", 1); };
2716 print STDERR $@ if $@;
2717
2718 }
2719
2720 $timeout = 30;
2721 $maxtries = int (($timeout + $wt -1)/$wt);
2722 $try = 0;
2723 while (($try < $maxtries) && $count) {
2724 $try++;
2725 sleep $wt;
2726
2727 $vzlist = vzlist();
2728 $count = 0;
2729 foreach my $vmid (keys %$vzlist) {
2730 next if !$vzlist->{$vmid}->{pid};
2731 $count++;
2732 }
2733 last if !$count;
2734 }
2735
2736 return if !$count;
2737
2738 foreach my $vmid (keys %$vzlist) {
2739 next if !$vzlist->{$vmid}->{pid};
2740
2741 $msg = "VM $vmid still running - terminating now with SIGTERM\n";
2742 syslog ('info', $msg);
2743 print $msg;
2744 kill 15, $vzlist->{$vmid}->{pid};
2745 }
2746
2747 # this is called by system shotdown scripts, so remaining
2748 # processes gets killed anyways (no need to send kill -9 here)
2749
2750 $msg = "Qemu Server stopped\n";
2751 syslog ('info', $msg);
2752 print STDERR $msg;
2753 }
2754}
2755
2756# pci helpers
2757
2758sub file_write {
2759 my ($filename, $buf) = @_;
2760
2761 my $fh = IO::File->new ($filename, "w");
2762 return undef if !$fh;
2763
2764 my $res = print $fh $buf;
2765
2766 $fh->close();
2767
2768 return $res;
2769}
2770
2771sub pci_device_info {
2772 my ($name) = @_;
2773
2774 my $res;
2775
2776 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
2777 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
2778
2779 my $irq = file_read_firstline("$pcisysfs/devices/$name/irq");
2780 return undef if !defined($irq) || $irq !~ m/^\d+$/;
2781
2782 my $vendor = file_read_firstline("$pcisysfs/devices/$name/vendor");
2783 return undef if !defined($vendor) || $vendor !~ s/^0x//;
2784
2785 my $product = file_read_firstline("$pcisysfs/devices/$name/device");
2786 return undef if !defined($product) || $product !~ s/^0x//;
2787
2788 $res = {
2789 name => $name,
2790 vendor => $vendor,
2791 product => $product,
2792 domain => $domain,
2793 bus => $bus,
2794 slot => $slot,
2795 func => $func,
2796 irq => $irq,
2797 has_fl_reset => -f "$pcisysfs/devices/$name/reset" || 0,
2798 };
2799
2800 return $res;
2801}
2802
2803sub pci_dev_reset {
2804 my ($dev) = @_;
2805
2806 my $name = $dev->{name};
2807
2808 my $fn = "$pcisysfs/devices/$name/reset";
2809
2810 return file_write ($fn, "1");
2811}
2812
2813sub pci_dev_bind_to_stub {
2814 my ($dev) = @_;
2815
2816 my $name = $dev->{name};
2817
2818 my $testdir = "$pcisysfs/drivers/pci-stub/$name";
2819 return 1 if -d $testdir;
2820
2821 my $data = "$dev->{vendor} $dev->{product}";
2822 return undef if !file_write ("$pcisysfs/drivers/pci-stub/new_id", $data);
2823
2824 my $fn = "$pcisysfs/devices/$name/driver/unbind";
2825 if (!file_write ($fn, $name)) {
2826 return undef if -f $fn;
2827 }
2828
2829 $fn = "$pcisysfs/drivers/pci-stub/bind";
2830 if (! -d $testdir) {
2831 return undef if !file_write ($fn, $name);
2832 }
2833
2834 return -d $testdir;
2835}
2836
28371;