]> git.proxmox.com Git - pve-manager.git/commitdiff
ui: qemu/PCIEdit: rework panel to add a mapped configuration
authorDominik Csapak <d.csapak@proxmox.com>
Fri, 16 Jun 2023 13:05:33 +0000 (15:05 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Fri, 16 Jun 2023 14:25:42 +0000 (16:25 +0200)
reworks the panel to use a controller, so that we can easily
add the selector for mapped pci devices

shows now a selection between 'raw' and 'mapped' devices, where
'raw' ones work like before, and 'mapped' ones take the values
form the hardware map config

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
www/manager6/qemu/PCIEdit.js

index 2f67aece9125a7f61e364f3e852d262e7c4fde7f..8cef1b105a8c96f84fc528f8df34fb73e579f27c 100644 (file)
@@ -3,71 +3,155 @@ Ext.define('PVE.qemu.PCIInputPanel', {
 
     onlineHelp: 'qm_pci_passthrough_vm_config',
 
-    setVMConfig: function(vmconfig) {
-       var me = this;
-       me.vmconfig = vmconfig;
+    controller: {
+       xclass: 'Ext.app.ViewController',
+
+       setVMConfig: function(vmconfig) {
+           let me = this;
+           let view = me.getView();
+           me.vmconfig = vmconfig;
 
-       var hostpci = me.vmconfig[me.confid] || '';
+           let hostpci = me.vmconfig[view.confid] || '';
 
-       var values = PVE.Parser.parsePropertyString(hostpci, 'host');
-       if (values.host) {
-           if (!values.host.match(/^[0-9a-f]{4}:/i)) { // add optional domain
-               values.host = "0000:" + values.host;
+           let values = PVE.Parser.parsePropertyString(hostpci, 'host');
+           if (values.host) {
+               if (!values.host.match(/^[0-9a-f]{4}:/i)) { // add optional domain
+                   values.host = "0000:" + values.host;
+               }
+               if (values.host.length < 11) { // 0000:00:00 format not 0000:00:00.0
+                   values.host += ".0";
+                   values.multifunction = true;
+               }
+               values.type = 'raw';
+           } else if (values.mapping) {
+               values.type = 'mapped';
            }
-           if (values.host.length < 11) { // 0000:00:00 format not 0000: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);
+
+           view.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
+               let pcie = me.lookup('pcie');
+               pcie.setDisabled(true);
+               pcie.setBoxLabel(gettext('Q35 only'));
            }
-       }
 
-       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);
+           if (values.romfile) {
+               me.lookup('romfile').setVisible(true);
+           }
+       },
 
-       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'));
-       }
+       selectorEnable: function(selector) {
+           let me = this;
+           me.pciDevChange(selector, selector.getValue());
+       },
 
-       if (values.romfile) {
-           me.down('field[name=romfile]').setVisible(true);
-       }
-    },
+       pciDevChange: function(pcisel, value) {
+           let me = this;
+           let mdevfield = me.lookup('mdev');
+           if (!value) {
+               if (!pcisel.isDisabled()) {
+                   mdevfield.setDisabled(true);
+               }
+               return;
+           }
+           let pciDev = pcisel.getStore().getById(value);
 
-    onGetValues: function(values) {
-       let me = this;
-       if (!me.confid) {
-           for (let i = 0; i < PVE.Utils.hardware_counts.hostpci; i++) {
-               if (!me.vmconfig['hostpci' + i.toString()]) {
-                   me.confid = 'hostpci' + i.toString();
-                   break;
+           mdevfield.setDisabled(!pciDev || !pciDev.data.mdev);
+           if (!pciDev) {
+               return;
+           }
+
+           let path = value;
+           if (pciDev.data.map) {
+               // find local mapping
+               for (const entry of pciDev.data.map) {
+                   let mapping = PVE.Parser.parsePropertyString(entry);
+                   if (mapping.node === pcisel.up('inputpanel').nodename) {
+                       path = mapping.path.split(';')[0];
+                       break;
+                   }
+               }
+               if (path.indexOf('.') === -1) {
+                   path += '.0';
                }
            }
-           // FIXME: what if no confid was found??
-       }
-       values.host.replace(/^0000:/, ''); // remove optional '0000' domain
 
-       if (values.multifunction) {
-           values.host = values.host.substring(0, values.host.indexOf('.')); // skip the '.X'
-           delete values.multifunction;
-       }
+           if (pciDev.data.mdev) {
+               mdevfield.setPciID(path);
+           }
+           if (pcisel.reference === 'selector') {
+               let iommu = pciDev.data.iommugroup;
+               if (iommu === -1) {
+                   return;
+               }
+               // try to find out if there are more devices in that iommu group
+               let id = path.substring(0, 5); // 00:00
+               let count = 0;
+               pcisel.getStore().each(({ data }) => {
+                   if (data.iommugroup === iommu && data.id.substring(0, 5) !== id) {
+                       count++;
+                       return false;
+                   }
+                   return true;
+               });
+               me.lookup('group_warning').setVisible(count > 0);
+           }
+       },
 
-       if (values.rombar) {
-           delete values.rombar;
-       } else {
-           values.rombar = 0;
-       }
+       onGetValues: function(values) {
+           let me = this;
+           let view = me.getView();
+           if (!view.confid) {
+               for (let i = 0; i < PVE.Utils.hardware_counts.hostpci; i++) {
+                   if (!me.vmconfig['hostpci' + i.toString()]) {
+                       view.confid = 'hostpci' + i.toString();
+                       break;
+                   }
+               }
+               // FIXME: what if no confid was found??
+           }
 
-       if (!values.romfile) {
-           delete values.romfile;
-       }
+           values.host?.replace(/^0000:/, ''); // remove optional '0000' domain
 
-       let ret = {};
-       ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
-       return ret;
+           if (values.multifunction && values.host) {
+               values.host = values.host.substring(0, values.host.indexOf('.')); // skip the '.X'
+               delete values.multifunction;
+           }
+
+           if (values.rombar) {
+               delete values.rombar;
+           } else {
+               values.rombar = 0;
+           }
+
+           if (!values.romfile) {
+               delete values.romfile;
+           }
+
+           delete values.type;
+
+           let ret = {};
+           ret[view.confid] = PVE.Parser.printPropertyString(values, 'host');
+           return ret;
+       },
+    },
+
+    viewModel: {
+       data: {
+           isMapped: true,
+       },
+    },
+
+    setVMConfig: function(vmconfig) {
+       return this.getController().setVMConfig(vmconfig);
+    },
+
+    onGetValues: function(values) {
+       return this.getController().onGetValues(values);
     },
 
     initComponent: function() {
@@ -78,78 +162,97 @@ Ext.define('PVE.qemu.PCIInputPanel', {
            throw "no node name specified";
        }
 
+       me.columnT = [
+           {
+               xtype: 'displayfield',
+               reference: 'iommu_warning',
+               hidden: true,
+               columnWidth: 1,
+               padding: '0 0 10 0',
+               value: 'No IOMMU detected, please activate it.' +
+               'See Documentation for further information.',
+               userCls: 'pmx-hint',
+           },
+           {
+               xtype: 'displayfield',
+               reference: 'group_warning',
+               hidden: true,
+               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: 'pmx-hint',
+           },
+       ];
+
        me.column1 = [
+           {
+               xtype: 'radiofield',
+               name: 'type',
+               inputValue: 'mapped',
+               boxLabel: gettext('Mapped Device'),
+               bind: {
+                   value: '{isMapped}',
+               },
+           },
+           {
+               xtype: 'pvePCIMapSelector',
+               fieldLabel: gettext('Device'),
+               reference: 'mapped_selector',
+               name: 'mapping',
+               labelAlign: 'right',
+               nodename: me.nodename,
+               allowBlank: false,
+               bind: {
+                   disabled: '{!isMapped}',
+               },
+               listeners: {
+                   change: 'pciDevChange',
+                   enable: 'selectorEnable',
+               },
+           },
+           {
+               xtype: 'radiofield',
+               name: 'type',
+               inputValue: 'raw',
+               checked: true,
+               boxLabel: gettext('Raw Device'),
+           },
            {
                xtype: 'pvePCISelector',
                fieldLabel: gettext('Device'),
                name: 'host',
+               reference: 'selector',
                nodename: me.nodename,
+               labelAlign: 'right',
                allowBlank: false,
+               disabled: true,
+               bind: {
+                   disabled: '{isMapped}',
+               },
                onLoadCallBack: function(store, records, success) {
                    if (!success || !records.length) {
                        return;
                    }
-                   if (records.every((val) => val.data.iommugroup === -1)) { // no IOMMU groups
-                       let 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: 'pmx-hint',
-                       });
-                       me.items.insert(0, warning);
-                       me.updateLayout(); // insert does not trigger that
-                   }
+                   me.lookup('iommu_warning').setVisible(
+                       records.every((val) => val.data.iommugroup === -1),
+                   );
                },
                listeners: {
-                   change: function(pcisel, value) {
-                       if (!value) {
-                           return;
-                       }
-                       let pciDev = pcisel.getStore().getById(value);
-                       let mdevfield = me.down('field[name=mdev]');
-                       mdevfield.setDisabled(!pciDev || !pciDev.data.mdev);
-                       if (!pciDev) {
-                           return;
-                       }
-                       if (pciDev.data.mdev) {
-                           mdevfield.setPciID(value);
-                       }
-                       let iommu = pciDev.data.iommugroup;
-                       if (iommu === -1) {
-                           return;
-                       }
-                       // try to find out if there are more devices in that iommu group
-                       let id = pciDev.data.id.substring(0, 5); // 00:00
-                       let count = 0;
-                       pcisel.getStore().each(({ data }) => {
-                           if (data.iommugroup === iommu && data.id.substring(0, 5) !== id) {
-                               count++;
-                               return false;
-                           }
-                           return true;
-                       });
-                       let 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: 'pmx-hint',
-                           });
-                           me.items.insert(0, warning);
-                           me.updateLayout(); // insert does not trigger that
-                       } else if (!count && warning) {
-                           me.remove(warning);
-                       }
-                   },
+                   change: 'pciDevChange',
+                   enable: 'selectorEnable',
                },
            },
            {
                xtype: 'proxmoxcheckbox',
                fieldLabel: gettext('All Functions'),
+               reference: 'all_functions',
+               disabled: true,
+               labelAlign: 'right',
                name: 'multifunction',
+               bind: {
+                   disabled: '{isMapped}',
+               },
            },
        ];
 
@@ -157,6 +260,7 @@ Ext.define('PVE.qemu.PCIInputPanel', {
            {
                xtype: 'pveMDevSelector',
                name: 'mdev',
+               reference: 'mdev',
                disabled: true,
                fieldLabel: gettext('MDev Type'),
                nodename: me.nodename,
@@ -188,6 +292,7 @@ Ext.define('PVE.qemu.PCIInputPanel', {
                submitValue: true,
                hidden: true,
                fieldLabel: 'ROM-File',
+               reference: 'romfile',
                name: 'romfile',
            },
            {
@@ -214,6 +319,7 @@ Ext.define('PVE.qemu.PCIInputPanel', {
            {
                xtype: 'proxmoxcheckbox',
                fieldLabel: 'PCI-Express',
+               reference: 'pcie',
                name: 'pcie',
            },
            {