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

推薦する

JD Cloudが新ブランドを立ち上げ:中国のクラウドコンピューティング市場に新たな大物が参入

4月20日、「クラウドは新たな台頭、未来は無限の可能性」をテーマにしたJD Cloudブランド発表会...

医療ウェブサイト最適化の現状:外部広告がウェブサイトのトラフィックをサポート

医療ウェブサイトの最適化に関しては、競争が熾烈です。動画広告にしろ、ウェブサイトの最適化にしろ、競争...

企業連携のミレニアム・ファルコンが誕生します。何が際立っているのでしょうか?

[51CTO.comより引用] こちらは特設記者会見会場。ここはTeambitionが生産される場所...

医療ウェブサイトのプロモーションにおけるセカンダリドメイン名の役割と使用法の分析

まず、セカンドレベルドメイン名をプロモーションに利用するのは、医療業界に限った方法ではありません。A...

プログラミング言語PHPがモバイル版に登場すると報道

北京時間10月4日、アメリカのテクノロジーブログ「VentureBeat」の寄稿者であるジョン・コー...

私のブログ改訂版に含まれる SEO 要素についての簡単な説明

最近、ウェブページのデザインを学んでいて、たくさんのスタイルを学んだことに気づきました。その後、私の...

Yixinは11月8日に無料トラフィックプランを開始:すべてのユーザーをカバー

新浪科技報、11月1日朝のニュース:YiXinは本日、無料データプランを発表しました。11月8日から...

私を騙したサービスプロバイダー - 私のウェブサイトがブロックされた理由がようやく分かりました

ちょうど今日、Mecheng が Baidu Spider をブロックするという誤った操作によって、...

#乾物おすすめ# BandwagonHost: 11.11の特別プロモーション商品、在庫限り

BandwagonHostは、熱狂的なオンラインショッピングフェスティバルでもある中国の独身の日(1...

friendhosting: 2018年春に45%割引、8つのデータセンター、無制限のトラフィックVPS、カスタムISO

ブルガリアのホスティング プロバイダー friendhosting (2009 年 4 月~) は、...

コロケーションの 5 つのメリット: ハイブリッド クラウド戦略にコロケーションを取り入れるべき理由

競争力を維持するために、企業はオンデマンドのテクノロジー サービスにますます依存するようになっていま...

corgitech-7ドル/vMware/750mメモリ/30gハードディスク/1Tトラフィック/8データセンター

corgitech は老舗の VPS プロバイダー (旧バージョンは 2 匹のかわいい子犬でした) ...

ユーザーエクスペリエンスを向上させる最適化: ウェブサイトのナビゲーション

先ほど、ユーザー エクスペリエンスの基本的な要素であるアクセス速度について説明しました。今日は、ユー...

Baidu がウェブマスター向けに外部リンクを拒否するツールのベータ版をリリースしたことの賛否両論について簡単に議論する

3月1日、Baiduは外部リンクを拒否する最新のバージョンを発表し、インターネット上のウェブサイトや...

HP、OpenStackオープンソースクラウドアーキテクチャのサポートを発表

海外メディアの報道によると、HPは今週、OpenStackオープンソースクラウドインフラストラクチャ...