Configure the numvfs for SRIOV interfaces
authorkarthik s <ksundara@redhat.com>
Fri, 26 Aug 2016 16:18:04 +0000 (21:48 +0530)
committerkarthik s <ksundara@redhat.com>
Mon, 29 Aug 2016 14:11:35 +0000 (19:41 +0530)
This patch shall create VFs via the PCI SYS interface.
Default value : $::os_service_default
Sample Format : ['eth0:4','eth2:128']
For values as in sample format, the sriov_numvfs config files
for eth0 and eth2 will have the values 4 and 128 respectively
The SR-IOV numvfs configuration shall be persisted in /sbin/ifup-local
so that, during the bootup of the compute nodes, the numvfs
configuration will be restored.

Change-Id: I7450b904475bdf46498d9af633416b3eba12f761
Implements: blueprint tripleo-sriov
Signed-off-by: karthik s <ksundara@redhat.com>
lib/puppet/provider/sriov_vf_config/numvfs.rb [new file with mode: 0644]
lib/puppet/type/sriov_vf_config.rb [new file with mode: 0644]
manifests/host/sriov.pp [new file with mode: 0644]
manifests/host/sriov/numvfs_persistence.pp [new file with mode: 0644]
manifests/profile/base/neutron/sriov.pp
releasenotes/notes/sriov_numvfs-40564db9e1be589b.yaml [new file with mode: 0644]
spec/classes/tripleo_host_sriov_spec.rb [new file with mode: 0644]
spec/defines/tripleo_host_sriov_numvfs_persistence_spec.rb [new file with mode: 0644]
spec/unit/provider/sriov_vf_config/numvfs_spec.rb [new file with mode: 0644]
spec/unit/type/sriov_vf_config_spec.rb [new file with mode: 0644]

diff --git a/lib/puppet/provider/sriov_vf_config/numvfs.rb b/lib/puppet/provider/sriov_vf_config/numvfs.rb
new file mode 100644 (file)
index 0000000..cfa663c
--- /dev/null
@@ -0,0 +1,57 @@
+Puppet::Type.type(:sriov_vf_config).provide(:numvfs) do
+  desc <<-EOT
+    The file /sys/class/net/<sriov_interface_name>/device/sriov_numvfs will be
+    present when a physical PCIe device supports SR-IOV. A number written to
+    this file will enable the specified number of VFs. This provider shall read
+    the file and ensure that the value is zero, before writing the number of
+    VFs that should be enabled. If the VFs needs to be disabled then we shall
+    write a zero to this file.
+  EOT
+
+  def create
+    if File.file?(sriov_numvfs_path)
+      _set_numvfs
+    else
+      fail("#{sriov_numvfs_path} doesn't exist. Check if #{sriov_get_interface} is a valid network interface supporting SR-IOV")
+    end
+  end
+
+  def destroy
+    if File.file?(sriov_numvfs_path)
+      File.write(sriov_numvfs_path,"0")
+    end
+  end
+
+  def exists?
+    if File.file?(sriov_numvfs_path)
+      cur_value = File.read(sriov_numvfs_path)
+      if cur_value.to_i == sriov_numvfs_value
+        return true
+      end
+    end
+    return false
+  end
+
+  def _set_numvfs
+    # During an update, the content of file sriov_numvfs_path has to be set
+    # to 0 (ZERO), before writing the actual value
+    cur_value = File.read(sriov_numvfs_path)
+    if cur_value != 0
+      File.write(sriov_numvfs_path,"0")
+    end
+    File.write(sriov_numvfs_path,sriov_numvfs_value)
+  end
+
+  def sriov_numvfs_path
+    "/sys/class/net/#{sriov_get_interface}/device/sriov_numvfs"
+  end
+
+  def sriov_get_interface
+    resource[:name].split(':', 2).first
+  end
+
+  def sriov_numvfs_value
+    resource[:name].split(':', 2).last.to_i
+  end
+
+end
diff --git a/lib/puppet/type/sriov_vf_config.rb b/lib/puppet/type/sriov_vf_config.rb
new file mode 100644 (file)
index 0000000..09a3671
--- /dev/null
@@ -0,0 +1,10 @@
+Puppet::Type.newtype(:sriov_vf_config) do
+
+  ensurable
+
+  newparam(:name) do
+    desc "sriov_numvfs conf as <physical_network>:<number_of_vfs> format"
+    newvalues(/^[a-z0-9\-_]+:[0-9]+$/)
+  end
+
+end
diff --git a/manifests/host/sriov.pp b/manifests/host/sriov.pp
new file mode 100644 (file)
index 0000000..a30db42
--- /dev/null
@@ -0,0 +1,27 @@
+# == Class: tripleo::host::sriov
+#
+# Configures host configuration for the SR-IOV interfaces
+#
+# === Parameters
+#
+# [*number_of_vfs*]
+#   (optional) List of <physical_network>:<number_of_vfs> specifying the number
+#   VFs to be exposed per physical interface.
+#   For example, to configure two interface with number of VFs, specify
+#   it as ['eth1:4','eth2:10']
+#   Defaults to []
+#
+class tripleo::host::sriov (
+  $number_of_vfs = [],
+) {
+
+  if !empty($number_of_vfs) {
+    sriov_vf_config { $number_of_vfs: ensure => present }
+
+    # the numvfs configuration needs to be persisted for every boot
+    tripleo::host::sriov::numvfs_persistence {'persistent_numvfs':
+      vf_defs        => $number_of_vfs,
+      content_string => "#!/bin/bash\n"
+    }
+  }
+}
diff --git a/manifests/host/sriov/numvfs_persistence.pp b/manifests/host/sriov/numvfs_persistence.pp
new file mode 100644 (file)
index 0000000..1ee402c
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# tripleo::host::sriov::numvfs_persistence used by tripleo::host::sriov
+#
+# === Parameters:
+#
+# [*vf_defs*]
+#   (required) Array of of <physical_interface>:<numvfs>.
+#   Example: ['eth1:10','eth2:8']
+#
+# [*content_string*]
+#   (required) String which shall be written to the script file.
+#
+define tripleo::host::sriov::numvfs_persistence(
+  $vf_defs,
+  $content_string
+){
+  # Since reduce isn't available, we use recursion to iterate each entries of
+  # "physical_interface:vfs" and accumulate the content that needs to be
+  # written to the script file.
+  include ::stdlib
+
+  if empty($vf_defs) {
+    file { '/etc/sysconfig/allocate_vfs':
+      ensure  => file,
+      content => $content_string,
+      group   => 'root',
+      mode    => '0755',
+      owner   => 'root',
+    }
+
+    file { '/sbin/ifup-local':
+      group   => 'root',
+      mode    => '0755',
+      owner   => 'root',
+      content => '#!/bin/bash',
+      replace => false
+    }
+
+    file_line { 'call_ifup-local':
+      path    => '/sbin/ifup-local',
+      line    => '/etc/sysconfig/allocate_vfs $1',
+      require => File['/sbin/ifup-local'],
+    }
+  } else {
+    $vfspec = split($vf_defs[0], ':')
+    $interface = $vfspec[0]
+    $count = $vfspec[1]
+    $vfdef_str = "${content_string}[ \"${interface}\" == \"\$1\" ] && echo ${count} > /sys/class/net/${interface}/device/sriov_numvfs\n"
+    tripleo::host::sriov::numvfs_persistence{"mapped ${interface}":
+      vf_defs        => delete_at($vf_defs, 0),
+      content_string => $vfdef_str
+    }
+  }
+}
+
index 9b5f34c..00ecc21 100644 (file)
@@ -36,6 +36,7 @@ class tripleo::profile::base::neutron::sriov(
   if $step >= 4 {
     if 'sriovnicswitch' in $mechanism_drivers  {
       include ::neutron::agents::ml2::sriov
+      include ::tripleo::host::sriov
     }
   }
 
diff --git a/releasenotes/notes/sriov_numvfs-40564db9e1be589b.yaml b/releasenotes/notes/sriov_numvfs-40564db9e1be589b.yaml
new file mode 100644 (file)
index 0000000..85cbdec
--- /dev/null
@@ -0,0 +1,4 @@
+---
+features:
+  - Added a provider to configure VFs for SR-IOV interface.
+    Added a define for persistence of the VFs configuratin.
diff --git a/spec/classes/tripleo_host_sriov_spec.rb b/spec/classes/tripleo_host_sriov_spec.rb
new file mode 100644 (file)
index 0000000..15d3813
--- /dev/null
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe 'tripleo::host::sriov' do
+
+  shared_examples_for 'sriov vfs configuration for Red Hat distributions' do
+
+    let :facts do
+      {
+        :osfamily                  => 'RedHat',
+        :operatingsystemmajrelease => 7,
+      }
+    end
+
+    let :params do
+      {:number_of_vfs => []}
+    end
+
+    it 'does not configure numvfs by default' do
+      is_expected.not_to contain_sriov_vf_config([])
+    end
+
+    context 'when number_of_vfs is configured' do
+      let :params do
+        {:number_of_vfs => ['eth0:4','eth1:5']}
+      end
+
+      it 'configures numvfs' do
+        is_expected.to contain_sriov_vf_config('eth0:4').with( :ensure => 'present' )
+        is_expected.to contain_sriov_vf_config('eth1:5').with( :ensure => 'present')
+        is_expected.to contain_tripleo__host__sriov__numvfs_persistence('persistent_numvfs').with(
+          :vf_defs        => ['eth0:4','eth1:5'],
+          :content_string => "#!/bin/bash\n"
+        )
+      end
+    end
+  end
+
+  it_configures 'sriov vfs configuration for Red Hat distributions'
+end
diff --git a/spec/defines/tripleo_host_sriov_numvfs_persistence_spec.rb b/spec/defines/tripleo_host_sriov_numvfs_persistence_spec.rb
new file mode 100644 (file)
index 0000000..57559a2
--- /dev/null
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe 'tripleo::host::sriov::numvfs_persistence' do
+
+  describe 'confugure numvfs for persistence' do
+
+    let :title do
+      'numvfs'
+    end
+
+    let :params do
+      {
+        :name           => 'persistence',
+        :vf_defs        => ['eth0:10','eth1:8'],
+        :content_string => "Hashbang\n"
+      }
+    end
+
+    it 'configures persistence' do
+      is_expected.to contain_file('/etc/sysconfig/allocate_vfs').with(
+        :ensure  => 'file',
+        :content => "Hashbang\n[ \"eth0\" == \"\$1\" ] && echo 10 > /sys/class/net/eth0/device/sriov_numvfs\n[ \"eth1\" == \"\$1\" ] && echo 8 > /sys/class/net/eth1/device/sriov_numvfs\n",
+        :group   => 'root',
+        :mode    => '0755',
+        :owner   => 'root',
+      )
+      is_expected.to contain_file('/sbin/ifup-local').with(
+        :group   => 'root',
+        :mode    => '0755',
+        :owner   => 'root',
+        :content => '#!/bin/bash',
+        :replace => false,
+      )
+      is_expected.to contain_file_line('call_ifup-local').with(
+        :path => '/sbin/ifup-local',
+        :line => '/etc/sysconfig/allocate_vfs $1',
+      )
+    end
+  end
+end
diff --git a/spec/unit/provider/sriov_vf_config/numvfs_spec.rb b/spec/unit/provider/sriov_vf_config/numvfs_spec.rb
new file mode 100644 (file)
index 0000000..ac1a398
--- /dev/null
@@ -0,0 +1,40 @@
+require 'puppet'
+require 'spec_helper'
+require 'puppet/provider/sriov_vf_config/numvfs'
+
+provider_class = Puppet::Type.type(:sriov_vf_config).
+  provider(:numvfs)
+
+describe provider_class do
+
+  let(:test_cfg_path) { "/tmp/test-ifup-local.txt" }
+  let :numvfs_conf do
+    {
+      :name   => 'eth0:10',
+      :ensure => 'present',
+    }
+  end
+
+  describe 'when setting the attributes' do
+    let :resource do
+      Puppet::Type::Sriov_vf_config.new(numvfs_conf)
+    end
+
+    let :provider do
+      provider_class.new(resource)
+    end
+
+    it 'should return the correct interface name' do
+      expect(provider.sriov_get_interface).to eql('eth0')
+    end
+
+    it 'should return the correct numvfs value' do
+      expect(provider.sriov_numvfs_value).to eql(10)
+    end
+
+    it 'should return path of the file to enable vfs' do
+      expect(provider.sriov_numvfs_path).to eql('/sys/class/net/eth0/device/sriov_numvfs')
+    end
+  end
+
+end
diff --git a/spec/unit/type/sriov_vf_config_spec.rb b/spec/unit/type/sriov_vf_config_spec.rb
new file mode 100644 (file)
index 0000000..9a911f6
--- /dev/null
@@ -0,0 +1,47 @@
+require 'puppet'
+require 'puppet/type/sriov_vf_config'
+
+describe 'Puppet::Type.type(:sriov_vf_config)' do
+  it 'should allow name to be passed' do
+    expect{Puppet::Type.type(:sriov_vf_config).new(
+      :name   => 'eth0:10',
+      :ensure => 'present'
+    )}.not_to raise_error
+  end
+  it 'should allow name to be passed with -' do
+    expect{Puppet::Type.type(:sriov_vf_config).new(
+      :name   => 'eth-0:10',
+      :ensure => 'present'
+    )}.not_to raise_error
+  end
+  it 'should allow name to be passed with _' do
+    expect{Puppet::Type.type(:sriov_vf_config).new(
+      :name   => 'eth_0:10',
+      :ensure => 'present'
+    )}.not_to raise_error
+  end
+  it 'should throw error for invalid format' do
+    expect{Puppet::Type.type(:sriov_vf_config).new(
+      :name   => 'eth0',
+      :ensure => 'present'
+    )}.to raise_error(Puppet::ResourceError)
+  end
+  it 'should throw error for invalid format without interface name' do
+    expect{Puppet::Type.type(:sriov_vf_config).new(
+      :name   => ':9',
+      :ensure => 'present'
+    )}.to raise_error(Puppet::ResourceError)
+  end
+  it 'should throw error for invalid format for numvfs' do
+    expect{Puppet::Type.type(:sriov_vf_config).new(
+      :name   => 'eth8:none',
+      :ensure => 'present'
+    )}.to raise_error(Puppet::ResourceError)
+  end
+  it 'should throw error for invalid format without numvfs' do
+    expect{Puppet::Type.type(:sriov_vf_config).new(
+      :name   => 'eth0:',
+      :ensure => 'present'
+    )}.to raise_error(Puppet::ResourceError)
+  end
+end