gui: add qemu/PCIEdit

this patch adds the PCIEdit window and InputPanel uses PCISelector
and MDevSelector

when we detect an iommugroup of -1, we put a warning on top to inform
the user that IOMMU is not activated (but let him add the devices
regardless, so that he can use it after IOMMU is activated)

also puts a warning if he selects a device that shares an iommugroup
with a different device (but not the same device with different
function). that detection is not perfect, but we cannot do really
better

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2018-11-22 11:35:45 +01:00 committed by Thomas Lamprecht
parent 02cebb1a46
commit c59fb4eef5
2 changed files with 234 additions and 0 deletions

View File

@ -139,6 +139,7 @@ JSSRC= \
qemu/Config.js \ qemu/Config.js \
qemu/CreateWizard.js \ qemu/CreateWizard.js \
qemu/USBEdit.js \ qemu/USBEdit.js \
qemu/PCIEdit.js \
qemu/SerialEdit.js \ qemu/SerialEdit.js \
qemu/AgentIPView.js \ qemu/AgentIPView.js \
qemu/CloudInit.js \ qemu/CloudInit.js \

View File

@ -0,0 +1,233 @@
Ext.define('PVE.qemu.PCIInputPanel', {
extend: 'Proxmox.panel.InputPanel',
onlineHelp: 'qm_pci_passthrough',
setVMConfig: function(vmconfig) {
var me = this;
me.vmconfig = vmconfig;
var hostpci = me.vmconfig[me.confid] || '';
var values = PVE.Parser.parsePropertyString(hostpci, 'host');
if (values.host && values.host.length < 6) { // 00:00 format not 00:00.0
values.host += ".0";
values.multifunction = true;
}
values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
me.setValues(values);
if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
// machine is not set to some variant of q35, so we disable pcie
var pcie = me.down('field[name=pcie]');
pcie.setDisabled(true);
pcie.setBoxLabel(gettext('Q35 only'));
}
if (values.romfile) {
me.down('field[name=romfile]').setVisible(true);
}
},
onGetValues: function(values) {
var me = this;
var ret = {};
if(!me.confid) {
var i;
for (i = 0; i < 5; i++) {
if (!me.vmconfig['hostpci' + i.toString()]) {
me.confid = 'hostpci' + i.toString();
break;
}
}
}
if (values.multifunction) {
// modify host to skip the '.X'
values.host = values.host.substring(0,5);
delete values.multifunction;
}
if (values.rombar) {
delete values.rombar;
} else {
values.rombar = 0;
}
ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
return ret;
},
initComponent: function() {
var me = this;
me.nodename = me.pveSelNode.data.node;
if (!me.nodename) {
throw "no node name specified";
}
me.column1 = [
{
xtype: 'pvePCISelector',
fieldLabel: gettext('Device'),
name: 'host',
nodename: me.nodename,
allowBlank: false,
onLoadCallBack: function(store, records, success) {
if (!success || !records.length) {
return;
}
var first = records[0];
if (first.data.iommugroup === -1) {
// no iommu groups
var warning = Ext.create('Ext.form.field.Display', {
columnWidth: 1,
padding: '0 0 10 0',
value: 'No IOMMU detected, please activate it.' +
'See Documentation for further information.',
userCls: 'pve-hint'
});
me.items.insert(0, warning);
me.updateLayout(); // insert does not trigger that
}
},
listeners: {
change: function(pcisel, value) {
if (!value) {
return;
}
var pcidev = pcisel.getStore().getById(value);
var mdevfield = me.down('field[name=mdev]');
mdevfield.setDisabled(!pcidev || !pcidev.data.mdev);
if (!pcidev) {
return;
}
var id = pcidev.data.id.substring(0,5); // 00:00
var iommu = pcidev.data.iommugroup;
// try to find out if there are more devices
// in that iommu group
if (iommu !== -1) {
var count = 0;
pcisel.getStore().each(function(record) {
if (record.data.iommugroup === iommu &&
record.data.id.substring(0,5) !== id)
{
count++;
return false;
}
});
var warning = me.down('#iommuwarning');
if (count && !warning) {
warning = Ext.create('Ext.form.field.Display', {
columnWidth: 1,
padding: '0 0 10 0',
itemId: 'iommuwarning',
value: 'The selected Device is not in a seperate' +
'IOMMU group, make sure this is intended.',
userCls: 'pve-hint'
});
me.items.insert(0, warning);
me.updateLayout(); // insert does not trigger that
} else if (!count && warning) {
me.remove(warning);
}
}
if (pcidev.data.mdev) {
mdevfield.setPciID(value);
}
}
}
},
{
xtype: 'proxmoxcheckbox',
fieldLabel: gettext('All Functions'),
name: 'multifunction'
}
];
me.column2 = [
{
xtype: 'pveMDevSelector',
name: 'mdev',
disabled: true,
fieldLabel: gettext('MDev Type'),
nodename: me.nodename,
listeners: {
change: function(field, value) {
var mf = me.down('field[name=multifunction]');
if (!!value) {
mf.setValue(false);
}
mf.setDisabled(!!value);
}
}
},
{
xtype: 'proxmoxcheckbox',
fieldLabel: gettext('Primary GPU'),
name: 'x-vga'
}
];
me.advancedColumn1 = [
{
xtype: 'proxmoxcheckbox',
fieldLabel: 'ROM-Bar',
name: 'rombar'
},
{
xtype: 'displayfield',
submitValue: true,
hidden: true,
fieldLabel: 'ROM-File',
name: 'romfile'
}
];
me.advancedColumn2 = [
{
xtype: 'proxmoxcheckbox',
fieldLabel: 'PCI-Express',
name: 'pcie'
}
];
me.callParent();
}
});
Ext.define('PVE.qemu.PCIEdit', {
extend: 'Proxmox.window.Edit',
vmconfig: undefined,
isAdd: true,
subject: gettext('PCI Device'),
initComponent : function() {
var me = this;
me.isCreate = !me.confid;
var ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
confid: me.confid,
pveSelNode: me.pveSelNode
});
Ext.apply(me, {
items: [ ipanel ]
});
me.callParent();
me.load({
success: function(response) {
ipanel.setVMConfig(response.result.data);
}
});
}
});