},
};
+my $ivshmem_fmt = {
+ size => {
+ type => 'integer',
+ minimum => 1,
+ description => "The size of the file in MB.",
+ },
+ name => {
+ type => 'string',
+ pattern => '[a-zA-Z0-9\-]+',
+ optional => 1,
+ format_description => 'string',
+ description => "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
+ },
+};
+
my $confdesc = {
onboot => {
optional => 1,
optional => 1,
description => "Script that will be executed during various steps in the vms lifetime.",
},
+ ivshmem => {
+ type => 'string',
+ format => $ivshmem_fmt,
+ description => "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
+ optional => 1,
+ }
};
+my $cicustom_fmt = {
+ meta => {
+ type => 'string',
+ optional => 1,
+ description => 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
+ format => 'pve-volume-id',
+ format_description => 'volume',
+ },
+ network => {
+ type => 'string',
+ optional => 1,
+ description => 'Specify a custom file containing all network data passed to the VM via cloud-init.',
+ format => 'pve-volume-id',
+ format_description => 'volume',
+ },
+ user => {
+ type => 'string',
+ optional => 1,
+ description => 'Specify a custom file containing all user data passed to the VM via cloud-init.',
+ format => 'pve-volume-id',
+ format_description => 'volume',
+ },
+};
+PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
+
my $confdesc_cloudinit = {
citype => {
optional => 1,
type => 'string',
description => 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
},
+ cicustom => {
+ optional => 1,
+ type => 'string',
+ description => 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
+ format => 'pve-qm-cicustom',
+ },
searchdomain => {
optional => 1,
type => 'string',
$loc_res = 1 if $conf->{hostusb}; # old syntax
$loc_res = 1 if $conf->{hostpci}; # old syntax
+ $loc_res = 1 if $conf->{ivshmem};
+
foreach my $k (keys %$conf) {
next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
# sockets are safe: they will recreated be on the target side post-migrate
next if !$d;
my $pcie = $d->{pcie};
- if($pcie){
+ if ($pcie) {
die "q35 machine model is not enabled" if !$q35;
# win7 wants to have the pcie devices directly on the pcie bus
# instead of in the root port
} else {
$pciaddr = print_pcie_addr("hostpci$i");
}
- }else{
+ } else {
$pciaddr = print_pci_addr("hostpci$i", $bridges, $arch, $machine_type);
}
push @$devices, '-device', $netdevicefull;
}
+ if ($conf->{ivshmem}) {
+ my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
+
+ my $bus;
+ if ($q35) {
+ $bus = print_pcie_addr("ivshmem");
+ } else {
+ $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
+ }
+
+ my $ivshmem_name = $ivshmem->{name} // $vmid;
+ my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
+
+ push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
+ push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
+ }
+
if (!$q35) {
# add pci bridges
if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
} elsif ($deviceid =~ m/^(net)(\d+)$/) {
- return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
+ return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
- my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
- my $use_old_bios_files = undef;
- ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
+ my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
+ my $use_old_bios_files = undef;
+ ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
- my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
- qemu_deviceadd($vmid, $netdevicefull);
- eval { qemu_deviceaddverify($vmid, $deviceid); };
+ my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
+ qemu_deviceadd($vmid, $netdevicefull);
+ eval {
+ qemu_deviceaddverify($vmid, $deviceid);
+ qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
+ };
if (my $err = $@) {
eval { qemu_netdevdel($vmid, $deviceid); };
warn $@ if $@;
die $err;
- }
+ }
} elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
unlink "/var/run/qemu-server/${vmid}.$ext";
}
+ if ($conf->{ivshmem}) {
+ my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
+ # just delete it for now, VMs which have this already open do not
+ # are affected, but new VMs will get a separated one. If this
+ # becomes an issue we either add some sort of ref-counting or just
+ # add a "don't delete on stop" flag to the ivshmem format.
+ unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
+ }
+
foreach my $key (keys %$conf) {
next if $key !~ m/^hostpci(\d+)$/;
my $hostpciindex = $1;
});
}
+sub convert_iscsi_path {
+ my ($path) = @_;
+
+ if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
+ my $portal = $1;
+ my $target = $2;
+ my $lun = $3;
+
+ my $initiator_name = get_initiator_name();
+
+ return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
+ "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
+ }
+
+ die "cannot convert iscsi path '$path', unkown format\n";
+}
+
sub qemu_img_convert {
my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
my $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
+ my $src_is_iscsi = ($src_path =~ m|^iscsi://|);
+ my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
+
my $cmd = [];
push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
push @$cmd, '-T', 'none' if $src_scfg->{type} eq 'zfspool';
- push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
- if ($is_zero_initialized) {
+
+ if ($src_is_iscsi) {
+ push @$cmd, '--image-opts';
+ $src_path = convert_iscsi_path($src_path);
+ } else {
+ push @$cmd, '-f', $src_format;
+ }
+
+ if ($dst_is_iscsi) {
+ push @$cmd, '--target-image-opts';
+ $dst_path = convert_iscsi_path($dst_path);
+ } else {
+ push @$cmd, '-O', $dst_format;
+ }
+
+ push @$cmd, $src_path;
+
+ if (!$dst_is_iscsi && $is_zero_initialized) {
push @$cmd, "zeroinit:$dst_path";
} else {
push @$cmd, $dst_path;