From d57cb3edadcd6833eeed4923ea7e6eceefb3196e Mon Sep 17 00:00:00 2001 From: Tristan Robert Date: Tue, 23 Feb 2021 12:00:30 +0100 Subject: [PATCH] feat: :sparkles: fixes Add missing Meltdown / Spectre related CPU flags #69 --- lib/fog/proxmox/helpers/cpu_helper.rb | 58 +++++++++++++++++++-------- spec/helpers/cpu_helper_spec.rb | 47 +++++++++++++--------- 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/lib/fog/proxmox/helpers/cpu_helper.rb b/lib/fog/proxmox/helpers/cpu_helper.rb index 60ecbd9..2510360 100644 --- a/lib/fog/proxmox/helpers/cpu_helper.rb +++ b/lib/fog/proxmox/helpers/cpu_helper.rb @@ -21,33 +21,59 @@ module Fog module Proxmox # module Cpu mixins module CpuHelper - CPU_REGEXP = /(\bcputype=)?([\w-]+)[,]?(\bflags=)?(\+[\w-]+)?[;]?(\+[\w-]+)?/ - def self.extract(cpu,i) - cpu ? CPU_REGEXP.match(cpu.to_s)[i] : '' + CPU_REGEXP = /(\bcputype=)?(?[\w-]+)[,]?(\bflags=)?(?[[\+\-][\w-]+[;]?]*)/ + FLAGS = { spectre: 'spec-ctrl', pcid: 'pcid', ssbd: 'ssbd', ibpb: 'ibpb', virt_ssbd: 'virt-ssbd', amd_ssbd: 'amd-ssbd', amd_no_ssb: 'amd-no-ssb', md_clear: 'md-clear', pdpe1gb: 'pdpe1gb', hv_tlbflush: 'hv-tlbflush', aes: 'aes', hv_evmcs: 'hv-evmcs' } + def self.flags + FLAGS + end + + def self.extract(cpu, name) + captures_h = cpu ? CPU_REGEXP.match(cpu.to_s) : { cputype: '', flags: '' } + captures_h[name] + end + + def self.extract_cputype(cpu) + extract(cpu, :cputype) + end + + def self.extract_flags(cpu) + extract(cpu, :flags) end - def self.extract_type(cpu) - extract(cpu,2) + def self.flag_value(cpu, flag_key) + flag_value = '0' + raw_values = extract_flags(cpu).split(';').select { |flag| ['+' + flag_key, '-' + flag_key].include?(flag) } + unless raw_values.empty? + flag_value = raw_values[0].start_with?('+') ? '+1' : raw_values[0].start_with?('-') ? '-1' : '0' + end + flag_value end - def self.has_pcid?(cpu) - extract(cpu,5) == '+pcid' + def self.hash_has_no_default_flag?(cpu_h, flag_name) + cpu_h.key?(flag_name) && ['-1', '+1'].include?(cpu_h[flag_name]) end - def self.has_spectre?(cpu) - extract(cpu,4) == '+spec-ctrl' + def self.hash_flag(cpu_h, flag_name) + flag = '' + if cpu_h.key?(flag_name) + flag = '+' if cpu_h[flag_name] == '+1' + flag = '-' if cpu_h[flag_name] == '-1' + end + flag end def self.flatten(cpu_h) - return {} unless cpu_h['cpu_type'] + return '' unless cpu_h['cpu_type'] cpu_type = "cputype=#{cpu_h['cpu_type']}" - spectre = cpu_h['spectre'].to_i == 1 - pcid = cpu_h['pcid'].to_i == 1 - cpu_type += ',flags=' if spectre || pcid - cpu_type += '+spec-ctrl' if spectre - cpu_type += ';' if spectre && pcid - cpu_type += '+pcid' if pcid + num_flags = 0 + FLAGS.each_key { |flag_key| num_flags += 1 if hash_has_no_default_flag?(cpu_h, flag_key.to_s) } + cpu_type += ',flags=' if num_flags > 0 + flags_with_no_default_value = FLAGS.select { |flag_key, _flag_value| hash_has_no_default_flag?(cpu_h, flag_key.to_s) } + flags_with_no_default_value.each_with_index do |(flag_key, flag_value), index| + cpu_type += hash_flag(cpu_h, flag_key.to_s) + flag_value if hash_has_no_default_flag?(cpu_h, flag_key.to_s) + cpu_type += ';' if num_flags > index + 1 + end cpu_type end end diff --git a/spec/helpers/cpu_helper_spec.rb b/spec/helpers/cpu_helper_spec.rb index 2549bcb..fe411ed 100644 --- a/spec/helpers/cpu_helper_spec.rb +++ b/spec/helpers/cpu_helper_spec.rb @@ -23,10 +23,10 @@ describe Fog::Proxmox::CpuHelper do let(:cpu) do - 'cputype=Skylake-Client,flags=+spec-ctrl;+pcid' + 'cputype=Skylake-Client,flags=+spec-ctrl;+pcid;+ssbd;-aes' end let(:cpu_nocputype) do - 'kvm64,flags=+spec-ctrl;+pcid' + 'kvm64,flags=+spec-ctrl;+pcid;+ssbd' end let(:cpu_nospectre) do 'cputype=kvm64,flags=+pcid' @@ -34,37 +34,44 @@ let(:cpu_nopcid) do 'cputype=kvm64,flags=+spec-ctrl' end + let(:cpu_nossbd) do + 'cputype=kvm64,flags=+pcid' + end - describe '#extract_type' do + describe '#extract_cputype' do it "returns string" do - result = Fog::Proxmox::CpuHelper.extract_type(cpu) + result = Fog::Proxmox::CpuHelper.extract_cputype(cpu) assert_equal('Skylake-Client', result) end it "returns string" do - result = Fog::Proxmox::CpuHelper.extract_type(cpu_nocputype) + result = Fog::Proxmox::CpuHelper.extract_cputype(cpu_nocputype) assert_equal('kvm64', result) end end - describe '#has_spectre?' do - it "returns true" do - result = Fog::Proxmox::CpuHelper.has_spectre?(cpu) - assert result + describe '#flag_value' do + it "returns +1" do + result = Fog::Proxmox::CpuHelper.flag_value(cpu, 'spec-ctrl') + assert_equal('+1', result) end - it "returns false" do - result = Fog::Proxmox::CpuHelper.has_spectre?(cpu_nospectre) - assert !result + it "returns -1" do + result = Fog::Proxmox::CpuHelper.flag_value(cpu, 'aes') + assert_equal('-1', result) + end + it "returns 0" do + result = Fog::Proxmox::CpuHelper.flag_value(cpu, 'amd-ssbd') + assert_equal('0', result) end end - - describe '#has_pcid?' do - it "returns true" do - result = Fog::Proxmox::CpuHelper.has_pcid?(cpu) - assert result + + describe '#flatten ' do + it "returns cputype=kvm64,flags=+pcid;+ibpb;-hv-tlbflush" do + result = Fog::Proxmox::CpuHelper.flatten("cpu_type"=>"kvm64", "spectre"=>"0", "pcid"=>"+1", "ssbd"=>"0", "ibpb"=>"+1", "virt_ssbd"=>"0", "amd_ssbd"=>"0", "amd_no_ssb"=>"0", "md_clear"=>"0", "pdpe1gb"=>"0", "hv_tlbflush"=>"-1", "aes"=>"0", "hv_evmcs"=>"0") + assert_equal('cputype=kvm64,flags=+pcid;+ibpb;-hv-tlbflush', result) end - it "returns false" do - result = Fog::Proxmox::CpuHelper.has_pcid?(cpu_nopcid) - assert !result + it "returns cputype=Skylake-Client,flags=+spec-ctrl;+pcid;+amd-no-ssbd'" do + result = Fog::Proxmox::CpuHelper.flatten('cpu_type' => 'Skylake-Client', 'pcid' => '+1', 'spectre' => '+1', 'amd_no_ssb' => '-1') + assert_equal('cputype=Skylake-Client,flags=+spec-ctrl;+pcid;-amd-no-ssb', result) end end end \ No newline at end of file