読者です 読者をやめる 読者になる 読者になる

仮想マシンのスタックとネットワークI/Oについて

仮想化コンセプト

  • 仮想マシンモニタ=VMM(Virtual Machine Monitor)は、自身の子プロセスとして仮想マシンを実行し、ユーザモードでは実行できない命令を仮想マシンが発行したときは、CPUで例外が発生するため、それをVMMが補足(trap)*1して、仮想マシンが実行すべき命令をVMMが実行すれば良い(trap-and-emulate)。
  • そのためには、VMMは特権モードで実行し、仮想マシンを特権モードより低いモード(かつ、ユーザモードより高いモード)で実行すれば良い。

x86における仮想化

  • リングのコンセプトには0〜3の4段階があり、リング0はハードウェアにアクセスする特権命令を実行する。つまり、カーネルモードはリング0で実行し、ユーザモードはリング3で実行する。なお、1,2は使用しない。
  • x86では、「非特権命令であるためリング0以外で実行してもトラップは発生しないが、リングの状態やハードウェアリソースの状態に依存する命令」=センシティブ命令、が存在するため、仮想化コンセプト通りにVMMを実装してもうまくいかない。

http://image.gihyo.co.jp/assets/images/dev/serial/01/vm_work/0004/004.jpg

  • そこで、バイナリトランスレーションという技術により、VMMが仮想マシンの実行するプログラムを解析して、センシティブ命令を別の命令に置き換えるという手法が確立されたが、実装の難易度が高く、VMMの選択肢が限られていた。

Intel VT-x/AMD-Vの登場

  • Intel VT-xはハードウェア(CPU)による仮想化の実現支援機構で、リング0の状態にVM root modeとVM non-root modeの区別を提供する。
  • かつ、全てのセンシティブな命令をトラップできるようになるので、バイナリトランスレーション等のテクニックも不要になった。
  • ホスト側のオペレーティング・システムがリング0を占有するために、ゲスト側のオペレーティング・システムをリング0以外の1か2で動かす必要があったが、このIntel VTのサポートにより、ゲスト側のオペレーティング・システムをリング0で動かしつつ、VMMはそれよりも上位からの制御が可能になった。

  • Intel VT-x

http://image.gihyo.co.jp/assets/images/dev/serial/01/vm_work/0005/002.jpg

http://image.gihyo.co.jp/assets/images/dev/serial/01/vm_work/0005/003.jpg

  • 性能については、バイナリトランスレーションを採用しているVMwareの方が、CPUの仮想化支援機構を利用したKVMよりも、当初は速かった。VMEntryやVMExitによるモードの移行処理のオーバーヘッドが大きかったためである。CPUの技術向上によりこれらの処理に必要なクロック数が下がり、この差は解消されていった。

VMCS(Intel)/VMCB(AMD)

  • 仮想マシンが扱う各種レジスタなどの情報を保存しておくための物理メモリ上の領域。CPUによって、VMEntryの際にはVMCSから情報を復帰し、VMExitの際にはVMCSへ情報を退避する。VMCSに保存されない情報については、VMMによって復帰・退避が行われる。

http://image.slidesharecdn.com/2nd-intelvt-091006192819-phpapp01/95/bitvisor-intelvt-53-728.jpg?cb=1254857383

EPT (Extended Page Table)

  • ゲストOSは各プロセス毎にページテーブルを持つが、VMMはゲストの物理アドレスをホストの物理アドレスに変換する必要があるので、VMMはその変換表をSPT (Shadow Page Table)として管理しその変換をソフトウェア的に実行する。
  • このソフトウェア的な変換をなくすために、仮想マシンごとのゲストの物理アドレスからホストの物理アドレスへの変換を、MMUと同様にCPUによって実行する。これがEPT。
  • VMMによるSPTを用いたソフトウェア的な変換をなくすと共に、ゲストOSのページテーブル変更=SPTの更新時のVMExit/VMEntryのオーバーヘッドをなくすこともできる。

VPID (Virtual Processor Identifier)

  • TLB(Translation Lookahead Buffer)は、直前に利用したプロセスのページテーブルをCPUキャッシュに載せて再利用することで、メモリアクセスを減らして高速化する。
  • 仮想マシンのTLBと、VMMのTLBは異なるため、VMEntry-VMExitの際に(つまり仮想マシンのプロセスがシステムコールを呼んで特権命令を実行する度に)、TLBがフラッシュされてしまい、TLBの本来の意義が果たせなくなってしまう。
  • そこで、TLBをそれぞれの仮想マシンとVMMで使い分けてCPUキャッシュに保持するために、VPIDを導入しそれぞれのTLBを識別して管理できるようにした。

完全仮想化

  • ゲストOSを変更しない完全仮想化であらゆるOSをゲストとして実現する。KVMではQemuによるエミュレーションを利用するが、CPUのエミュレーションは非常に遅いので、Intel-VT/AMD-Vの仮想化支援機構が無いと実用性が無い。
  • KVMではHypervisorはLinuxホスト上でqemu-kvmと呼ばれる一つのプロセスとして動作し、kvm.koというカーネルモジュールを介して特権命令を実行する。

準仮想化

  • ゲストOSを変更する準仮想化で仮想化を実現するが、オープンソースのOSしかゲストとして採用できない。仮想マシンをリング1で実行することで、CPUの仮想化支援機構を必要としない方式。
  • Xen/VMware ESXではHypervisorは物理ハードウェア上で直接動作する。

Nested VMM

  • CPUの仮想化支援機構を、ゲスト上のVMMにも提供する機能。KVM on KVM などが可能になる。仮想マシン/proc/cpuinfovmxsmxといった単語が見える場合は、Nested VMMが有効。

I/Oの仮想化

Intel VT-d

SR-IOV

  • PCI Expressバイスが提供する機能で、VT-dによるダイレクトDMAを行いながらも、仮想マシン間でデバイスの共有が可能になった。
  • NICの場合、仮想スイッチによるCPUを用いたホスト-ゲスト間のトラヒック転送を行う必要がなくなり、物理NICのネイティブな処理能力を発揮することができる。

仮想デバイスによるNICエミュレーション

VMMが、エミュレートした仮想デバイスを仮想マシンに対して提供し、仮想マシンにはその仮想デバイスに対するデバイスドライバがインストールされる。それぞれ、バックエンド、フロントエンド、と呼ばれる。

仮想化環境におけるパケットフォワーディング

  • e1000

https://image.slidesharecdn.com/e4-bb-ae-e6-83-b3-e5-8c-96-e7-92-b0-e5-a2-83-e3-81-ab-e3-81-8a-e3-81-91-e3-82-8b-20-e3-83-91-e3-82-b1-e3-83-83-e3-83-88-e3-83-95-e3-82-a9-e3-83-af-e3-83-bc-e3-83-87-e3-82-a3-e3-83-b3-e3-82-b0-130603141515-phpapp01/95/-12-638.jpg?cb=1370268967

  • virtio

https://image.slidesharecdn.com/e4-bb-ae-e6-83-b3-e5-8c-96-e7-92-b0-e5-a2-83-e3-81-ab-e3-81-8a-e3-81-91-e3-82-8b-20-e3-83-91-e3-82-b1-e3-83-83-e3-83-88-e3-83-95-e3-82-a9-e3-83-af-e3-83-bc-e3-83-87-e3-82-a3-e3-83-b3-e3-82-b0-130603141515-phpapp01/95/-26-638.jpg?cb=1370268967

  • vhost-net

https://image.slidesharecdn.com/e4-bb-ae-e6-83-b3-e5-8c-96-e7-92-b0-e5-a2-83-e3-81-ab-e3-81-8a-e3-81-91-e3-82-8b-20-e3-83-91-e3-82-b1-e3-83-83-e3-83-88-e3-83-95-e3-82-a9-e3-83-af-e3-83-bc-e3-83-87-e3-82-a3-e3-83-b3-e3-82-b0-130603141515-phpapp01/95/-27-638.jpg?cb=1370268967

Thanks to

www.slideshare.net

ネットワークI/O

  • パケット受信処理

http://i0.wp.com/opensourceforu.com/wp-content/uploads/2016/08/Figure-1-Data-receiving-process.jpg

  • NAPI - ハードウェア割り込みが多くて性能が上がらない状況を改善するため、ハードウェア割り込みが発生した際にいったん割り込みを禁止して、カーネルが物理デバイスのメモリをポーリングする、という仕組みを提供するLinux Kernel API。ポーリングはプロセススケジューリングによって実行されるため、割り込み禁止からポーリングの間にNICに到着したパケットをまとめてソフトウェア処理できるため効率が良い。

http://www.coderplay.org/images/2015-12-05-1/nic-device-driver-process.png

  • 受信パケットを別のCPUで処理すると、プロセススケジューリングに依存してパケット処理の順序が変わってしまうことでreorderingが発生する頻度が多くなることを避けるため、受信パケットのソフトウェア上の処理は特定のCPUに集中してしまう。

  • RSS - 複数の受信パケットキューに5 tuplesをベースにパケットを振り分けて、それぞれのキューを別のCPUに割り当てて処理する制御を、ソフトウェアとして実現したもの。5 tuplesで振り分けることでreorderingの問題が起こるのを防ぐ。

  • RFS - RSSの仕組みをNIC上にハードウェアとして実現したもの。

  • netmap

    • ユーザアプリケーションが直接参照可能なメモリ領域とNICバイスをmmapによりマッピング
    • 上記のメモリ領域は再利用するためにリングメモリとして事前に確保
    • systemcallあたりの処理パケット数を増やすことによりコストを下げる(amortize)
    • 共有メモリ領域にメモリを確保することによりプロセス間(インターフェース間)のフォワーディングはzero-copyを実現

blog.yuuk.io

www.slideshare.net

http://www.coderplay.org/networkingdev/Linux-Kernel-Networking-Packet-Receiving.htmlwww.coderplay.org

Linuxデバイスドライバ 第3版

Linuxデバイスドライバ 第3版

Intel DPDK

  • パケット処理におけるLinuxカーネルの処理がオーバーヘッドとなりつつあり、さらにSR-IOVなどNICと(ユーザスペースで動作する)仮想マシンを直接繋げる技術も登場している。
  • Intel DPDKは、Linuxカーネルバイパスし、ユーザスペースでデバイスドライバを動かして、直接パケットをアプリケーションに届けるようなプログラムを実装するためのSDKを提供する。
  • PMD(Poll Mode Driver)と呼ばれる特別なデバイスドライバを特定のCPUで動かしてNICを監視し、パケットをユーザスペースのアプリケーションに届ける。また、UIO/VFIOといったユーザスペースでデバイスドライバを動かすためのカーネルモジュールを使用する。
  • マルチコアを活用しており、フロー単位でCPUを割り当てるrun-to-completionモードと、処理単位でCPUを割り当てるpipelineモードが選択できる。

http://www.bosco-tech.com/file/160311_icm2015-muramatsu.pdf

f:id:nishidy:20161112001534p:plain:w500

blog.slankdev.net

*1:例外発生時に呼ばれるコールバック関数をオーバーライトしてる?