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以降のリポジトリーパッケージを使う場合は、以下をご覧ください。
インストール
次のようにコマンドを実行して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
後編に続きます。