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

推薦する

遠方からのお客様、ぜひご宿泊ください。ウェブサイトのユーザー増加システムは真剣に受け止めなければなりません。

今回はMADCINカンファレンスに出席するために再び厦門に戻り、有名な旅行ウェブサイトを通じてホテル...

3月にGoogleが行った検索アルゴリズムの改善をいくつか挙げる

Baidu が盲目的に Google を模倣しているとき、Google 検索が常に改善されていること...

ウェブサイト構築の最高の領域は、文化を創造することです

ウェブサイト構築の最高レベルは、実は文化を創造することです。文化とは何でしょうか? 文化は実際には人...

KubernetesとDockerをバックアップする方法

コンテナ内のすべてをバックアップする必要はありませんが、災害発生時にコンテナを実行および管理する構成...

最適化は道の終わりではありません。リンク構築は困難な状況において新しいアイデアを持つべきです。

ウェブサイトの最適化はますます難しくなってきている、という共通の認識をほとんどの人が持っています。こ...

あなたは本当にユーザーを理解していますか? 彼らを変えることができないなら、私たちは製品を変えるしかありません。

少し前に、インターネットで「ダウングレード理論」という非常に人気のある記事を見ました。その大まかな考...

ハッカーは、Apple iPhone 5Sが米国政府の指紋収集に役立っていると主張

有名なハッカー集団「アノニマス」は最近、Apple が米国国家安全保障局 (NSA) と協力して、最...

ホストに「ログインに失敗しました」と表示されたり、ページのクリックが応答しない場合の解決策

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

ソフト記事マーケティングにおけるニュースマーケティング

ニュースとは、人々が知らない、知りたくない、あるいは知るべき最新の事実を報道することです。人間は知識...

20gddos 保護: spartanhost-1.5/256 メモリ/20g ハードディスク/1T トラフィック/G ポート/シアトル

spartanhost.NET は、VPS 事業の年末プロモーションを実施しています。すべての VP...

トピックページの最適化プロセス

テーマ別ページの利点は、ロングテールキーワードでランク付けされやすいことであり、基本的にすべての業界...

BuyVMはどうですか?マイアミの10Gbps帯域幅VPSの簡単なレビュー、いくつかのデータを共有

buyvmはどうですか? buyvm は良い考えでしょうか? buyvm は最近、4 つの主要なコン...

マイクロコミュニティがフォーラムサイト所有者に適さない6つの理由

最近、マイクロコミュニティはインターネット上で輝く星となっています。さまざまなテクノロジーメディアが...

AWS スポットインスタンスを使用してクラウドコンピューティングのコストを 90% 削減する方法

企業の IT チームの中には、スポットインスタンスを利用するのではなく、容量を予約することを選択する...

分散キャップ定理と基底理論の簡単な分析!

[[346602]]導入理論計算機科学において、CAP 定理 (ブリューワーの定理とも呼ばれる) ...