【SR-IOV】仮想マシンにVFを割り当てる手順

# 0. はじめに
SR-IOVに対応したNICを利用すると、**仮想マシンやコンテナで構築されたネットワークの高速化や低遅延化**が期待できます。
本記事では、**仮想マシンのネットワーク・インターフェースとしてVF**（**SR-IOVの利用によって生成される仮想化された軽量のPCie機能**）**を割り当てる手順**を紹介します。

## 0.1 物理マシンの情報
OS : Ubuntu 18.04
arch : x86_64
NIC : Intel NIC X540-AT2
# 1. SR-IOVとは
SR-IOV (Single Root Input/Output Virtualization) とは、**PCIeリソースを独立な複数のPCIeリソースに分割する仮想化技術**です。
SR-IOVを有効化し、適切な設定を施すと、PF（完全なPCIe機能）と複数のVF（軽量なPCIe機能）を生成することができます。
SR-IOVを利用することで、**ホスト上の仮想マシンやコンテナにPCIeリソースを個別に割り当てることで、高スループットで低遅延なネットワークを構築**することができます。

# 2. SR-IOVの有効化と設定
※SR-IOVに対応したNICとドライバーが用意されていることが前提となります。

## 2.1 NICに関する情報の確認

下記コマンドより、NICの型番を確認しました。
今回利用するNICは、**Intel NIC X540-AT2**でした。
```
# lspci 
03:00.0 Ethernet controller: Intel Corporation Ethernet Controller 10-Gigabit X540-AT2 (rev 01)
03:00.1 Ethernet controller: Intel Corporation Ethernet Controller 10-Gigabit X540-AT2 (rev 01)
```
下記コマンドより、ドライバーを確認しました。
ドライバーは、DPDK対応ドライバーの**ixgbe**でした。
- DPDK対応のIntel NIC一覧：http://core.dpdk.org/supported/nics/intel/
```
# ethtool -i enp3s0f0
driver: ixgbe
version: 5.1.0-k
firmware-version: 0x80000389
expansion-rom-version: 
bus-info: 0000:03:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: yes
```


## 2.2 CPUやIO仮想化技術の有効化
SR-IOVを利用するためには、CPU仮想化（VT-xやAMD-Vと呼ばれる）とIO仮想化（VT-dまたはIOMMUと呼ばれる）を有効化する必要があります。

### 2.2.1 CPU仮想化 
BIOSの設定画面で、VT-x、または、AMD-Vを有効化します。
有効化されたことを確認するためには、以下のコマンドを実行します。
何らかの情報が表示されれば、CPU仮想化が有効化されていると言えます。
```
# cat /proc/cpuinfo | grep vmx
```
### 2.2.2 IO仮想化 
以下のように、/etc/default/grubを編集します。
```
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"
```
grub設定ファイルに変更を反映させます。
```
# sudo grub-mkconfig -o /boot/grub/grub.cfg
```
マシンを再起動させます。
```
# sudo reboot
``` 
再起動後、以下のコマンドにて、ブート時の設定を確認すると、**IOMMU enabled**となっており、IOMMUが利用可能になっていることが確認できます。
``` 
# dmesg | grep -E "DMAR|IOMMU"
[    0.000000] ACPI: DMAR 0x000000008F2A0668 000070 (v01 MOUSEC COMPUTER 00000001 INTL 00000001)
[    0.000000] ACPI: Reserving DMAR table memory at [mem 0x8f2a0668-0x8f2a06d7]
[    0.000000] DMAR: IOMMU enabled
```
# 3. SR-IOVの利用
今回は、予め用意した仮想マシン（VM）に対してVFを接続します。

## 3.1 VFの作成
以下のコマンドにて、2つのVFを作成します。
```
# sudo -i
# echo 2 > /sys/class/net/enp3s0f0/device/sriov_numvfs 
```
以下のコマンドにて、VFが作成されているかを確認します。
今回は片方のVFのみを利用します。
```
# lspci | grep "Virtual Function"
03:10.0 Ethernet controller: Intel Corporation X540 Ethernet Controller Virtual Function (rev 01)
03:10.2 Ethernet controller: Intel Corporation X540 Ethernet Controller Virtual Function (rev 01)
```

## 3.2 VFの接続
先ずは、システムに接続されているデバイス一覧を表示させます。
VFが認識されていること、デバイスとして認識される際の名前を確認します。
```
# virsh nodedev-list
<省略>
pci_0000_03_10_0
pci_0000_03_10_2
<省略>
```
デバイスの名称である、pci_0000_03_10_0を指定してデバイスの詳細情報を表示させます。
```
# virsh nodedev-dumpxml pci_0000_03_10_0
<device>
  <name>pci_0000_03_10_0</name>
  <path>/sys/devices/pci0000:00/0000:00:1b.4/0000:03:10.0</path>
  <parent>pci_0000_00_1b_4</parent>
  <driver>
    <name>ixgbevf</name>
  </driver>
  <capability type='pci'>
    <domain>0</domain>
    <bus>3</bus>
    <slot>16</slot>
    <function>0</function>
    <product id='0x1515'>X540 Ethernet Controller Virtual Function</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='phys_function'>
      <address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
    </capability>
    <iommuGroup number='14'>
      <address domain='0x0000' bus='0x03' slot='0x10' function='0x0'/>
    </iommuGroup>
    <pci-express>
      <link validity='cap' port='0' speed='5' width='8'/>
      <link validity='sta' width='0'/>
    </pci-express>
  </capability>
</device>
```
今回は、MACアドレスを固定する方法でVFをVMに接続させます。
そのためのファイルを以下のように作成しておきます。
```
# cat /tmp/new-interface.xml
   <interface type='hostdev' managed='yes'>
     <source>
       <address type='pci' domain='0x0000' bus='0x03' slot='0x10' function='0x0'/>
     </source>
     <mac address='52:54:00:6d:90:11'/>
   </interface>
```
VMを起動させておき、以下のコマンドを実行すると、VFが接続されます。
尚、今回は接続の永続化を行っていません。
```
# sudo virsh attach-device ipdk /tmp/new-interface.xml --live
```
# 4. 動作確認
## 4.1 IPアドレスとルーティングの設定
VMにログインし、IPアドレスとルーティングを設定します。
元々のインターフェースはdeactivateにしておきます。
今回、VFのインターフェースの名称は、ens8でした。
以下のコマンドにて、IPアドレスとルーティングを設定しました。
ens8のIPアドレスは、ルーターと同一のサブネットのIPアドレスにしています。
```
# ip a add 192.168.10.31/24 dev ens8
# ip r add default via 192.168.10.1 dev ens8
```
## 4.2 pingによる疎通確認
pingを用いて、VMからVF経由で外部に接続できることを確認します。
無事に疎通していることを確認できました。
```
#  ping 8.8.8.8 -c 3
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=13.2 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=118 time=12.3 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=118 time=12.4 ms

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 12.304/12.656/13.204/0.413 ms
```
# 5. まとめ
本記事では、仮想マシンのネットワーク・インターフェースとしてVF（SR-IOVの利用によって生成される仮想化された軽量のPCie機能）を割り当てる手順を紹介しました。
SR-IOVによって生成されたVFをVMに接続し、IPアドレス等の設定をすることで、外部ネットワークに接続できることを確認しました。


# 参考

https://www.server-world.info/query?os=Ubuntu_18.04&p=kvm&f=11

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/sect-sr_iov-using_sr_iov