おそらく、Amazon のサーバーレス コンピューティングである AWS Lambda と Fargate をご存知でしょう。エンジン。 サーバーレス コンピューティングは、その性質上、厳重なセキュリティと優れたパフォーマンスを必要とするややトリッキーなタスクをもたらします。 まさにそのトピックのために、Amazon は Firecracker.
と呼ばれる microVM 解決策を考案しました。Micro って何?
MicroVM は、最小限の、軽量の仮想マシン。 それらは軽量 仮想マシン ショー (VMM) によって生成され、冗長で栄光のある側面が取り除かれます。 事実に基づいて作られた VM を大切にし、分離とセキュリティのためにハードウェア ステージの仮想化を提供します
このブログ投稿に関する MicroVM は、基本的に、コンテナのワークロードに合わせて作られた仮想化テクノロジーです。
Firecracker の補助
Firecracker は、 Linux カーネルベースのほとんどが仮想マシン (KVM) です。 コンテナ ワークロードのニーズを解決するために Amazon が作成した長い道のりです。 それは長い道のりです 開始ソース , で書かれました (信じられないほど素晴らしい)錆び、2018 年以降、製造業は時代遅れです。
つい最近まで、Lambda は非常に優れた Linux コンテナーの上にバインドされていました。分離された内部の個別のデジタル マシン。 各コンテナはさまざまな Lambda の目的を果たしましたが、すべての VM はさまざまなテナントを提供しました。 セキュリティの観点からは非常に効率的であっても、この配置はパフォーマンスの窮屈さを意味し、可変次元のワークロードを固定次元の VM にパックするのは難しいことが証明されています.
Amazon は、
を必要とするサーバーレス ワークロードの次の解決策として、待機を計画することにしました。 一貫した、ネイティブに近い
パフォーマンス
、同じノードでさまざまな機能が実行されているため、これももはや低く設定されていません
、快適でなければならない知識の漏えい、権限昇格、およびさまざまなセキュリティ上の危険性 パンチの効いた 互換性 であるため、機能は、再コンパイルやコード調整なしで、任意のライブラリとバイナリをバインドする役割を果たします
過剰で多用途
スケーラビリティ ity
1 台のマシンで何百もの機能をバインドできるようにする 関数はオーバーコミットソースへのプロットを伴うべきであり、最も注意が必要です-彼らが望む最小限の量のソースの行使をつかむ
スタートアップとバウンドダウン
は、機能の冷ややかな開始時間が分単位のままであることを伝えるために、非常に高速である必要があります
そのため、「わずか 125 ミリ秒」という印象的な起動時間と、「ホストごとに 2d あたり最大 150 個の microVM」の作成速度をサポートすることを達成する役割を効率的に果たすようになりました (出典:
https://firecracker-microvm.github.io/
).
は、機能の冷ややかな開始時間が分単位のままであることを伝えるために、非常に高速である必要があります
もっと深く…
Firecracker の各タスクは必ず 1 つの MicroVM に対して実行され、次のスレッドで構成されます: API サーバー、VMM、および vCPU(s) スレッド — すべてのゲスト CPU コアごとに 1 つ。
爆竹は現在役に立ちます x86_64 と カーネル モデル 4.14 以降を実行する aarch64
アーキテクチャ。 aarch64 の Toughen が機能の合計になることはめったにありませんが、アルファ段階の開始については信じられています。 この投稿のすべてのアーキテクチャに関する明示的な知識は、x86_64 実装。
APIサーバー APIサーバーはすべての Firecracker タスクの管理プレーン。
合法的な医師によると、それは長い道のりです、「デジタル マシンの短いコース内で決して」、 を通過してオフにしても無音にする必要があるno-api フラグ config-file は別として用意されています。
それは から始まった長い道のりです) ApiServerAdapter を真のスレッドで実行し、UNIX ソケット上で実行される REST API を公開します。 ゲスト カーネル、ブート引数、サルベージ構成、ブロック ガジェット構成、ゲスト マシン構成、および cpuid を構成するためのエンドポイントが存在します。 、ロギング、メトリクス、価格制限、およびメタデータ プロバイダー。 操作は、起動前および起動後に API サーバーに送信することもできます。
API サーバー スレッドと VMM の間の会話真の VM を実行および制御するスレッド (後述) は、Rust チャネルの実行を完了します
チャネルは API 要求について通知されますAPI サーバーに到着すると epoll
APIサーバーはすべての Firecracker タスクの管理プレーン。
合法的な医師によると、それは長い道のりです、「デジタル マシンの短いコース内で決して」、 を通過してオフにしても無音にする必要があるno-api フラグ config-file は別として用意されています。
それは から始まった長い道のりです) ApiServerAdapter を真のスレッドで実行し、UNIX ソケット上で実行される REST API を公開します。 ゲスト カーネル、ブート引数、サルベージ構成、ブロック ガジェット構成、ゲスト マシン構成、および cpuid を構成するためのエンドポイントが存在します。 、ロギング、メトリクス、価格制限、およびメタデータ プロバイダー。 操作は、起動前および起動後に API サーバーに送信することもできます。
API サーバー スレッドと VMM の間の会話真の VM を実行および制御するスレッド (後述) は、Rust チャネルの実行を完了します
チャネルは API 要求について通知されますAPI サーバーに到着すると epoll
イベントを処理するために FC がさまざまな場所で実行する試合ループ:
// API イベントを無効にする FD。 これが make によるブロック eventfd です // これは簡単なブロック ループである config/pre-boot ループ内で時代遅れになっています // 最も注目を集めているのは、API イベントを消費するものです。 させて
api_event_fd
=
// API イベントを無効にする FD。 これが make によるブロック eventfd です // これは簡単なブロック ループである config/pre-boot ループ内で時代遅れになっています
// 最も注目を集めているのは、API イベントを消費するものです。させて
api_event_fd
=
EventFd
:: 新鮮
(
0
) 。クイズ(「API Eventfd を取得できなくなりました。」);// Vmm スレッドと Api スレッドの間のすべての方向のチャネル させて (to_vmm,
from_api )
=チャネル(); させて (to_api, from_vmm)
=チャネル(); 糸:: ビルダー :: 新鮮() 。タイトル("fc_api" .to_owned()) .スポーン(クロス
||, to_vmm,
{マッチApiServer::mmds_info新鮮(from_vmm
, to_vmm_event_fd ).bind_and_run( bind_path ,
process_time_reporter,
&api_seccomp_filter, )) { // ... } })。クイズ(
"API スレッドの生成に失敗しました。");
ソース: 爆竹/sr c/firecracker/src/api_server_adapter.rs
API サーバーが生成されると、ApiServerAdapter
が実行され、build_microvm_from_requests()[cfg(target_arch
= "x86_64")] と通信します。 これは、連続する API 呼び出しの実行をループし、VM のプリブートを無効にします:
pub fn
build_microvm_from_requests ,G>
(seccomp_filters :&BpfThreadMap , イベントマネージャ
:&
mut)イベントマネージャ
, instance_info : InstanceInfo, recv_req :F: )G, boot_timer_enabled : ブール, ) -> 結果:: 結果 <, 返事
(VmResources , アーク<ミューテックス
<Vmm>>), 終了コード> 場所 F : Fn() -> VmmAction, G : Fn(
アクション結果// 構成、設定連続する API 呼び出しによって microVM を開始します。 // API 呼び出しを繰り返して microVm を構成します。 // ループが途切れるとmicroVM を効率的に起動し、稼働中の Vmm を構築します。 一方
preboot_controller
.built_vmm.is_none() {// クエリを別の場所に累積し、 task it, send wait on response. 返事( preboot_controller.handle_preboot_request(recv_req()); // 致命的なエラーが発生した場合は、ループを破棄します。 )もしも させて いくつかの(exit_code[cfg(target_arch = "x86_64")] )kernel_image=// ...preboot_controller。致命的な誤り { 戻る エラー(exit_code
); }
}}) HIMEM_START ~ 0x0010_0000
ソース: firecracker/src/vmm/src/rpc_interface.rs
VM を効率的に事前起動した後、ApiServerAdapter
は、ApiServerAdapter: を呼び出してバインドします。 :run_microvm().
FC の API サーバーの仕様は、 ここ
ブート シーケンスと Linux ブート プロトコル
でカーネルをストレート ブートします。 16 ビット からの起動を希望するエントリ ポイントモード.との弱い PC ブート シーケンスBIOS は次のステップで構成されます:
起動時に、CPU — 精密モードで実行 — に配置された命令を実行します。 ROM 領域にジャンプするハードウェア リセット ベクター。 そのファームウェア コードは、何百もの初期化プログラム (その場合は BIOS) をひっくり返します。 スタートアップ プログラムは、POST (バイタリティ オン セルフ テスト) 整合性を実行して、依存するすべてのハードウェア デバイスが効果的に機能していることを確認します
その後、起動可能なガジェット (CD 圧力、HDD、NIC) の購入を開始します — チャンスがない場合、起動に失敗します。 HDD の場合、ブータブル ガジェットはマスター ブート レジェンド (MBR) である可能性があり、その役割は、アクティブなパーティションを一瞥し、そのブート セクター コードを作成することです。 ブート セクタ コードは基本的に、カーネルを本体のメモリにロードし、管理を OS に移す役割を担う第 1 段階のブート ローダーです。
さまざまな種類のブートローダー システム プロット。 各種のブート ローダーは、さまざまなリソースの障害に直面するように設計されたさまざまなレベルのコレクションを有効にし、第 1 段階のブート ローダーの 512 バイトのサイズ制限を大切にします。 例として、Grub は 3 層のブート ローダーです。
とはいえ、Linux カーネルは基本的にはBIOS とブートローダー。 変更点として、Firecracker は 64 ビット Linux ブート プロトコルに関連する十分な処理を行います。これは、カーネル イメージをどのようにロードおよびバインドする必要があるかを指定します。 FC は greeable-mode
Linux ブートの正当な医師のためProtocol つぶやき、agreeable-mode のエントリは
0x100000、次のスキーマ内で見られるように:
ブート プロトコル モデル>=2.02 の新しい bzImage カーネルの場合、次のメモリ フォーマットはプロンプトです: ~ ~ | 受け入れモードのカーネル | 100000 +------------------------+ | I/O メモリ ギャップ | 0A0000 +------------------------+ | BIOS 用に予約 | 未使用でうなる可能性が高いほど強力なままにしておきます ~ ~ | 備考欄 | (X+10000 タグの下になります) X+10000 +------------------------+ | スタック/ヒープ | カーネルの正確なモード コードによる実行用。 X+08000 +------------------------+ | カーネルのセットアップ | カーネルの正確なモードのコード。 | | カーネル ブート セクター | カーネルのレガシー ブート セクタ。 X +------------------------+ | ブートローダー | ← ブート セクタ エントリ ポイント 0000:7C00 001000 +------------------------+ | MBR/BIOS 用に予約 | 000800 +------------------------+ | 全体的に MBR によって時代遅れになっている | 000600 +------------------------+ | BIOS は最も注目を集めています。 000000 +------------------------+ ... X を処理する場所は、ブート ローダーのメーカーが許す限り小さいものです。
したがって、爆竹
セット
であり、中断内では start_address
として渡されます。 load_kernel() を呼び出すとき) 。 load_kernel() in flip は、提供されたイメージに対してサニティ テストを実行し、そのセグメントを読み取り、中断内でゲスト メモリのエントリ ポイントを返します。
,
#
パブfn load_kernel
<F >( guest_mem:
&GuestMemoryMmap
:&mut
F, 開始アドレス:u64
,)
-> 結果<ゲストアドレス )> 場所 F:教わります
+Leer ),{kernel_image
。一目( SeekFrom :: 誕生( 0)) .map_err(|
_|エラー:: SeekKernelImage )?; させて
mut
ehdr
= 妖精
::エルフ64_Ehdr::
デフォルト();
ehdr ).as_bytes () .read_from(0, kernel_image
, mem:: のサイズ:: <妖精
:: Elf64_Ehdr >()) .map_err(|エラー:: ReadKernelDataStruct("ELFヘッダーの学習に失敗しました"))?; // 健全性テスト // ... kernel_image_|
。一目( SeekFrom:: 誕生(
ehdr.e_poff ))
)mem_offset =ゲストアドレス ( phdr .p_paddr.map_err(|_| エラー::SeekProgramHeader:: Elf64_Phdr
)?; させて phdr_sz=mem:: のサイズ ::
<
妖精>phdr.p_type &(); させて
mut
phdrs: Vec<
妖精:: Elf64_Phdr>
= vec! [];ために_ の 0u寸法.. ehdr(); phdr.as_bytes().e_phnum として
usize {mut phdrさせて妖精:: Elf64_Phdr
=::
デフォルト
.read_from(0, kernel_imag e, phdr_sz ) .map_err(|_ | エラー:: ReadKernelDataStruct(「ELFプログラムヘッダの学習に失敗しました」))?;phdrs。押す
(phdr); }// これが指摘するすべての問題について教えられるプロット ヘッダーために
phdr の &phdrs{ もしも
()妖精
::PT_LOAD==0 ||).p_filesz ==
phdr0続行{;カーネル イメージ 。一目(SeekFrom:: 誕生( ph dr.p_offset)) .map_err}(|_|:: SeekKernelStart
エラー)させて?;
); もしも
mem_offset.raw_value () <start_address戻る エラー (エラー:: InvalidProgramHeaderAddress{); } guest_mem .read_from (mem_offset, kernel_image, phdr
.p_filesz ) として usize) .map_err(|のインデックスを保留します。 バッファなので、例としてのバルーン ドライバの場合、それらは inflateq になります。 ,
_
| エラー:: ReadKernelImage)?; }
は、virtio 互換システムの実装に必要な要件を示しています。 フロントエンド ドライバーは Linux>=2.6.25 でそのまま出荷されますが、バックエンド ドライバー (以下「デバイス」と呼びます) は医師の指示に従って実装する必要があります。Ok( ゲストアドレス(ehdr .e_entry
)) }
ソース:
firecracker/src/kernel/src/loader/mod .rs
Firecracker は圧縮されていないカーネル イメージを直接使用します。 vmlinux 、従来のブート シーケンスを実行するための追加コストを節約できます。カーネルは起動時に解凍します。 上記の特別な FC ブート シーケンスのすべてにより、大幅なパフォーマンスの向上が可能になり、最終的に AWS Lambda の顧客が迅速なコールド スタートとして体験する結果が得られます。
デバイスモデル & VirtIO
Virtio は、Rusty Russell (iptables!) を彼のx86 Linux 準仮想化ハイパーバイザー lguest
での作業。 完全な仮想化 (ゲストが別のホストで実行されているという事実に依存しない) とは対照的に、準仮想化テクノロジでは、ゲストが独自にドライバーを実装し、そのホストと連携する必要があります。 これは、トラップやハードウェア エミュレーション ドライバーによって仲介されるのではなく、ゲストがホストと直接対話するため、最終的にパフォーマンスの向上に役立ちます。 明らかに、これを機能させるには、ゲスト OS を変更する必要があります。 Firecracker は、通常の VM よりも優れたパフォーマンスを意味する準仮想化 KVM を使用して実装されます。外国人が母国語で直接話す (準仮想化) vs 翻訳者の助けを借りて話す (完全仮想化)
Virtio の目的は、フロントエンド ドライバー (ゲスト上) とバックエンド デバイス ドライバー (ホスト上)、および両端間のトランスポート層
仕様
ガイドライン プレーンにアクセスするプロットのゲストとホスト間の相互作用は、 と呼ばれるリング バッファー構造体と一致します。 virtqueue には、ゲスト割り当てのバッファーが含まれています。 ホストは、これらのゲスト メモリ領域の読み取りと書き込みを行います。 各ガジェットには複数の virtqueue を含めることができますが、すべてのバッファーは、最も多くの注目を集めた学習または最も注目を集めた書き込みの両方である可能性がありますが、すべてではありません。 各ガジェットには、その仮定のガジェットによって書かれ、学習される真の情報に加えて、永続的な規律、機能のビット、構成の住居が含まれています。
通知2つの端の間は時代遅れであり、さまざまな終了を否定するために否定されています:
構成の置き換え(ガジェット -> ドライバ) 時代遅れのバッファガジェットで (ガジェット -> ドライバー) ゲスト (ドライバー -> ガジェット) によって使用可能なバッファー
より優れたパフォーマンスパラ仮想化は大量の仮想化を提供します 仮想化は Virtio の「利用可能なバッファ」通知メカニズムであり、コストのかかる VMExit を大量に節約します。 例として、十分な仮想化解像度で NIC エミュレーションを行うと、エミュレートされたガジェットに書き込まれるバイトごとに VMExit が存在します。 virtio を使用すると、最初に合計バッファーが書き込まれ、最も注目を集めるのは、使用可能なバッファーをホストに通知するプロットのために単一の VMExit がディスパッチされることです
vhost と呼ばれるより優れた virtio バックエンド実装があることを示します。これは、KVM 用のカーネル内 virtio デバイスを導入し、ゲスト カーネルからホスト カーネルへの情報プレーンを啓発し、冗長なホスト ユーザー空間をカーネル内の syscall に保存します。 . Firecracker は現在、この実装を実行していません。これらのドライバーとデバイスのレイアウトと実装は少し異なります:
PCIバスは基本的にほとんどがトランスポートベース
Memory Mapped IO 基本的にはほとんどがトランスポートに基づいています (FC が選択したトランスポート)
Channel I/O 基本的にはトランスポートベース
PCI ベースのほとんどのトランスポートと MMIO の違いの 1 つは、PCI とは異なり、MMIO は一般的なガジェットを提供しないことです。発見メカニズム。 これは、すべてのガジェットについて、ゲスト OS が解決してレジスタの位置を認識し、時代遅れの割り込みを行うことを意味します。
全体として、通知ゲストからホストへのさまざまなレジスタへの事実上の書き込みであり、ハイパーバイザーによってキャッチされたシグナルをオフにします (ioeventfd & VMExits)、ホストからゲストへの通知がプライマリであっても
irqfd 中断。 それぞれの「時代遅れのバッファ」通知と「使用可能なバッファ」通知は、全体的に非常にコストのかかる操作になる可能性があるため、抑制可能です。
爆竹の援助- 接続されたすべてのガジェット (サルベージ、ブロックなど) は、基本的に
MMIO
指定+a バスデバイス形質 resp
ガジェットを取り付けると、FCはそれを異常なマッチループにサブスクライブします。 各ガジェットは MutEventSubscriber ガジェットの queue_evts
に対してマッチ フェーシングを実装するトレイト (つまり、「使用可能なバッファ」通知)。 これらのキュー イベントは、接続された virtqueue
deflateq、および statsq キュー
FC は、ガジェットの queue_evts
内のすべてのファイル記述子を登録します。 (おそらくおそらくそのガジェットに対して明示的である可能性があります)
KVM 自体
0x050の世話をするときはいつでも (virtio::NOTIFY_REG_OFFSET)) は、ゲストの長さのために書かれています
KVM_IOEVENTFD ioctl. virtio::NOTIFY_REG_OFFSET
は Queue Notifier と呼ばれます。 正当な MMIO 仕様によると、「このレジスタに価格を書き込むと、キューにタスクへの新しいバッファがあることがガジェットに通知されます」。 おそらくおそらくもはや登録されていない可能性がある MMIO/PMIO ゲスト アドレスの一致では、KVM_IOEVENTFD
ioctl, write は異常な VMexit をオフにします.
KVM_IOEVENTFD
この ioctl は、ゲストの長さを処理する実際の pio/mmio に ioeventfd をアタッチまたはデタッチします。 登録された take care 内のゲスト書き込みは、提供された一致を別の終了トリガーとして通知します。 ハイパーリンク
全体として、MMIO の登録のドリフト-基本的にベースの主なガジェットは次のとおりです:
)FC は MMIO ガジェットに新しいスロットを割り当てます ゲストが参加する ioevents にサブスクライブします ネゲートでirqfdを登録し、プロットでゲストに割り込みを送信します ガジェットを MMIO スロットに挿入します そして、中断の中でカーネルを設定します bootparams をゲスト ドライバで構成:
パブ
fn register_mmio_virtio_for_boot
(
&mut
自己, vm:
&VmFd
、 デバイスID: 弦, mmio_device :
MmioTransport, _cmdline:&mut
kernel_cmdline:: コマンドライン , )
->
結果{ させて mmio_slot[cfg(target_arch = "x86_64")] =自己.allocate_new_slot
(1)?; 自己.register_mmio_virtio
(vm, デバイスID: アーク, mmio_device ),&mmio_slot)?; #[cfg(target_arch = “x86_64”)]
自分:: add_virtio_device_to_cmdline (
_&コマンドライン,
mmio_slot)?; 十分な(
mmio_slot
) }
ソース: firecracker/src /vmm/src/device_manager/mmio.rs
最小限の VMM であるため、FC はエミュレートされたドライバーのかなり窮屈な場所を提供します: ブロックストレージ (virtio-blk)、ネットワーク (virtio-salvage)、vsock (virtio-vsock)、バルーンドライバー (virtio-balloon)、シリアルコンソール、そして部分的な I8042 キーボード コントローラーは、VM を終了するために最も注目を集めていました。
上記のデバイスを起動するには、FC トラフィックもすべてのプログラマブル割り込みコントローラー (PIC) と I/O が開発したプログラマブル割り込みコントローラー (IOAPIC)、および KVM のプログラマブル インターバル タイマー (PIT) の外観
レガシー y シリアル コンソールや I8042 コントローラなどのデバイスは、Port Mapped IO と一致しています。 それぞれ起動しました vcpu は、virtio デバイス用の MMIO バスとレガシー デバイス用の PMIO バスで配置されています:
)パブ
)fn start_vcpus
vcpus:
ベク<
Vcpu
>, vcpu_seccomp_filter
<BpfProgram
>, )
->結果<()>
{ // ... 編集済み ために
mut vcpu の。ドレイン(vcpus.. ) { vcpu.set_mmio_bus= "x86_64")] vcpu .kvm_vcpu
(自己.mmio_device_manager.bus。クローン()); #[cfg(target_arch.set_pio_bus(自己。 pio_device_manager.io_bus
。クローン ()); // …編集済み } // ... 編集済み 十分な(()) }ソース: firecracker/src/vmm/src/lib.rs
MMIO の読み取りと書き込みは、おそらく対処できる VMExit から離れています。 、さまざまな問題の中で、run_emulation()という目的で VCPU を実行します (後で説明します)。 これらの VmExit は、ガジェットの管理プレーン (つまり、その構成住居) にアクセスするには時代遅れです:
/// KVM コンテキストで vCPU を実行し、kvm 終了プロットを処理します。 ///
/// エミュレーションが処理または中断されたかどうかを示すエラーまたは列挙型を返します。 パブ
fn
run_emulationpio_bus )= &自己.pio_bus(
&自己) -> 結果<VcpuEmulation>
{
マッチ 自分.emulate() { VcpuExit:: MmioRead (addr, 情報) => { もしも させて いくつかの
(mmio_bus)=
&自己.kvm_vcpu.mmio_bus { mmio_bus。学び(addr、 情報); 指標
.vcpu.exit_mmio_read.inc ();}十分な
(VcpuEmulation:: 処理済み )
}
VcpuExitaddr,::MmioWrite(addr
, 情報) => { もしも させて いくつかの
mmio_bus )= &自己.kvm_vcpu .mmio_bus { mmio_bus 。書く ((addr情報); METRICS .vcpu.exit_mmio_write.inc(); },十分な(VcpuEmulation::対応) } // ... 編集済みarch_specific_reason// バインドされた明示的なアーキテクチャ エミュレーション。=>
{自分結果
.kvm_vcpu.run_arch_emulation(arch_specific_reason) } // ...編集済み }
}ソース: firecracker/src/vmm/src/vstate/vcpu/mod.rs
PMIO の読み取りと書き込みは arch-explicit であり、個別に処理されます:
/// KVM コンテキストで vCPU を実行し、kvm 終了プロットを処理します///
// / かどうかを指定するエラーまたは列挙型を返しますエミュレーションが処理または中断されなくなりました。 パブ fn
run_arch_emulation
(&自己, 出口: VcpuExit) -> 山岳::
> {{ VcpuExit:: IoIn(マッチ 出口
情報) => { もしも させて いくつかの({ pio_bus。学び(u64 ::から
(addr ), 情報); METRICS
.vcpu.exit_io_inaddr, 情報
)=>{ もしも させて
いくつかの(pio_bus)= &自己.pio_bus { pio_bus。書く( u64:: から(addr), 情報); METRICS .vcpu.exit_io_out
.inc();
}十分な(VcpuEmulation
:: 処理済み) }// ...編集済み<自己> { させて タップ= 蛇口:: open_named}new_with_tap ( 身元:ソース: firecracker/src/vmm/src/vstate /vcpu/x86_64.rs
通信網
ゲストのネットワーク デバイスは タップ ホスト上のデバイス:
impl 得る {/// 指定された TAP インターフェースを使用して新しい virtio ネットワーク ガジェットを開発します。 pub
fn弦,
tap_if_name ): 弦, guest_mac :
可能性<& MacAddr>tx_rate_limiter: RateLimiter , allow_mmds_requests : bool, rx_rate_limiter: )RateLimiter,
,) -> 結果(&tap_if_name| 1 <<).map_err(エラー::TapOpen?; // 以下の virtio の側面に一致するようにオフロード フラグを関連付けます。)タップ.set_offload )( net_gen:: TUN_F_CSUM|net_gen:: TUN_F_UFO
|
net_gen:: TUN_F_TSO4 |net_gen:: TUN_F_TSO6, ) .map_err(
エラーTapSetOffload::)?
; )させてvnet_hdr_size = vnet_hdr_len() として
i32
; タップ.set_vnet_hdr_size(vnet_hdr_size) .map_err
(
エラー
:: TapSetVnetHdrSize)?; させて mut avail_features
= 1 << VIRTIO_NET_F_GUEST_CSUM | 1 <<VIRTIO_NET_F_CSUM| 1 <<
VIRTIO_NET_F_GUEST_TSO4 [cfg(target_arch
= “x86_64”)] | 1
<| 1 << VIRTIO_NET_F_HOST_TSO4 | 1<< VIRTIO_NET_F_HOST_UFOVIRTIO_F_VERSION_1
; // …編集済み } // …編集済み }ソース:
firecracker/src/devices/src/virtio /salvage/gadget.rs
Vsock[cfg(target_arch
= “x86_64”)]
Vsock は双方向のホスト/ゲスト会話モードとして起動されました n. 別のプロットは、そのようなホスト/ゲストの相互作用を提供するがかなり窮屈な virtio-console の実行である可能性があります。 まず第一に、1:1 シリアル ポートを介して N:1 接続を多重化することは困難であり、ユーティリティ ステージで処理する必要があります。 起動するには、API はソケット API で必要なパーソナリティ ガジェットと一致しており、セマンティクスはストリーム セマンティクスであり、データグラム プロトコルには効果的に適合しません。 その上、ホスト マシンにはハードコードされた適度に小さいポート制限 (512 前後) があります。
さまざまなVsock は非常に優れた UNIX エリア ソケット API (connect()、bind()、win()、learn()、write() など) を提供するため、すべてのデータグラムとストリームのセマンティクスに役立ちます。
AF_VSOCK という名前の本当の家族の世話があります。 そのプロットのために。 送信元アドレスと送信先アドレスは、32 ビットのコンテキスト ID (cid) と 32 ビットのポートのタプルで構成され、1 つのバイト否定
Firecracker は、構成された vsock ドライバーを使用して MicroVM を開始する必要がある場所で、ホストが開始する vsock 接続を支援します。 また、ホストが宛先ポートでリッスンし、VIRTIO_VSOCK_OP_RST その他の場合はゲストへのメッセージ
ストレージ
ストレージ用 Firecracker は、バックアップされた virtio-block デバイスを実装しますホスト上のレコードデータによって。 その間、ファイルシステムのパススルー解決 (virtio-fs) は実行されません (セキュリティ上の問題のためでしょうか?)。 FC には焦げ付きがないため、VM を実行する前に VM のすべてのブロック デバイスを無音で接続する必要があることを示します。 起動するには、そのようなデバイスを VM に効率的にマウントすることを否定して、ゲスト カーネルが支援するファイル システムで事前にフォーマットする必要があります。
すべての学習操作と書き込み操作は、単一の requestq
の実行で提供されます。 virtio キュー。 virtio 仕様でサポートされている正当な操作のうち:最も注目を集める爆竹は、IN、OUT、FLUSH に役立ちます:
パブ
enum
リクエストの種類 { の
,外
, 流す,
GetDeviceID, 非対応(u32 ), }
rootfsブロックガジェットはVM を起動する前に構成された、ch そう:
rootfs_path=$(pwd)
“/your-rootfs.ext4” カール –unix-socket /tmp/爆竹.ソケット -i -X PUT ‘http://localhost/drives/rootfs’
-H'Accept: utility/json' -H 'Verbalize material-Form: utility/json'
-d"{"ドライブID": "rootfs"、 "
path_on_host
": "${ rootfs_path}"、"
is_root_device𝚆𝚊𝚝𝚌𝚑 𝙽𝙾𝚆 📺": ファ実際、"
is_read_only": スプリアス }"
最小限の rootfs イメージを取得するためのマップの例は、Firecracker's で偶然見つけることさえできます。 合法的な医者.
Ballooning
Ballooning は、メモリのオーバーコミットの解決策を示します。 これにより、ホスト管理のオンクイズ割り当てとゲスト メモリの再利用が可能になります。
virtio-balloon ガジェットは、バルーン ゲスト ドライバーは、ホストによって指定されたプロットに到達するまでメモリを割り当て、それらの新しいメモリ アドレスが待機するのを経験します。 同じスタイルで、バルーン ドライバーは、ホスト ガジェットが要求する以上のメモリを持っている場合、ゲスト自体へのメモリ待機を解放します。 これは、ゲスト カーネルの長さに対する独立した「メモリ クライアント/アロケータ」であり、さまざまなプロセスでメモリを競合し、VM のプリブート RAM 障害の長さにわたって動作します。
ホストはバルーンメモリページを自由に選択できます。 それらをさまざまなトラフィックに見つけます。 これにより、ホストは、使用可能なソースと一致するすべてのトラフィックのメモリ ソースを操作および知的調整できるため、オーバーコミットが可能になります。
Virtio-balloon は 3 つの virtio キューを保持します: inflateq,
deflateq
、およびstatsq)。 Inflateq は、ホスト ガジェットに提供されたアドレスについてつぶやくためにゲスト ドライバーによって時代遅れになっています (したがって、「バルーン」が膨らんでいます)。 一方、deflateq は、ゲストによって時代遅れになっているメモリ アドレスの経験に対して時代遅れになっています (したがって、「バルーン」はしぼんでいます)。 . Statsq が必須になることはめったになくなり、ゲストがメモリ統計を送信するために時代遅れになったとしても無音にする必要があります.
Firecracker の実装