仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

Ubuntu Xenial (16.04) でOpen vSwitch+DPDKな環境を作る(前編)

Open vSwitch+DPDKが今、熱いようです。

早速、Ubuntu XenialでOpen vSwitch+DPDKな環境を作ってみることにしました。次のバージョンのUbuntuを使って動作確認しました。

$ cat /proc/version_signature
Ubuntu 4.4.0-53.74-generic 4.4.30
$ cat /etc/lsb-release |grep DISTRIB_DESCRIPTION
DISTRIB_DESCRIPTION="Ubuntu 16.04.1 LTS"

[2017/7/6 追記] Ubuntu 4.4.0-83.106-generic 4.4.70、Ubuntu 16.04.2 LTSで前後編を動作確認。

NICの確認

まずは動かそうとしているサーバーに対応するNICが実装されていることを確認します。 なお、NICによってサポートしている機能に差があるため、使おうとしている機能がそのNICで使えることを確認してください。

Numaノードの確認

DPDKポートとして使うNICがどちらのNumaノードに格納されているか確認します。 本例の場合は、Numaノード0側にNICが接続されていることがわかります。

~# hwloc-ls
Machine (63GB total)
  NUMANode L#0 (P#0 31GB)
  ..
..
 HostBridge L#0
      PCIBridge
        PCI 8086:10fb
          Net L#0 "eno1"
        PCI 8086:10fb
          Net L#1 "eno2"
      PCIBridge
        PCI 1000:0073
          Block(Disk) L#2 "sda"
      PCIBridge
        PCI 8086:1521
          Net L#3 "eno3"
        PCI 8086:1521
          Net L#4 "eno4"
..
NUMANode L#1 (P#1 31GB) + Package L#1 + L3 L#1 (20MB)  
...

numactlコマンドを実行して、CPUコアのNumaノードごとの割り振りを確認します。このサーバーには論理32プロセッサーが実装されていることが確認できます。またメモリーは合計64GB、32GB毎割り振られていることがわかります。

~# numactl -H
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
node 0 size: 32128 MB
node 0 free: 31083 MB
node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31
node 1 size: 32251 MB
node 1 free: 31498 MB
node distances:
node   0   1
  0:  10  20
  1:  20  10

PPAの追加

Ubuntu XenialのOVSはバージョン2.5がサポートされます。より新しいバージョンのOVSをUbuntuで使うには、OpenStackのリポジトリー「CloudArchive」にあるパッケージを使うと便利です。次のコマンドを実行します。

Newtonより新しいバージョンのOpenStackが提供された場合はより新しいバージョンを指定してください。

# add-apt-repository cloud-archive:newton
# apt-get update

Ocata以降のリポジトリーパッケージを使う場合は、以下をご覧ください。

tech.virtualtech.jp

インストール

次のようにコマンドを実行してDPDKとDPDK EnableなOVSをインストールします。 パッケージの依存関係で普通のOVSもインストールされるので、二個目のコマンドで切り替えています。

# apt-get install openvswitch-switch-dpdk dpdk
# update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk

NICのバインド

NIC用のドライバーをバインドするため、modprobeコマンドで読み込みます。

ex.

# modprobe uio_pci_generic 
or
# modprobe vfio-pci 

uio_pci_generic でも良い(パフォーマンスはでない)が、使える環境ならvfio-pciの方が良いようです。

また、e1000のように対応しているNICの場合はuio_pci_genericの代わりに、よりパフォーマンスの良いigb_uioを使うこともできます。Ubuntu Xenialではdpdk-igb-uio-dkmsパッケージの導入により、利用可能になります。

前の手順で読み込んだモジュールを再起動後も読み込むように/etc/modulesに書き込んでください。

# echo "uio_pci_generic" >> /etc/modules

モジュールについてはmodinfoコマンドで概要を確認できます。カーネルを更新すると新しいモジュールが利用できますので最新のものを使うことをおすすめします。Linuxカーネルの更新後は必ずシステムの再起動が必要です。

$ modinfo uio_pci_generic
filename:       /lib/modules/4.4.0-53-generic/kernel/drivers/uio/uio_pci_generic.ko
description:    Generic UIO driver for PCI 2.3 devices
author:         Michael S. Tsirkin <mst@redhat.com>
license:        GPL v2
version:        0.01.0
srcversion:     41BEEDE6B2A7E267E6CCD84
depends:        uio
intree:         Y
vermagic:       4.4.0-53-generic SMP mod_unload modversions

以降の手順は汎用的に利用可能なuio_pci_genericを使う例とします。

ネットワーク設定

管理用NIC以外はコメントアウトします。DPDKがネットワークを管轄するためです。 リモートアクセス用のNICとDPDK用のデバイスは別のものを用意するといいと思います。

# vi /etc/network/interfaces
auto eno1
iface eno1 inet static
address 172.16.214.100
netmask 255.255.0.0
gateway 172.16.0.1
dns-nameservers 8.8.8.8 8.8.4.4

#auto ens1f0
…
#auto ens1f1
…

OVS-DPDK関連の設定変更

まず、次のコマンドを実行してHugePagesを設定します。 ページサイズはのちに動かすアプリケーションに合わせたサイズを指定する必要があります。grep pdpe1gb /proc/cpuinfo |uniq|grep pdpe1gbコマンドを実行してpdpe1gbフラグが出力された場合は1Gの方でページサイズを設定できます。出力されない古いプロセッサーを実装したサーバーでは2Mの方でページサイズを指定してください。1Gで指定した場合、アプリケーションによっては2Mのページも必要な場合があるようです。

# vi /etc/dpdk/dpdk.conf
...
NR_2M_PAGES=8192 (2Mx8192=約16GB分)
...
NR_1G_PAGES=16

# systemctl restart dpdk    #設定を反映
# systemctl enable dpdk    #サービスの永続化

Linuxカーネルパラメーターへの記述

次のようにLinuxカーネルパラメーターでHugePagesを使うための設定を行うこともできます。指定したメモリーサイズは確保されるため、Linux Kernel側から見ると使用中になるので注意してください。改行せずに1行で入力してください。

# vi /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="default_hugepagesz=1G hugepagesz=1G hugepages=16 hugepagesz=2M hugepages=8192"

vfio-pciを使う場合にはVT-dが必要なため、iommu=pt intel_iommu=on の記述が必要です。その場合は次のように実行して、カーネル起動後もIOMMUを有効にするためを入れておきます。 なお、uio_pci_genericを使う場合はこの設定は不要です。

# vi /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="iommu=pt intel_iommu=on"

GRUBの変更を反映させるために次のように実行して、再起動します。

# update-grub && reboot

なお、HPEのサーバーでIOMMUを使うには、次の情報を確認して対応してください。 この対処を施した場合、IOMMUが利用可能になりますが、サーバー前面のステータスランプが警告表示(常時、赤ランプ点滅)になります。ちなみにDellのサーバーでは特に何をする必要もありませんでした。

デバイスの確認とバインド

まず、DPDKのバインド状況を確認します。

# dpdk-devbind --status

初期状態ではコマンドを実行すると次のような出力がされます。「Network devices using DPDK-compatible driver」がnoneと表示されるはずです。この状態ではDPDKがNICに対して有効化されていない状態です。

Network devices using DPDK-compatible driver
============================================
<none>

Network devices using kernel driver
===================================
0000:01:00.0 'NetXtreme II BCM5709 Gigabit Ethernet' if=eno1 drv=bnx2 unused=uio_pci_generic *Active*
0000:01:00.1 'NetXtreme II BCM5709 Gigabit Ethernet' if=eno2 drv=bnx2 unused=uio_pci_generic
0000:02:00.0 'NetXtreme II BCM5709 Gigabit Ethernet' if=eno3 drv=bnx2 unused=uio_pci_generic
0000:02:00.1 'NetXtreme II BCM5709 Gigabit Ethernet' if=eno4 drv=bnx2 unused=uio_pci_generic
0000:07:00.0 '82575GB Gigabit Network Connection' if=enp7s0f0 drv=igb unused=uio_pci_generic
0000:07:00.1 '82575GB Gigabit Network Connection' if=enp7s0f1 drv=igb unused=uio_pci_generic
0000:08:00.0 '82575GB Gigabit Network Connection' if=enp8s0f0 drv=igb unused=uio_pci_generic
0000:08:00.1 '82575GB Gigabit Network Connection' if=enp8s0f1 drv=igb unused=uio_pci_generic

Other network devices
=====================
<none>

Active」とステータスが出ているNICは別の処理で使用中のNICです。NetworkサービスでStaticなIPアドレスを割り当ててUPしているNICであるためです。Linux側で利用しているデバイスはDPDKドライバーを読み込むことはできません。

例えばuio_pci_genericとして、デバイス番号「0000:07:00.0」のNICをバインドするには次のように実行します。アンバインドするには-bオプションを-uに変えて実行してください。

# dpdk-devbind -b uio_pci_generic  0000:07:00.0

もう一度ステータスを確認すると次のように出力されるはずです。これで指定したデバイスでDPDK-compatible driverが読み込まれます。

# dpdk-devbind --status
...
Network devices using DPDK-compatible driver
============================================
0000:07:00.0 '82575GB Gigabit Network Connection' drv=uio_pci_generic unused=igb
...

DPDKバインドしたデバイスをLinux Kernel側に戻すには、同じくdpdk-devbind -bコマンドでドライバーの割り当てを上書きします。例えば先にバインドしたデバイスを元に戻すには現在利用していない(unused)ドライバーを指定すれば良いので、次のように設定することができます。

# dpdk-devbind -b igb 0000:07:00.0

DPDKモジュールの自動読み込みに関する設定

先の手順で手動でバインドしましたが、これは/etc/dpdk/interfacesに記述することで自動的にバインドさせることができます。次のように実行して、指定したデバイス番号のNICでDPDK対応ドライバーを利用するための設定を行っておきます。

# vi /etc/dpdk/interfaces
pci 0000:07:00.0 uio_pci_generic ←追記  

# systemctl restart dpdk    #設定を反映
# systemctl enable dpdk    #サービスの永続化

DPDKとOVSのセットアップ

ここまでできたら、次にOVSの設定を行います。通常のようにOVSを使うのと異なり、いくつかオプションを指定します。以下のページの情報を参考にしましたが、次に実行するコマンドを列挙します。

Documentation/vhost-user-ovs-dpdk - QEMU

# mkdir -p /var/run/openvswitch
# mount -t hugetlbfs -o pagesize=2048k none /dev/hugepages

# modprobe openvswitch

# killall ovsdb-server ovs-vswitchd
# rm -f /var/run/openvswitch/vhost-user*
# rm -f /etc/openvswitch/conf.db

# export DB_SOCK=/var/run/openvswitch/db.sock
# ovsdb-tool create /etc/openvswitch/conf.db /usr/share/openvswitch/vswitch.ovsschema
# ovsdb-server --remote=punix:$DB_SOCK --remote=db:Open_vSwitch,Open_vSwitch,manager_options --pidfile --detach

# ovs-vsctl --no-wait init
# ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-lcore-mask=0xf
# ovs-vsctl --no-wait set Open_vSwitch . other_config:pmd-cpu-mask=0x2
# ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem=1024,1024
# ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
# ovs-vswitchd unix:$DB_SOCK --pidfile --detach --log-file=/var/log/openvswitch/ovs-vswitchd.log
# ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-extra="--vhost-owner root:root --vhost-perm 0666"
# service openvswitch-switch restart

# ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
# ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
# ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuser
# ovs-vsctl show
cd83e731-6786-4985-9102-25c874b87255
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "vhost-user2"
            Interface "vhost-user2"
                type: dpdkvhostuser
        Port "vhost-user1"
            Interface "vhost-user1"
                type: dpdkvhostuser

OVSにDPDKデバイスをバインドします。次のように実行します。

# ovs-vsctl add-port ovsbr0 dpdk0 -- set Interface dpdk0 type=dpdk
(物理デバイスを指定するのではなく、dpdk番号を指定する)

Interface "dpdk0"が追加されたことを確認します。この段階でtopコマンドを実行すると、ovs-vswitchdプロセスのCPU使用率が上がっているのを確認できます。上がっていない場合は/var/log/openvswitch/ovs-vswitchd.logを確認して原因を探ります。例えば、lcoreやpmdの割り当てが足りないとか、dpdk-socket-memの指定の問題などです。

# ovs-vsctl show
cd83e731-6786-4985-9102-25c874b87255
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "vhost-user2"
            Interface "vhost-user2"
                type: dpdkvhostuser
        Port "vhost-user1"
            Interface "vhost-user1"
                type: dpdkvhostuser
        Port "dpdk0"
            Interface "dpdk0"   ←追加された
                type: dpdk

以上でUbuntu Server XenialにOpen vSwitch+DPDKをインストールできます。

DPDKドライバーの切り替え

-uオプションは稀に失敗するので、unbindせずに新しいドライバーをバインドすると上書きできるようです。

# ovs-vsctl del-port ovsbr0 dpdk0
# dpdk-devbind -b igb_uio 0000:07:00.0
# dpdk-devbind --status
Network devices using DPDK-compatible driver
============================================
0000:07:00.0 '82575GB Gigabit Network Connection' drv=igb_uio unused=igb,uio_pci_generic
...
# service openvswitch-switch restart
# ovs-vsctl add-port ovsbr0 dpdk0 -- set Interface dpdk0 type=dpdk

OVSパラメーターの追加

other_configでパラメータを追加してOVSを再起動すると良いようです。

# ovs-vsctl --no-wait set Open_vSwitch . other_config:pmd-cpu-mask=0x2
# service openvswitch-switch restart

後編に続きます。

tech.virtualtech.jp