手当たり次第に書くんだ

飽きっぽいのは本能

Ubuntu 22.04 OVS-DPDK 構築失敗から見る DPDK dataplane の難しさ

Ubuntu 22.04 上で OVS-DPDK を構築し、KVM の vhost-user と組み合わせて高速 dataplane を作ろうとした検証メモです。結論から言うと、この時点では外部通信まで成立せず、構築は失敗しています。

ただし、この失敗は単なる作業ミスの記録ではありません。OVS-DPDK は Linux bridge や通常の Open vSwitch の延長ではなく、IOMMU、HugePages、NIC driver binding、DPDK enabled OVS、vhost-user socket、QEMU の実行権限、VM XML がすべて噛み合って初めて成立する dataplane です。

この記事では、当時の試行錯誤を残しつつ、どこが難しいのか、なぜ OVS-DPDK は通常の仮想ネットワークと別物として扱うべきなのかを整理します。

試したかった構成

当時の目的は、KVM 上の VM に OVS-DPDK の vhost-user port を割り当て、通常の kernel datapath より短い高速 dataplane を作ることでした。さらに発展形として、Kubernetes Multus と組み合わせ、Pod からストレージ向け通信を高速化できないかも考えていました。

  • Ubuntu 22.04 を KVM ホストとして使う
  • Open vSwitch を DPDK datapath で動かす
  • HugePages と IOMMU を有効化する
  • NIC を DPDK 用 driver へ bind する
  • OVS に vhost-user-client port を作る
  • KVM VM の interface を vhost-user にする

発想としては自然ですが、実際には各レイヤの責任境界が通常の VM ネットワークとは大きく変わります。

IOMMU と HugePages を用意する

DPDK を使うには、IOMMU と HugePages が重要になります。IOMMU はデバイス DMA の分離に関係し、HugePages は DPDK の packet buffer を効率よく扱うために使われます。

sudo tee /etc/default/grub <<"EOF"
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt default_hugepagesz=1G hugepagesz=1G hugepages=4"
EOF

sudo update-grub
sudo reboot

再起動後は、IOMMU と HugePages の状態を確認します。

sudo dmesg | grep -i iommu
grep Huge /proc/meminfo

ここまでは DPDK 環境の入口です。ただし、HugePages を確保できていても、それだけで OVS-DPDK が動くわけではありません。NIC、OVS、vhost-user、VM 側の設定が続きます。

OVS を DPDK 用 datapath で動かす

OVS-DPDK では、通常の kernel datapath ではなく、DPDK を利用する ovs-vswitchd を前提にします。ここで通常の OVS と同じ感覚で進めると、datapath の責任境界を見誤ります。

sudo systemctl stop openvswitch-switch
sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024,1024"
sudo systemctl start openvswitch-switch
sudo ovs-vsctl get Open_vSwitch . dpdk_initialized

DPDK が有効になっているかだけでなく、ovs-vswitchd が期待した binary / datapath / HugePages で動いているかを確認する必要があります。

NIC を DPDK 用 driver へ bind する

DPDK で物理 NIC を扱うには、通常の kernel driver から NIC を切り離し、vfio-pci などの driver へ bind します。これは通常の Linux networking から NIC を外す操作でもあります。

sudo dpdk-devbind.py --status
sudo modprobe vfio-pci
sudo dpdk-devbind.py --bind=vfio-pci 0000:xx:yy.z
sudo dpdk-devbind.py --status

ここで NIC を bind すると、その NIC は通常の ip link や NetworkManager の管理対象ではなくなります。つまり、外部通信の見方も通常の Linux NIC とは変わります。

DPDK bridge と vhost-user port を作る

OVS-DPDK 側では、datapath_type=netdev の bridge を作り、dpdk port や vhost-user-client port を追加します。

sudo ovs-vsctl add-br storage -- set bridge storage datapath_type=netdev
sudo ovs-vsctl add-port storage dpdk0 -- set Interface dpdk0 type=dpdk options:dpdk-devargs=0000:xx:yy.z

sudo mkdir -p /opt/openvswitch/vhuc
sudo ovs-vsctl add-port storage storage-vhuc00 \
  -- set Interface storage-vhuc00 type=dpdkvhostuserclient \
  options:vhost-server-path=/opt/openvswitch/vhuc/storage-vhuc00

この時点で、通常の Linux bridge に tap を追加する構成とはかなり違います。OVS-DPDK 側の socket と、QEMU 側の vhost-user interface が正しく対応する必要があります。

状態確認と切り戻し

状態確認では、OVS の bridge / port / interface の状態を確認します。うまくいかない場合は、port や bridge を削除して切り戻します。

sudo ovs-vsctl show
sudo ovs-vsctl list Interface

sudo ovs-vsctl del-port storage storage-vhuc00
sudo ovs-vsctl del-br storage

VM 側に vhost-user interface を割り当てる

VM 側では、libvirt の interface を vhostuser に変更します。socket path、mode、model が OVS-DPDK 側の設定と合っている必要があります。

<interface type='vhostuser'>
  <source type='unix' path='/opt/openvswitch/vhuc/storage-vhuc00' mode='server'/>
  <model type='virtio'/>
</interface>

当時の検証では、ここまで設定したものの、外部通信が成立せず中断しました。vhost-user-client を使う際の QEMU 実行権限、socket の所有権、libvirt / QEMU の動作ユーザー、OVS 側の mode などが関係していた可能性があります。

なぜ失敗したのか

この検証で重要なのは、単一のコマンドが間違っていたというより、OVS-DPDK の構成要素が多く、どこか 1 つでも噛み合わないと通信が成立しない点です。

領域確認すべきこと
IOMMU有効化され、VFIO で安全にデバイスを扱えるか
HugePagesOVS-DPDK が利用できるサイズと量で確保されているか
NIC binding対象 NIC が kernel driver ではなく DPDK 用 driver に bind されているか
OVS-DPDKdpdk-init、socket-mem、datapath_type=netdev が成立しているか
vhost-userOVS 側 socket と QEMU 側 interface が一致しているか
権限QEMU / libvirt が socket へアクセスできるか
経路VM から外部へ出る L2 / L3 経路が成立しているか

通常の仮想ネットワークであれば、Linux bridge、tap、virtio-net を見れば済むことが多いです。しかし OVS-DPDK では、kernel datapath を迂回するため、標準的な Linux networking の観測点も減ります。

OVS-DPDK は通常の OVS の延長ではない

OVS-DPDK は、Open vSwitch の見た目をしていますが、中身は通常の kernel OVS とは別の datapath です。Linux kernel の bridge / OVS に port を足す感覚で扱うと、どこで packet が処理され、どこで drop しているのかが分かりにくくなります。

  • NIC は kernel networking から切り離される
  • packet buffer は HugePages 側で扱われる
  • datapath は userspace 側へ寄る
  • vhost-user socket が VM との接続点になる
  • QEMU / libvirt の権限が datapath の成立条件になる
  • 標準的な ip / tcpdump だけでは見えない領域が増える

この失敗から得られる設計上の教訓

この検証は通信成立までは到達していませんが、DPDK dataplane の難しさを理解する材料としては価値があります。

  • OVS-DPDK は通常の仮想ネットワークより準備する前提が多い
  • IOMMU / HugePages / NIC bind / OVS / QEMU / libvirt を一体で見る必要がある
  • 成功確認は ovs-vsctl show だけでは足りない
  • vhost-user の socket 権限と QEMU 実行ユーザーは重要な確認点になる
  • DPDK dataplane は高速化の設定ではなく、ネットワーク処理の責任境界を変える構成である

VM パフォーマンス Day8 で整理したように、DPDK は Linux kernel network stack を通らない dataplane を作る技術です。したがって、Linux 側の標準的な操作感を期待すると、確認点を見失いやすくなります。

まとめ

Ubuntu 22.04 で OVS-DPDK と KVM vhost-user を組み合わせる検証は、当時は外部通信まで成立せず失敗しました。

しかし、この失敗は OVS-DPDK がなぜ難しいのかをよく示しています。IOMMU、HugePages、NIC binding、OVS-DPDK、vhost-user socket、QEMU / libvirt の権限、VM XML、外部経路がすべて揃わないと dataplane は成立しません。

OVS-DPDK は通常の OVS や Linux bridge の延長ではなく、kernel datapath を迂回する別種の dataplane です。構築する場合は、単なる手順ではなく、どのレイヤがどの責任を持つのかを分けて確認する必要があります。

参考
書籍
参考書籍

作って理解する仮想化技術 ── ハイパーバイザを実装しながら仕組みを学ぶ

ハイパーバイザ、CPU 仮想化支援、メモリ仮想化、割り込み、仮想デバイスなど、VM の性能設計を低レイヤから理解したい場合の参考書籍です。価格や在庫はリンク先で確認してください。

Amazon で見る

このリンクは Amazon アソシエイトリンクです。

関連記事

Ubuntu 22.04 OVS-DPDK 構築失敗から見る DPDK dataplane の難しさ

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トップへ戻る