use PVE::QemuConfig;
use PVE::QMPClient;
use PVE::RPCEnvironment;
+use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr);
use PVE::QemuServer::Memory;
+use PVE::QemuServer::USB qw(parse_usb_device);
use Time::HiRes qw(gettimeofday);
use File::Copy qw(copy);
use URI::Escape;
description => "Enable/disable NUMA.",
default => 0,
},
+ hugepages => {
+ optional => 1,
+ type => 'string',
+ description => "Enable/disable hugepages memory.",
+ enum => [qw(any 2 1024)],
+ },
vcpus => {
optional => 1,
type => 'integer',
my $MAX_SERIAL_PORTS = 4;
my $MAX_PARALLEL_PORTS = 3;
my $MAX_NUMA = 8;
-my $MAX_MEM = 4194304;
-my $STATICMEM = 1024;
my $numa_fmt = {
cpus => {
if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
$res->{$1} = 1;
} else {
- warn "ignoring unknown hotplug feature '$feature'\n";
+ die "invalid hotplug feature '$feature'\n";
}
}
return $res;
warn $@;
return undef;
}
- $res->{macaddr} = PVE::Tools::random_ether_addr() if !defined($res->{macaddr});
+ if (!defined($res->{macaddr})) {
+ my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
+ $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
+ }
return $res;
}
return $res;
}
-sub parse_usb_device {
- my ($value) = @_;
-
- return undef if !$value;
-
- my $res = {};
- if ($value =~ m/^(0x)?([0-9A-Fa-f]{4}):(0x)?([0-9A-Fa-f]{4})$/) {
- $res->{vendorid} = $2;
- $res->{productid} = $4;
- } elsif ($value =~ m/^(\d+)\-(\d+(\.\d+)*)$/) {
- $res->{hostbus} = $1;
- $res->{hostport} = $2;
- } elsif ($value =~ m/^spice$/i) {
- $res->{spice} = 1;
- } else {
- return undef;
- }
-
- return $res;
-}
-
PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
sub verify_usb_device {
my ($value, $noerr) = @_;
}
sub foreach_drive {
- my ($conf, $func) = @_;
+ my ($conf, $func, @param) = @_;
foreach my $ds (valid_drive_names()) {
next if !defined($conf->{$ds});
my $drive = parse_drive($ds, $conf->{$ds});
next if !$drive;
- &$func($ds, $drive);
+ &$func($ds, $drive, @param);
}
}
sub foreach_volid {
- my ($conf, $func) = @_;
+ my ($conf, $func, @param) = @_;
my $volhash = {};
}
foreach my $volid (keys %$volhash) {
- &$func($volid, $volhash->{$volid});
+ &$func($volid, $volhash->{$volid}, @param);
}
}
my $cpuunits = defined($conf->{cpuunits}) ?
$conf->{cpuunits} : $defaults->{cpuunits};
- push @$cmd, '/usr/bin/systemd-run';
- push @$cmd, '--scope';
- push @$cmd, '--slice', "qemu";
- push @$cmd, '--unit', $vmid;
- push @$cmd, '--description', "'Proxmox VE VM $vmid'";
- # set KillMode=none, so that systemd don't kill those scopes
- # at shutdown (pve-manager service should stop the VMs instead)
- push @$cmd, '-p', "KillMode=none";
- push @$cmd, '-p', "CPUShares=$cpuunits";
- if ($conf->{cpulimit}) {
- my $cpulimit = int($conf->{cpulimit} * 100);
- push @$cmd, '-p', "CPUQuota=$cpulimit\%";
- }
-
push @$cmd, '/usr/bin/kvm';
push @$cmd, '-id', $vmid;
push @$cmd, '-drive', "if=pflash,format=raw,file=$ovmfvar_dst";
}
- if ($q35) {
- # the q35 chipset support native usb2, so we enable usb controller
- # by default for this machine type
- push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
- } else {
- $pciaddr = print_pci_addr("piix3", $bridges);
- push @$devices, '-device', "piix3-usb-uhci,id=uhci$pciaddr.0x2";
-
- my $use_usb2 = 0;
- for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
- next if !$conf->{"usb$i"};
- my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) };
- next if !$d || $d->{usb3}; # do not add usb2 controller if we have only usb3 devices
- $use_usb2 = 1;
- }
- # include usb device config
- push @$devices, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg' if $use_usb2;
- }
-
- # add usb3 controller if needed
-
- my $use_usb3 = 0;
- for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
- next if !$conf->{"usb$i"};
- my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) };
- next if !$d || !$d->{usb3};
- $use_usb3 = 1;
- }
-
- $pciaddr = print_pci_addr("xhci", $bridges);
- push @$devices, '-device', "nec-usb-xhci,id=xhci$pciaddr" if $use_usb3;
+ # add usb controllers
+ my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $q35, $usbdesc->{format}, $MAX_USB_DEVICES);
+ push @$devices, @usbcontrollers if @usbcontrollers;
my $vga = $conf->{vga};
my $qxlnum = vga_conf_has_spice($vga);
}
# usb devices
- for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
- next if !$conf->{"usb$i"};
- my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) };
- next if !$d;
-
- # if it is a usb3 device, attach it to the xhci controller, else omit the bus option
- my $usbbus = '';
- if (defined($d->{usb3}) && $d->{usb3}) {
- $usbbus = ',bus=xhci.0';
- }
-
- if (defined($d->{host})) {
- $d = parse_usb_device($d->{host});
- if (defined($d->{vendorid}) && defined($d->{productid})) {
- push @$devices, '-device', "usb-host$usbbus,vendorid=0x$d->{vendorid},productid=0x$d->{productid}";
- } elsif (defined($d->{hostbus}) && defined($d->{hostport})) {
- push @$devices, '-device', "usb-host$usbbus,hostbus=$d->{hostbus},hostport=$d->{hostport}";
- } elsif (defined($d->{spice}) && $d->{spice}) {
- # usb redir support for spice, currently no usb3
- push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir";
- push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0";
- }
- }
- }
-
+ my @usbdevices = PVE::QemuServer::USB::get_usb_devices($conf, $usbdesc->{format}, $MAX_USB_DEVICES);
+ push @$devices, @usbdevices if @usbdevices;
# serial devices
for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
if (my $path = $conf->{"serial$i"}) {
push @$cpuFlags , 'hv_vapic' if !$nokvm;
push @$cpuFlags , 'hv_time' if !$nokvm;
+ if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 6)) {
+ push @$cpuFlags , 'hv_reset' if !$nokvm;
+ push @$cpuFlags , 'hv_vpindex' if !$nokvm;
+ push @$cpuFlags , 'hv_runtime' if !$nokvm;
+ }
+
} else {
push @$cpuFlags , 'hv_spinlocks=0xffff' if !$nokvm;
}
push @$cmd, '-cpu', $cpu;
- my $memory = $conf->{memory} || $defaults->{memory};
- my $static_memory = 0;
- my $dimm_memory = 0;
-
- if ($hotplug_features->{memory}) {
- die "NUMA need to be enabled for memory hotplug\n" if !$conf->{numa};
- die "Total memory is bigger than ${MAX_MEM}MB\n" if $memory > $MAX_MEM;
- $static_memory = $STATICMEM;
- die "minimum memory must be ${static_memory}MB\n" if($memory < $static_memory);
- $dimm_memory = $memory - $static_memory;
- push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M";
-
- } else {
-
- $static_memory = $memory;
- push @$cmd, '-m', $static_memory;
- }
-
- if ($conf->{numa}) {
-
- my $numa_totalmemory = undef;
- for (my $i = 0; $i < $MAX_NUMA; $i++) {
- next if !$conf->{"numa$i"};
- my $numa = parse_numa($conf->{"numa$i"});
- next if !$numa;
- # memory
- die "missing NUMA node$i memory value\n" if !$numa->{memory};
- my $numa_memory = $numa->{memory};
- $numa_totalmemory += $numa_memory;
- my $numa_object = "memory-backend-ram,id=ram-node$i,size=${numa_memory}M";
-
- # cpus
- my $cpulists = $numa->{cpus};
- die "missing NUMA node$i cpus\n" if !defined($cpulists);
- my $cpus = join(',', map {
- my ($start, $end) = @$_;
- defined($end) ? "$start-$end" : $start
- } @$cpulists);
-
- # hostnodes
- my $hostnodelists = $numa->{hostnodes};
- if (defined($hostnodelists)) {
- my $hostnodes;
- foreach my $hostnoderange (@$hostnodelists) {
- my ($start, $end) = @$hostnoderange;
- $hostnodes .= ',' if $hostnodes;
- $hostnodes .= $start;
- $hostnodes .= "-$end" if defined($end);
- $end //= $start;
- for (my $i = $start; $i <= $end; ++$i ) {
- die "host NUMA node$i don't exist\n" if ! -d "/sys/devices/system/node/node$i/";
- }
- }
-
- # policy
- my $policy = $numa->{policy};
- die "you need to define a policy for hostnode $hostnodes\n" if !$policy;
- $numa_object .= ",host-nodes=$hostnodes,policy=$policy";
- }
-
- push @$cmd, '-object', $numa_object;
- push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
- }
-
- die "total memory for NUMA nodes must be equal to vm static memory\n"
- if $numa_totalmemory && $numa_totalmemory != $static_memory;
-
- #if no custom tology, we split memory and cores across numa nodes
- if(!$numa_totalmemory) {
-
- my $numa_memory = ($static_memory / $sockets) . "M";
-
- for (my $i = 0; $i < $sockets; $i++) {
-
- my $cpustart = ($cores * $i);
- my $cpuend = ($cpustart + $cores - 1) if $cores && $cores > 1;
- my $cpus = $cpustart;
- $cpus .= "-$cpuend" if $cpuend;
-
- push @$cmd, '-object', "memory-backend-ram,size=$numa_memory,id=ram-node$i";
- push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
- }
- }
- }
-
- if ($hotplug_features->{memory}) {
- PVE::QemuServer::Memory::foreach_dimm($conf, $vmid, $memory, $sockets, sub {
- my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
- push @$cmd, "-object" , "memory-backend-ram,id=mem-$name,size=${dimm_size}M";
- push @$cmd, "-device", "pc-dimm,id=$name,memdev=mem-$name,node=$numanode";
-
- #if dimm_memory is not aligned to dimm map
- if($current_size > $memory) {
- $conf->{memory} = $current_size;
- PVE::QemuConfig->write_config($vmid, $conf);
- }
- });
- }
-
+ PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
+
push @$cmd, '-S' if $conf->{freeze};
# set keyboard layout
}
}
+ # for usb devices there is no query-usb
+ # but we can iterate over the entries in
+ # qom-list path=/machine/peripheral
+ my $resperipheral = vm_mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
+ foreach my $per (@$resperipheral) {
+ if ($per->{name} =~ m/^usb\d+$/) {
+ $devices->{$per->{name}} = 1;
+ }
+ }
+
return $devices;
}
qemu_deviceadd($vmid, print_tabletdevice_full($conf));
+ } elsif ($deviceid =~ m/^usb(\d+)$/) {
+
+ die "usb hotplug currently not reliable\n";
+ # since we can't reliably hot unplug all added usb devices
+ # and usb passthrough disables live migration
+ # we disable usb hotplugging for now
+ qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
+
} elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
qemu_iothread_add($vmid, $deviceid, $device);
qemu_devicedel($vmid, $deviceid);
+ } elsif ($deviceid =~ m/^usb\d+$/) {
+
+ die "usb hotplug currently not reliable\n";
+ # when unplugging usb devices this way,
+ # there may be remaining usb controllers/hubs
+ # so we disable it for now
+ qemu_devicedel($vmid, $deviceid);
+ qemu_devicedelverify($vmid, $deviceid);
+
} elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
qemu_devicedel($vmid, $deviceid);
vm_mon_cmd($vmid, "netdev_del", id => $deviceid);
}
+sub qemu_usb_hotplug {
+ my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
+
+ return if !$device;
+
+ # remove the old one first
+ vm_deviceunplug($vmid, $conf, $deviceid);
+
+ # check if xhci controller is necessary and available
+ if ($device->{usb3}) {
+
+ my $devicelist = vm_devices_list($vmid);
+
+ if (!$devicelist->{xhci}) {
+ my $pciaddr = print_pci_addr("xhci");
+ qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
+ }
+ }
+ my $d = parse_usb_device($device->{host});
+ $d->{usb3} = $device->{usb3};
+
+ # add the new one
+ vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
+}
+
sub qemu_cpu_hotplug {
my ($vmid, $conf, $vcpus) = @_;
}
}
-sub qemu_memory_hotplug {
- my ($vmid, $conf, $defaults, $opt, $value) = @_;
-
- return $value if !check_running($vmid);
-
- my $memory = $conf->{memory} || $defaults->{memory};
- $value = $defaults->{memory} if !$value;
- return $value if $value == $memory;
-
- my $static_memory = $STATICMEM;
- my $dimm_memory = $memory - $static_memory;
-
- die "memory can't be lower than $static_memory MB" if $value < $static_memory;
- die "you cannot add more memory than $MAX_MEM MB!\n" if $memory > $MAX_MEM;
-
-
- my $sockets = 1;
- $sockets = $conf->{sockets} if $conf->{sockets};
-
- if($value > $memory) {
-
- PVE::QemuServer::Memory::foreach_dimm($conf, $vmid, $value, $sockets, sub {
- my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
-
- return if $current_size <= $conf->{memory};
-
- eval { vm_mon_cmd($vmid, "object-add", 'qom-type' => "memory-backend-ram", id => "mem-$name", props => { size => int($dimm_size*1024*1024) } ) };
- if (my $err = $@) {
- eval { qemu_objectdel($vmid, "mem-$name"); };
- die $err;
- }
-
- eval { vm_mon_cmd($vmid, "device_add", driver => "pc-dimm", id => "$name", memdev => "mem-$name", node => $numanode) };
- if (my $err = $@) {
- eval { qemu_objectdel($vmid, "mem-$name"); };
- die $err;
- }
- #update conf after each succesful module hotplug
- $conf->{memory} = $current_size;
- PVE::QemuConfig->write_config($vmid, $conf);
- });
-
- } else {
-
- PVE::QemuServer::Memory::foreach_reverse_dimm($conf, $vmid, $value, $sockets, sub {
- my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
-
- return if $current_size >= $conf->{memory};
- print "try to unplug memory dimm $name\n";
-
- my $retry = 0;
- while (1) {
- eval { qemu_devicedel($vmid, $name) };
- sleep 3;
- my $dimm_list = qemu_dimm_list($vmid);
- last if !$dimm_list->{$name};
- raise_param_exc({ $name => "error unplug memory module" }) if $retry > 5;
- $retry++;
- }
-
- #update conf after each succesful module unplug
- $conf->{memory} = $current_size;
-
- eval { qemu_objectdel($vmid, "mem-$name"); };
- PVE::QemuConfig->write_config($vmid, $conf);
- });
- }
-}
-
-sub qemu_dimm_list {
- my ($vmid) = @_;
-
- my $dimmarray = vm_mon_cmd_nocheck($vmid, "query-memory-devices");
- my $dimms = {};
-
- foreach my $dimm (@$dimmarray) {
-
- $dimms->{$dimm->{data}->{id}}->{id} = $dimm->{data}->{id};
- $dimms->{$dimm->{data}->{id}}->{node} = $dimm->{data}->{node};
- $dimms->{$dimm->{data}->{id}}->{addr} = $dimm->{data}->{addr};
- $dimms->{$dimm->{data}->{id}}->{size} = $dimm->{data}->{size};
- $dimms->{$dimm->{data}->{id}}->{slot} = $dimm->{data}->{slot};
- }
- return $dimms;
-}
-
sub qemu_block_set_io_throttle {
my ($vmid, $deviceid,
$bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
'shares' => 1,
'startup' => 1,
'description' => 1,
+ 'protection' => 1,
};
# hotplug changes in [PENDING]
} else {
vm_deviceunplug($vmid, $conf, $opt);
}
+ } elsif ($opt =~ m/^usb\d+/) {
+ die "skip\n";
+ # since we cannot reliably hot unplug usb devices
+ # we are disabling it
+ die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
+ vm_deviceunplug($vmid, $conf, $opt);
} elsif ($opt eq 'vcpus') {
die "skip\n" if !$hotplug_features->{cpu};
qemu_cpu_hotplug($vmid, $conf, undef);
vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
} elsif ($opt =~ m/^memory$/) {
die "skip\n" if !$hotplug_features->{memory};
- qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
+ PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
} elsif ($opt eq 'cpuunits') {
cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
} elsif ($opt eq 'cpulimit') {
} elsif ($value == 0) {
vm_deviceunplug($vmid, $conf, $opt);
}
+ } elsif ($opt =~ m/^usb\d+$/) {
+ die "skip\n";
+ # since we cannot reliably hot unplug usb devices
+ # we are disabling it
+ die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
+ my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
+ die "skip\n" if !$d;
+ qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
} elsif ($opt eq 'vcpus') {
die "skip\n" if !$hotplug_features->{cpu};
qemu_cpu_hotplug($vmid, $conf, $value);
$vmid, $opt, $value, 1);
} elsif ($opt =~ m/^memory$/) { #dimms
die "skip\n" if !$hotplug_features->{memory};
- $value = qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
+ $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
} elsif ($opt eq 'cpuunits') {
cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
} elsif ($opt eq 'cpulimit') {
$migrate_uri = "tcp:${localip}:${migrate_port}";
push @$cmd, '-incoming', $migrate_uri;
push @$cmd, '-S';
+
+ } elsif ($statefile eq 'unix') {
+ # should be default for secure migrations as a ssh TCP forward
+ # tunnel is not deterministic reliable ready and fails regurarly
+ # to set up in time, so use UNIX socket forwards
+ my $socket_addr = "/run/qemu-server/$vmid.migrate";
+ unlink $socket_addr;
+
+ $migrate_uri = "unix:$socket_addr";
+
+ push @$cmd, '-incoming', $migrate_uri;
+ push @$cmd, '-S';
+
} else {
push @$cmd, '-loadstate', $statefile;
}
eval { run_command($cmd); };
}
- eval { run_command($cmd, timeout => $statefile ? undef : 30,
- umask => 0077); };
+ my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
+ : $defaults->{cpuunits};
+
+ my %run_params = (timeout => $statefile ? undef : 30, umask => 0077);
+
+ my %properties = (
+ Slice => 'qemu.slice',
+ KillMode => 'none',
+ CPUShares => $cpuunits
+ );
+
+ if (my $cpulimit = $conf->{cpulimit}) {
+ $properties{CPUQuota} = int($cpulimit * 100);
+ }
+ $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
+
+ if ($conf->{hugepages}) {
+
+ my $code = sub {
+ my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
+ my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
+
+ PVE::QemuServer::Memory::hugepages_mount();
+ PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
+
+ eval {
+ PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
+ run_command($cmd, %run_params);
+ };
+
+ if (my $err = $@) {
+ PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
+ die $err;
+ }
+
+ PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
+ };
+ eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
+
+ } else {
+ eval {
+ PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
+ run_command($cmd, %run_params);
+ };
+ }
if (my $err = $@) {
# deactivate volumes if start fails
return 1;
}
-sub print_pci_addr {
- my ($id, $bridges) = @_;
-
- my $res = '';
- my $devices = {
- piix3 => { bus => 0, addr => 1 },
- #addr2 : first videocard
- balloon0 => { bus => 0, addr => 3 },
- watchdog => { bus => 0, addr => 4 },
- scsihw0 => { bus => 0, addr => 5 },
- 'pci.3' => { bus => 0, addr => 5 }, #can also be used for virtio-scsi-single bridge
- scsihw1 => { bus => 0, addr => 6 },
- ahci0 => { bus => 0, addr => 7 },
- qga0 => { bus => 0, addr => 8 },
- spice => { bus => 0, addr => 9 },
- virtio0 => { bus => 0, addr => 10 },
- virtio1 => { bus => 0, addr => 11 },
- virtio2 => { bus => 0, addr => 12 },
- virtio3 => { bus => 0, addr => 13 },
- virtio4 => { bus => 0, addr => 14 },
- virtio5 => { bus => 0, addr => 15 },
- hostpci0 => { bus => 0, addr => 16 },
- hostpci1 => { bus => 0, addr => 17 },
- net0 => { bus => 0, addr => 18 },
- net1 => { bus => 0, addr => 19 },
- net2 => { bus => 0, addr => 20 },
- net3 => { bus => 0, addr => 21 },
- net4 => { bus => 0, addr => 22 },
- net5 => { bus => 0, addr => 23 },
- vga1 => { bus => 0, addr => 24 },
- vga2 => { bus => 0, addr => 25 },
- vga3 => { bus => 0, addr => 26 },
- hostpci2 => { bus => 0, addr => 27 },
- hostpci3 => { bus => 0, addr => 28 },
- #addr29 : usb-host (pve-usb.cfg)
- 'pci.1' => { bus => 0, addr => 30 },
- 'pci.2' => { bus => 0, addr => 31 },
- 'net6' => { bus => 1, addr => 1 },
- 'net7' => { bus => 1, addr => 2 },
- 'net8' => { bus => 1, addr => 3 },
- 'net9' => { bus => 1, addr => 4 },
- 'net10' => { bus => 1, addr => 5 },
- 'net11' => { bus => 1, addr => 6 },
- 'net12' => { bus => 1, addr => 7 },
- 'net13' => { bus => 1, addr => 8 },
- 'net14' => { bus => 1, addr => 9 },
- 'net15' => { bus => 1, addr => 10 },
- 'net16' => { bus => 1, addr => 11 },
- 'net17' => { bus => 1, addr => 12 },
- 'net18' => { bus => 1, addr => 13 },
- 'net19' => { bus => 1, addr => 14 },
- 'net20' => { bus => 1, addr => 15 },
- 'net21' => { bus => 1, addr => 16 },
- 'net22' => { bus => 1, addr => 17 },
- 'net23' => { bus => 1, addr => 18 },
- 'net24' => { bus => 1, addr => 19 },
- 'net25' => { bus => 1, addr => 20 },
- 'net26' => { bus => 1, addr => 21 },
- 'net27' => { bus => 1, addr => 22 },
- 'net28' => { bus => 1, addr => 23 },
- 'net29' => { bus => 1, addr => 24 },
- 'net30' => { bus => 1, addr => 25 },
- 'net31' => { bus => 1, addr => 26 },
- 'xhci' => { bus => 1, addr => 27 },
- 'virtio6' => { bus => 2, addr => 1 },
- 'virtio7' => { bus => 2, addr => 2 },
- 'virtio8' => { bus => 2, addr => 3 },
- 'virtio9' => { bus => 2, addr => 4 },
- 'virtio10' => { bus => 2, addr => 5 },
- 'virtio11' => { bus => 2, addr => 6 },
- 'virtio12' => { bus => 2, addr => 7 },
- 'virtio13' => { bus => 2, addr => 8 },
- 'virtio14' => { bus => 2, addr => 9 },
- 'virtio15' => { bus => 2, addr => 10 },
- 'virtioscsi0' => { bus => 3, addr => 1 },
- 'virtioscsi1' => { bus => 3, addr => 2 },
- 'virtioscsi2' => { bus => 3, addr => 3 },
- 'virtioscsi3' => { bus => 3, addr => 4 },
- 'virtioscsi4' => { bus => 3, addr => 5 },
- 'virtioscsi5' => { bus => 3, addr => 6 },
- 'virtioscsi6' => { bus => 3, addr => 7 },
- 'virtioscsi7' => { bus => 3, addr => 8 },
- 'virtioscsi8' => { bus => 3, addr => 9 },
- 'virtioscsi9' => { bus => 3, addr => 10 },
- 'virtioscsi10' => { bus => 3, addr => 11 },
- 'virtioscsi11' => { bus => 3, addr => 12 },
- 'virtioscsi12' => { bus => 3, addr => 13 },
- 'virtioscsi13' => { bus => 3, addr => 14 },
- 'virtioscsi14' => { bus => 3, addr => 15 },
- 'virtioscsi15' => { bus => 3, addr => 16 },
- 'virtioscsi16' => { bus => 3, addr => 17 },
- 'virtioscsi17' => { bus => 3, addr => 18 },
- 'virtioscsi18' => { bus => 3, addr => 19 },
- 'virtioscsi19' => { bus => 3, addr => 20 },
- 'virtioscsi20' => { bus => 3, addr => 21 },
- 'virtioscsi21' => { bus => 3, addr => 22 },
- 'virtioscsi22' => { bus => 3, addr => 23 },
- 'virtioscsi23' => { bus => 3, addr => 24 },
- 'virtioscsi24' => { bus => 3, addr => 25 },
- 'virtioscsi25' => { bus => 3, addr => 26 },
- 'virtioscsi26' => { bus => 3, addr => 27 },
- 'virtioscsi27' => { bus => 3, addr => 28 },
- 'virtioscsi28' => { bus => 3, addr => 29 },
- 'virtioscsi29' => { bus => 3, addr => 30 },
- 'virtioscsi30' => { bus => 3, addr => 31 },
-
- };
-
- if (defined($devices->{$id}->{bus}) && defined($devices->{$id}->{addr})) {
- my $addr = sprintf("0x%x", $devices->{$id}->{addr});
- my $bus = $devices->{$id}->{bus};
- $res = ",bus=pci.$bus,addr=$addr";
- $bridges->{$bus} = 1 if $bridges;
- }
- return $res;
-
-}
-
-sub print_pcie_addr {
- my ($id) = @_;
-
- my $res = '';
- my $devices = {
- hostpci0 => { bus => "ich9-pcie-port-1", addr => 0 },
- hostpci1 => { bus => "ich9-pcie-port-2", addr => 0 },
- hostpci2 => { bus => "ich9-pcie-port-3", addr => 0 },
- hostpci3 => { bus => "ich9-pcie-port-4", addr => 0 },
- };
-
- if (defined($devices->{$id}->{bus}) && defined($devices->{$id}->{addr})) {
- my $addr = sprintf("0x%x", $devices->{$id}->{addr});
- my $bus = $devices->{$id}->{bus};
- $res = ",bus=$bus,addr=$addr";
- }
- return $res;
-
-}
-
# vzdump restore implementaion
sub tar_archive_read_firstfile {
die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
# try to detect archive type first
- my $pid = open (TMP, "tar tf '$archive'|") ||
+ my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
die "unable to open file '$archive'\n";
- my $firstfile = <TMP>;
+ my $firstfile = <$fh>;
kill 15, $pid;
- close TMP;
+ close $fh;
die "ERROR: archive contaions no data\n" if !$firstfile;
chomp $firstfile;
return if $line =~ m/^parent:/;
return if $line =~ m/^template:/; # restored VM is never a template
+ my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
# try to convert old 1.X settings
my ($id, $ind, $ethcfg) = ($1, $2, $3);
foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
my ($model, $macaddr) = split(/\=/, $devconfig);
- $macaddr = PVE::Tools::random_ether_addr() if !$macaddr || $unique;
+ $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
my $net = {
model => $model,
bridge => "vmbr$ind",
} elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
my ($id, $netstr) = ($1, $2);
my $net = parse_net($netstr);
- $net->{macaddr} = PVE::Tools::random_ether_addr() if $net->{macaddr};
+ $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
$netstr = print_net($net);
print $outfd "$id: $netstr\n";
} elsif ($line =~ m/^((ide|scsi|virtio|sata)\d+):\s*(\S+)\s*$/) {
my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
my $cmd = [];
- push @$cmd, '/usr/bin/qemu-img', 'convert', '-t', 'writeback', '-p', '-n';
+ push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
if ($is_zero_initialized) {
$newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $format, undef, ($size/1024));
push @$newvollist, $newvolid;
- PVE::Storage::activate_volumes($storecfg, $newvollist);
+ PVE::Storage::activate_volumes($storecfg, [$newvolid]);
my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
if (!$running || $snapname) {