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 シリーズをマスターする」 - カフカの謎を解き明かす

推薦する

キーワード選択戦略:人気のキーワードと人気のないキーワードと専門的なキーワードの関係

重要なヒント: ウェブサイトに適したキーワードを選択することは、検索エンジンからサイトが得るトラフィ...

大手メーカーの分散ID設計ソリューションをいくつかご紹介します

[[403803]]この記事はWeChatの公開アカウント「Learning Java from B...

Sina Weibo の曖昧なマーケティングイベントからレバレッジマーケティングを覗いてみよう

いわゆる状況を利用したマーケティングとは、マーケティング活動において販売の目的を隠し、消費者が好む環...

百度の誤解を招くサイトと実際のインデックスボリュームについて話しましょう

昨年から、Baiduは独自のBaidu Statisticsを宣伝し始めました。当時、ほとんどのウェ...

成功するSEO担当者が持つべきスキル

今や SEO は特別な秘密でも、神秘的なものでもありません。SEO チュートリアルはどこにでもありま...

Alibaba Cloud の全面的な値下げ、これは何を意味するのか?

今朝(2月29日)、Alibaba Cloudは、すべてのクラウド製品の公式サイト価格を引き下げると...

インターネットにおけるロングテールキーワードの本当の意味:大きな木の下で雨宿りするのは気持ちがいい

ウェブサイトの最適化に関するヒントといえば、多くのウェブマスターが「ロングテール キーワード」という...

ドットコムバブル時代のスパムを避ける方法

検索エンジンの誕生以来、ネットユーザーに多くのメリットをもたらしてきました。しかし、ネットユーザーの...

一般企業向けウェブサイト向けの優れたオリジナル記事の書き方

今では、最適化を行う際に「コンテンツは王であり、外部リンクは皇帝である」ということは誰もが知っていま...

2022年にマルチクラウド市場はどのように発展するでしょうか?

マルチクラウドとは、企業が 2 つ以上のクラウド コンピューティング プロバイダーが提供するクラウド...

ウェブサイトのサーバー障害が検索エンジンに与える影響と対策を分析する

[背景: 10 月 14 日に、新しい Web サイトの 1 つにサーバー問題が発生し、Web サイ...

ウェブデザインに手​​描きスタイルを取り入れてユーザーエクスペリエンスを向上

[コアヒント] 手描き風のスタイルをウェブページに適用してウェブサイトのユーザーエクスペリエンスを向...

マインドマッピングを使用して体系的にロングテールキーワードを掘り出す

以前、「EコマースWebサイト向けロングテールキーワードマイニングの経験の共有」という記事を共有しま...