Linux 仮想化 KVM-Qemu Virtqueue の分析

Linux 仮想化 KVM-Qemu Virtqueue の分析

[[390061]]

この記事はWeChatの公開アカウント「LoyenWang」から転載したもので、著者はLoyenWangです。この記事を転載する場合は、LoyenWang公式アカウントまでご連絡ください。

背景

  • ソースコードを読んでみろよ! --魯迅著
  • 一枚の写真は千の言葉に値する。 --ゴーリキー著

例:

  1. KVM バージョン: 5.9.1
  2. QEMU バージョン: 5.0.0
  3. ツール: Source Insight 3.5、Visio
  4. この記事はブログガーデンで同期されています: https://www.cnblogs.com/LoyenWang/

1. 概要

ワンワンワン、最近忙しくて更新のリズムが乱れていました。取り急ぎお詫び申し上げます。

  • 前回のシリーズでは、Virtio デバイスと Virtio ドライバーについてすでに説明しました。この記事では、virtqueue を分析します。
  • Virtqueue は、フロントエンドとバックエンド間のデータ交換に使用されます。このデータ キューを見ると、まず思い浮かぶのはリング バッファです。実際の実装はどのようになりますか?

2. データ構造

まずコアデータ構造を見てみましょう。

  • 通常、Virtio デバイスが Virtqueue を操作する場合、外部インターフェースとして理解できる struct virtqueue 構造体を使用し、Virtqueue メカニズムの実装は struct vring_virtqueue 構造体に依存します。
  • Virtqueue には、struct vring によって編成された 3 つのコア データ構造があります。
  1. struct vring_desc: 記述子テーブル。各記述子はメモリの一部を指します。メモリタイプは、それぞれ出力と入力を表す out タイプと in タイプに分けられます。ドライバーはメモリ管理を担当します。この構造体の次のフィールドは、複数の記述子を含む記述子チェーンを形成するために使用でき、フラグ フィールドは、読み取り専用や書き込み専用などのプロパティを記述するために使用されます。
  2. struct vring_avail: 使用可能な記述子領域。デバイスで使用可能な記述子 ID を記録するために使用されます。その本体は配列リングであり、これは実際にはリング バッファーです。
  3. struct vring_used: 使用された記述子領域。デバイスが処理した記述子 ID を記録するために使用されます。同様に、そのリング配列もリング バッファです。 struct vring_avail とは異なり、デバイスによって書き戻されたデータの長さも記録します。

もちろん、これは少し直感的ではないので、ここに図を示します。

  • 簡単に言えば、ドライバーはメモリ (scatterlist) を割り当て、それを virtqueue_add を通じて記述子テーブルに追加し、記述子テーブル内のエントリが特定の物理アドレスに対応できるようにします。実際、それはリソースプールとして理解することができます。
  • ドライバーは、使用可能なリソースを struct vring_avail に更新できます。つまり、使用可能な記述子 ID をリング配列に追加します。リング バッファに精通している学生は、そのメカニズムを明確に理解しているはずです。これは、ヘッドとテールの 2 つのポインタを維持することによって管理されます。ドライバーはヘッド ポインター (idx) の更新を担当し、デバイスはテール ポインターの更新を担当します (Qemu のデバイスは last_avail_idx を維持する責任があります)。ヘッドポインターとテールポインターは常にお互いを追いかけています。
  • デバイスが終了すると、使用された記述子 ID が struct vring_used に更新されます。 vring_virtqueue 自体は last_used_idx を維持し、そのメカニズムは struct vring_avail と一致しています。

3. プロセス分析

3.1 送信

ドライバーがデバイスにデータを送信する必要がある場合、プロセスは上記のようになります。

①A はバッファを割り当てて Virtqueue に追加することを意味し、①B は Used キューからバッファを取得することを意味します。2 つの方法のいずれかを選択します。

②送信のためにデータをバッファにコピーすることを示します。

③Availキュー内の記述子インデックス値を更新することを示します。デバイスが正しい値を確認できるようにするために、ドライバーはメモリ バリア操作を実行する必要があることに注意してください。

④と⑤は、ドライバーがデバイスにデータを取得するよう通知することを示します。

⑥デバイスがAvailキューから記述子インデックス値を取得することを示します。

⑦は記述子インデックスに対応するアドレスのデータを取り出すことを意味する。

⑧デバイスが使用済みキュー内の記述子インデックスを更新したことを示します。

⑨および⑩は、デバイスがデータが取得されたことをドライバーに通知することを示します。

3.2 受信

ドライバーがデバイスからデータを受信すると、プロセスは上記のようになります。

① デバイスがAvailキューから利用可能な記述子インデックス値を取得することを示します。

②記述子インデックスに対応するアドレスにデータをコピーすることを示します。

③使用済みキュー内の記述子インデックス値を更新することを示します。

④と⑤は、デバイスがドライバーにデータを取得するよう通知することを示します。

⑥ドライバーが使用済みキューから使用済み記述子インデックス値を取得することを示します。

⑦は記述子インデックスに対応するアドレスのデータを取り出すことを意味する。

⑧Availキュー内の記述子インデックス値が更新されたことを示します。

⑨と⑩は、ドライバーがデバイスに新しい記述子が利用可能であることを通知することを示します。

3.3 コード分析

コード分​​析は、次の図 (Virtio-Net) を中心に行われます。面倒なので、一方向のデータ転送のみを分析します。

3.3.1 仮想キューの作成

  • 前回のシリーズの記事では、virtio デバイスとドライバーを分析しました。 Virtio-Net は PCI ネットワーク カード デバイス ドライバーであり、それぞれ virtnet-probe と virtio_pci_probe ですべての初期化を完了します。
  • virtnet_probe 関数のエントリでは、Virtqueue は init_vqs を通じて初期化されます。呼び出し関係は図に示されています。最後に、vring_create_virtqueue が呼び出され、Virtqueue が作成されます。
  • この作成プロセス中、Virtqueue の作成に必要な情報を取得するために PCI を介してデバイス構成スペースを読み取るなど、一部の詳細は無視されます。
  • 最後に、vring_virtqueue データ構造の初期化が実行されます。 vring データ構造のメモリ割り当てもドライバー内で完了し、構造全体はドライバーによって管理および保守されます。

3.3.2 virtio-netドライバは

  • ネットワーク データの送信は、start_xmit 関数を通じてドライバーに実装されます。
  • xmit_skb 関数では、sg_init_table が sg リストを初期化し、sg_set_buf が sg を特定のバッファーにポイントし、skb_to_sgvec がソケット バッファー内のデータで sg を埋めます。
  • virtqueue_add_outbuf を介して sg を Virtqueue に追加し、Avail キュー内の記述子のインデックス値を更新します。
  • virtqueue_notify は、デバイスがデータを取得できることを通知します。

3.3.3 Qemu virtio-netデバイス受信

  • ゲスト ドライバーがレジスタに書き込むと、KVM に転送され、Qemu が最終的にそれをキャプチャして処理します。エントリ関数は kvm_handle_io です。
  • Qemu は、IO メモリ領域の読み取りおよび書き込み操作関数を設定します。ゲストが IO 操作を実行すると、最終的に操作関数がトリガーされます。 Virtio-Net の場合は PCI デバイスなので、操作関数は virtio_pci_config_write になります。
  • virtio_pci_config_write 関数では、ゲストの書き込み操作を判断して処理します。たとえば、VIRTIO_PCI_QUEUE_NOTIFY が発生すると、ゲスト ドライバーの通知を処理するために virtio_queue_notify が呼び出され、最後に handle_output 関数がコールバックされます。
  • Virtio-Net デバイスの場合、送信されるコールバック関数は virtio_net_handle_tx_bh であり、操作は virtio_net_flush_tx で完了します。
  • 一般的な操作モデル: virtqueue_pop を介して Avail キューからアドレスを取得し、データを処理し、virtqueue_push を介して処理された記述子インデックスを使用済みキューに更新し、virtio_notify を介してゲスト ドライバーに通知します。
  • Virtqueue のデザインコンセプトは非常に巧妙です。これは virtio だけでなく、AMP システム内のプロセッサ間の通信にも使用されます。

とりあえずこれで終わりです。また次回お会いしましょう。

参照する

https://www.redhat.com/en/blog/virtqueues-and-virtio-ring-how-data-travels

仮想 I/O デバイス バージョン 1.1

<<:  4 Windows 仮想デスクトップ管理の制限

>>:  「MQ シリーズをマスターする」 - カフカの謎を解き明かす

推薦する

今週の Github の人気プロジェクトの概要: 自然言語処理 Python ライブラリ spaCy が最もホットです!

先週、Github で最も人気のあるプロジェクトは、最近バージョン 2.0 に更新された自然言語処理...

車のロゴの意味についてどれくらい知っていますか?オンラインテストを受けて、自分だけのロゴを作りましょう

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています車のロゴは...

K8S で Kafka を実行するのは適切でしょうか?どのような落とし穴に遭遇するでしょうか?

Kubernetes は、ステートレス ワークロードを実行するためにゼロから設計されました。これらの...

観察によれば、8月22日の百度のアルゴリズムアップグレードは非常に軽微なものだった。

8月22日、Baiduのアルゴリズムがアップグレードされ、不正サイトの掲載や低品質サイトのランキング...

2018年中国モバイルゲーム産業調査レポート

近年の中国のモバイルゲーム産業の急速な成長は、国内のゲーム産業全体の急速な発展を促進してきました。 ...

SEO 担当者の叫び:「反撃しなければ負けてしまう」

序文:今日フォーラムにログインするとすぐに、Lu Songsong の「北京の SEO 従事者、基本...

専門家や達人に誤解されることは、誰も簡単に成功できないことを示している

数日前、G市の家庭教師をしている友人がQQを通じて私に連絡してきました。彼のウェブサイトはブロックさ...

Baidu の変化する機能に関する最新の観察: 新しいサイトが人気を集めている

最近、百度の最大の変化は、ますます多くのサイトをK-ingし、より多くのサイトを降格させていることだ...

戦場では相手を理解しなければならない

著者は歴史書、特に皇帝に関する本を読むのが好きです。私の意見では、古代の皇帝の思想は常に非常に深いた...

#blackfriday# hostus - 年間 50 ドル / 6G メモリ / 200g ハードドライブ / 7T トラフィック / 7 つのデータセンター

Hostus のブラック フライデー プロモーションが始まりました。6G メモリを搭載した超ハイエン...

WordPressでホストされているブログの数は7000万に達した

北京時間4月26日、ウォール・ストリート・ジャーナル傘下のブログサイトAllThingsDによると、...

ステーショングループ操作は不正行為ですか?

【はじめに】Pi Zirui の SEO に関する詳細な分析を読んで、いくつか考えました。SEO の...