[pve-devel] [RFC manager][stable-5] gui: vm: add CPU flag selector with tri-state awareness

Thomas Lamprecht t.lamprecht at proxmox.com
Thu Jun 6 22:32:54 CEST 2019


This allows to select the tri-state (enforce on, enforce off, default
from QEMU+CPU Model) for each CPU flag independently.

For this a grid with a widgetcolumn is used hosting tree radio
buttons for each state. They're marked '+' for enforce on, '-' for
enforce off and the default has no label, as it isn't easy to add in
such a way that it does not confuses people and does not looks
completely ugly.. But, to help people which have a hard time figuring
out what the states mean, a fake column was added showing the current
selected state's outcome in words.

For show casing the new nice interface add a few flags more, i.e.,
besides the existing 'spec-ctrl' and 'pcid' we add 'md-clear', 'ssbd'
and 'pdpe1gb', some AMD ones should be added too probably, but here
it could be worth to add some selected CPU model awareness, so that
flags are only enabled if they can make sense with the selected
model. But one should be able to add this relative easily with this
as base.

Currently this works mostly good, only three things are a bit
non-ideal:
* form reset-tracking is not completely working
* the grid height is sometimes cut a bit short without an scroll bar,
  this is the parent inputpanel rendering "to early" and thus having
  a miscalculated size, clicking reset should fix it.
* hardcoded flag lists is not ideal, we should try to generate this
  in the future, but here already qemu-server is lacking and this is
  rather independent of the fact and can be done later one just fine
  too.

Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---

for stable-5, as that one already has the MD-Clear patches (in qemu-server
and pve-qemu *git*)

 www/manager6/Makefile                  |   1 +
 www/manager6/form/VMCPUFlagSelector.js | 150 +++++++++++++++++++++++++
 www/manager6/qemu/ProcessorEdit.js     |  46 +++-----
 3 files changed, 168 insertions(+), 29 deletions(-)
 create mode 100644 www/manager6/form/VMCPUFlagSelector.js

diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 853fcb4f..b9a6dd14 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -61,6 +61,7 @@ JSSRC= 				                 	\
 	form/GlobalSearchField.js			\
 	form/QemuBiosSelector.js			\
 	form/VMSelector.js			\
+	form/VMCPUFlagSelector.js			\
 	form/USBSelector.js				\
 	form/CalendarEvent.js				\
 	form/CephPoolSelector.js				\
diff --git a/www/manager6/form/VMCPUFlagSelector.js b/www/manager6/form/VMCPUFlagSelector.js
new file mode 100644
index 00000000..a20da790
--- /dev/null
+++ b/www/manager6/form/VMCPUFlagSelector.js
@@ -0,0 +1,150 @@
+/*jslint confusion: true*/
+Ext.define('PVE.form.VMCPUFlagSelector', {
+    extend: 'Ext.grid.Panel',
+    alias: 'widget.vmcpuflagselector',
+
+    mixins: {
+	field: 'Ext.form.field.Field'
+    },
+
+    disableSelection: true,
+    columnLines: false,
+    selectable: false,
+    hideHeaders: true,
+
+    value: '',
+    unkownFlags: [],
+
+    store: {
+	type: 'store',
+	fields: ['flag', 'state', 'desc'],
+	data: [
+	    { flag: 'pcid', state: '=', desc: 'Meltdown fix cost reduction on Westmere, SandyBridge, and IvyBridge Intel CPU models' },
+	    { flag: 'spec-ctrl', state: '=', desc: 'Enhances Spectre mitigation, defaul on -IBRS CPUs' },
+	    { flag: 'md-clear', state: '=', desc: 'Required to confirm the MDS fixes' },
+	    { flag: 'ssbd', state: '=', desc: 'Required to enable the CVE-2018-3639 fix' },
+	    { flag: 'pdpe1gb', state: '=', desc: 'Required to allow guest OS to use 1GB size pages' },
+	],
+	listeners: {
+	    update: function() {
+		this.commitChanges();
+	    }
+	}
+    },
+
+    getValue: function() {
+	var me = this;
+	var store = me.getStore();
+	var flags = '';
+
+	// ExtJS does not has a nice getAllRecords interface for stores :/
+	store.queryRecordsBy(function() {return true;}).forEach(function(rec) {
+	    var s = rec.get('state');
+	    if (s && s !== '=') {
+		var f = rec.get('flag');
+		if (flags === '') {
+		    flags = s + f;
+		} else {
+		    flags += ';' + s + f;
+		}
+	    }
+	});
+
+	flags += me.unkownFlags.join(';');
+
+	return flags;
+    },
+
+    setValue: function(value) {
+	var me = this;
+	var store = me.getStore();
+
+	me.unkownFlags = [];
+
+	var flags = value ? value.split(';') : [];
+	flags.forEach(function(flag) {
+	    var sign = flag.substr(0, 1);
+	    flag = flag.substr(1);
+
+	    var rec = store.findRecord('flag', flag);
+	    if (rec !== null) {
+		rec.set('state', sign);
+	    } else {
+		me.unkownFlags.push(flag);
+	    }
+	});
+
+	store.reload();
+	//return me.callParent([value]);
+	me.resetOriginalValue();
+	return me.mixins.field.setValue.call(me, value);
+    },
+    columns: [
+	{
+	    xtype: 'widgetcolumn',
+	    dataIndex: 'state',
+	    onWidgetAttach: function (column, widget, record) {
+		var val = record.get('state') || '=';
+		widget.down('[inputValue=' + val + ']').setValue(true);
+		widget.rec = record;
+		widget.originalVal = val;
+		// TODO: disable if selected CPU model and flag are incompatible
+	    },
+	    widget: {
+		xtype: 'radiogroup',
+		hideLabel: true,
+		layout: 'hbox',
+		validateOnChange: false,
+		listeners: {
+		    change: function(f, value) {
+			if (f.rec) {
+			    var v = Object.values(value)[0];
+			    f.rec.set('state', v);
+			}
+		    }
+		},
+		items: [
+		    {
+			boxLabel: '-',
+			boxLabelAlign: 'before',
+			inputValue: '-'
+		    },
+		    {
+			//boxLabel: '=' ,
+			checked: true,
+			inputValue: '='
+		    },
+		    {
+			boxLabel: '+',
+			inputValue: '+'
+		    }
+		]
+	    },
+	    flex: 2
+	},
+	{
+	    header: 'Extra CPU Flag',
+	    dataIndex: 'flag',
+	    flex: 2
+	},
+	{
+	    header: 'Description',
+	    dataIndex: 'desc',
+	    cellWrap: true,
+	    flex: 5
+	},
+	{
+	    header: 'Extra CPU Flag',
+	    dataIndex: 'state',
+	    renderer: function(v) {
+		switch(v) {
+		    case '=': return 'Default';
+		    case '-': return 'Disable';
+		    case '+': return 'Enable';
+		    default: return 'Unknown';
+		}
+	    },
+	    flex: 2
+	}
+    ]
+});
diff --git a/www/manager6/qemu/ProcessorEdit.js b/www/manager6/qemu/ProcessorEdit.js
index 4c0524eb..4853d9ff 100644
--- a/www/manager6/qemu/ProcessorEdit.js
+++ b/www/manager6/qemu/ProcessorEdit.js
@@ -42,16 +42,11 @@ Ext.define('PVE.qemu.ProcessorInputPanel', {
 	// build the cpu options:
 	me.cpu.cputype = values.cputype;
 
-	var flags = [];
-
-	['pcid', 'spec-ctrl'].forEach(function(flag) {
-	    if (values[flag]) {
-		flags.push('+' + flag.toString());
-	    }
-	    delete values[flag];
-	});
-
-	me.cpu.flags = flags.length ? flags.join(';') : undefined;
+	if (values.flags) {
+	    me.cpu.flags = values.flags;
+	} else {
+	    delete me.cpu.flags;
+	}
 
 	delete values.cputype;
 	delete values.flags;
@@ -141,7 +136,10 @@ Ext.define('PVE.qemu.ProcessorInputPanel', {
 	    fieldLabel: gettext('CPU limit'),
 	    allowBlank: true,
 	    emptyText: gettext('unlimited')
-	},
+	}
+    ],
+
+    advancedColumn2: [
 	{
 	    xtype: 'proxmoxintegerfield',
 	    name: 'cpuunits',
@@ -151,27 +149,22 @@ Ext.define('PVE.qemu.ProcessorInputPanel', {
 	    value: '1024',
 	    deleteEmpty: true,
 	    allowBlank: true
-	}
-    ],
-
-    advancedColumn2: [
+	},
 	{
 	    xtype: 'proxmoxcheckbox',
 	    fieldLabel: gettext('Enable NUMA'),
 	    name: 'numa',
 	    uncheckedValue: 0
 	},
+    ],
+    advancedColumnB: [
 	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: 'PCID',
-	    name: 'pcid',
-	    uncheckedValue: 0
+	    xtype: 'label',
+	    text: 'Extra CPU Flags:'
 	},
 	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: 'SPEC-CTRL',
-	    name: 'spec-ctrl',
-	    uncheckedValue: 0
+	    xtype: 'vmcpuflagselector',
+	    name: 'flags'
 	}
     ]
 });
@@ -200,12 +193,7 @@ Ext.define('PVE.qemu.ProcessorEdit', {
 		    ipanel.cpu = cpu;
 		    data.cputype = cpu.cputype;
 		    if (cpu.flags) {
-			var flags = cpu.flags.split(';');
-			flags.forEach(function(flag) {
-			    var sign = flag.substr(0,1);
-			    flag = flag.substr(1);
-			    data[flag] = (sign === '+');
-			});
+			data.flags = cpu.flags;
 		    }
 		}
 		me.setValues(data);
-- 
2.20.1





More information about the pve-devel mailing list