Hi, this is my first attempt to implement hotplug pci devices (disk and nic).
- i've tested disk hotplug with disk image on lvm and iscsi disk. (no file image)
- disk hotplug only works with virtio and iscsi disks.
- nic hotplug works with all models
For the moment only hotplug works, but not un-hotplug.
so with my patch, you can't remove a disk or nic on a running vm, only when the vm is shutdown.
for unplug, we need to have pci slot id defined for each device, but to do that, we need to add a random slotid in the configuration file for each device (videocard,nic,disk,serial,..)
something like, domain='0x0000' bus='0x00' slot='0x01'. as new attributes.
more info here :
http://fedoraproject.org/wiki/Features/KVM_Stable_PCI_Addresses
http://fedoraproject.org/wiki/KVM_Stable_PCI_Addresses_Design_Notes
code is beta for moment,
I dont verify the return of the hotplug, code can be proper.
I have tried to not modified the soap method, so code is a bit tricky to detect add/remove of a nic in the qm set method. (because when we add a new nic , we resend the vlan of the nic with all nics).
ex:
vlan0: virtio=1E:E8:38:0B3:ED,e1000=5A:6C:2B:58:27:70
vlan100: e1000=36:92:44:20:E3:AC
i think it'll be better to have 1 line by nic in conf file
something like:
nic1:vlan=0,mac=1E:E8:38:0B3:ED,model=virtio,slot='0x01'
nic2:vlan=0,mac=5A:6C:2B:58:27:70,model=e1000,slot='0x02'
nic3:vlan=100,mac=36:92:44:20:E3:AC,model=e1000,slot='0x03'
more easy to add/remove (and modify) nic.
here the diffs:
/usr/sbin/qm
/usr/share/perl5/PVE/QemuServer.pm
- i've tested disk hotplug with disk image on lvm and iscsi disk. (no file image)
- disk hotplug only works with virtio and iscsi disks.
- nic hotplug works with all models
For the moment only hotplug works, but not un-hotplug.
so with my patch, you can't remove a disk or nic on a running vm, only when the vm is shutdown.
for unplug, we need to have pci slot id defined for each device, but to do that, we need to add a random slotid in the configuration file for each device (videocard,nic,disk,serial,..)
something like, domain='0x0000' bus='0x00' slot='0x01'. as new attributes.
more info here :
http://fedoraproject.org/wiki/Features/KVM_Stable_PCI_Addresses
http://fedoraproject.org/wiki/KVM_Stable_PCI_Addresses_Design_Notes
code is beta for moment,
I dont verify the return of the hotplug, code can be proper.
I have tried to not modified the soap method, so code is a bit tricky to detect add/remove of a nic in the qm set method. (because when we add a new nic , we resend the vlan of the nic with all nics).
ex:
vlan0: virtio=1E:E8:38:0B3:ED,e1000=5A:6C:2B:58:27:70
vlan100: e1000=36:92:44:20:E3:AC
i think it'll be better to have 1 line by nic in conf file
something like:
nic1:vlan=0,mac=1E:E8:38:0B3:ED,model=virtio,slot='0x01'
nic2:vlan=0,mac=5A:6C:2B:58:27:70,model=e1000,slot='0x02'
nic3:vlan=100,mac=36:92:44:20:E3:AC,model=e1000,slot='0x03'
more easy to add/remove (and modify) nic.
here the diffs:
/usr/sbin/qm
Code:
--- /root/origprox/qm 2010-11-01 14:51:25.000000000 +0100
+++ /usr/sbin/qm 2010-11-03 10:26:56.000000000 +0100
@@ -260,6 +260,7 @@
delete ($disk->{format}); # no longer needed
push @$vollist, $volid;
$settings->{$ds} = PVE::QemuServer::print_drive ($vmid, $disk);
+ $disk->{path} = PVE::Storage::path ($storecfg, $disk->{file});
} else {
my $path;
if ($disk->{file} =~ m|^/dev/.+|) {
@@ -270,7 +271,9 @@
if (!(-f $path || -b $path)) {
die "image '$path' does not exists\n";
}
+ $disk->{path}=$path;
}
+ $qm->vm_pciadd ($vmid,"disk", $disk);
}
};
@@ -306,6 +309,7 @@
PVE::QemuServer::check_lock ($conf) if !$skiplock;
my $unset = {};
+ my $cannot_delete_devices=0;
foreach my $opt (keys %$settings) {
my $value = $settings->{$opt};
next if !defined ($value);
@@ -325,14 +329,76 @@
$unset->{$opt} = 1;
delete $settings->{$opt};
}
+
+ #case is a disk, cant delete for the moment
+ if($conf->{diskinfo}->{$opt}){
+ $cannot_delete_devices=1;
+ }
+
+ #case is a vlan nic list
+ if ($opt =~ m/^vlan(\d+|u)$/){
+
+ my $vlanid;
+ if($opt =~ m/(\d+)/) {
+ $vlanid = int ($1);
+ }
+
+ my $vlan = PVE::QemuServer::parse_vlan ($settings->{$opt});
+ #disable vlan removal for the moment (opt=undef)
+ if (!$vlan){
+ $cannot_delete_devices=1;
+ next;
+ }
+ #need to get conf, to compare vlan change (nic add or remove)
+ my $oldvlan=PVE::QemuServer::parse_vlan ($conf->{$opt});
+ next if !$oldvlan;
+
+ my $oldnic_list=$oldvlan->{nics};
+ my $nic_list=$vlan->{nics};
+ my $nic;
+
+ #search nic to add if nic_list sent > niclist from conf)
+ if(@$nic_list > @$oldnic_list){
+ #check nic hotplug on this vlan
+ foreach my $nic (@$nic_list) {
+ foreach my $oldnic (@$oldnic_list) {
+ if($nic->{macaddr} eq $oldnic->{macaddr}) {
+ $nic->{exist}=1;
+ }
+ }
+
+ if(!$nic->{exist}) {
+ $nic->{vlanid}=$vlanid;
+ $qm->vm_pciadd ($vmid,'nic', $nic);
+ }
+ }
+ }
+ #search nic to remove if nic_list sent < niclist from conf)
+ elsif(@$nic_list < @$oldnic_list){
+ $cannot_delete_devices=1;
+ #check nic hot-unplug on this vlan
+ foreach my $oldnic (@$oldnic_list) {
+ foreach my $nic (@$nic_list) {
+ if($oldnic->{macaddr} eq $nic->{macaddr}) {
+ $oldnic->{exist}=1;
+ }
+
+ }
+ if(!$oldnic->{exist}) {
+ $nic->{vlanid}=$vlanid;
+ #$qm->vm_pcidel ($vmid,"nic", "pci_id"); #disable for the moment
+ }
+ }
+ }
+ }
}
add_random_macs ($settings);
create_disks ($qm->{storecfg}, $vmid, $settings);
-
+ unless ($cannot_delete_devices == 1 && PVE::QemuServer::check_running($vmid)){
PVE::QemuServer::change_config_nolock ($vmid, $settings, $unset, 1);
-
+ }
});
my $err = $@;
/usr/share/perl5/PVE/QemuServer.pm
Code:
--- /root/origprox/PVE/QemuServer.pm 2010-10-13 11:55:00.000000000 +0200
+++ /usr/share/perl5/PVE/QemuServer.pm 2010-11-03 10:22:33.000000000 +0100
@@ -1964,6 +1964,61 @@
die $@ if $@;
}
+sub vm_pciadd {
+ my ($self, $vmid,$type, $params) = @_;
+
+ my $filename = PVE::QemuServer::config_file ($vmid);
+
+ return unless -f $filename;
+
+ lock_config ($vmid, sub {
+
+ return if !check_running ($vmid); # do nothing
+
+ my $conf = $self->load_config ($vmid);
+
+ check_lock ($conf);
+
+ if($type eq "disk")
+ {
+ unless ( $params->{interface} eq 'ide'){
+ $self->vm_monitor_command ($vmid, "pci_add auto storage file=".$params->{path}.",if=".$params->{interface}."", 1);
+ }
+ }
+ elsif($type eq "nic")
+ {
+ #pci_add bus nic[[vlan=n][,macaddr=addr][,model=type]]
+ $self->vm_monitor_command ($vmid, "pci_add auto nic vlan=".$params->{vlanid}.",macaddr=".$params->{macaddr}.",model=".$params->{model}."", 1);
+ }
+
+ });
+
+ die $@ if $@;
+}
+
+sub vm_pcidel {
+ my ($self, $vmid,$pci_id) = @_;
+
+
+ my $filename = PVE::QemuServer::config_file ($vmid);
+
+ return unless -f $filename;
+
+ lock_config ($vmid, sub {
+
+ return if !check_running ($vmid); # do nothing
+
+ my $conf = $self->load_config ($vmid);
+
+ check_lock ($conf);
+
+ $self->vm_monitor_command ($vmid, "pci_del ".$pci_id, 1);
+
+ });
+
+ die $@ if $@;
+}
+
sub vm_destroy {
my ($self, $vmid, $skiplock) = @_;
Last edited: