ネットワーク
ネットワークスタック(Ethernet・ARP・IPv4・ICMP・UDP・TCP(クライアントとサーバ)・DHCP・DNS)はアーキ非依存で、ゼロから作ったものです。同じソースが、5 つのターゲットすべてで動きます。
1 つのスタック、複数の NIC
| ターゲット | NIC |
|---|---|
| x86_64 | e1000 |
| riscv64 / aarch64 | virtio-net |
| RV32(Pico 2 W) | CYW43439 Wi-Fi |
| ARMv6-M(Pico W) | CYW43439 Wi-Fi |
スタックは、カードを名指ししません。使うのは、HAL が渡すものだけ——フレームを送る、取りに行く、リングへ返す。それに、ドライバが公開する MAC アドレスと受信待ちスロット。これらを実装した backend なら、どれでも差し込めます。同じスタックが、有線 Ethernet でも無線でも動きます。
Wi-Fi ドライバと、その依存
CYW43439 のドライバは Zig で、ベンダ SDK はコンパイルに入りません。gSPI のバスプログラムと、バスおよび join のコマンド列は、pico-sdk と cyw43-driver のソースを基にしています。
そして無線チップ自体はベンダのファームウェアで動きます。ファームウェア(約 224 KB)・NVRAM・CLM という 3 つのバイナリブロブを flash に書き込み、起動時にチップへストリームします。これは部品の性質であり、どの CYW43 ドライバも同じ 3 つを積みます。
カーネルが NIC を所有し、スクリプトが指揮する
層の分け方は、ほかのすべてと同じ二層です。カーネルがネットワークカードを所有し、スクリプトは FFI を通して指揮します。
riscv64 では、この境界に双方向のバッファ ABIが通ります。U-mode のアクターがポインタと長さを渡し、カーネルがページテーブルを歩いてそのポインタの全ページがユーザマップされていることを確認してから、読みまたは書きます。だからスクリプトは、境界を越えて整数だけでなく任意のバイト列(カスタムメッセージ、HTTP 応答)を送受信します。
aarch64 は同じ機構をファイル I/O にのみ使っています。TCP の FFI はありません。
**x86 と MCU の FFI 境界は、現状すべて整数です。**バッファ ABI はまだ配線していません。
割り込み駆動の受信(x86 のみ)
x86 では、受信をポーリングの刻みでなく割り込みで処理します。e1000 のレガシ INTx を割り込みコントローラ経由でベクタにルートし、割り込みサービスルーチンが線を de-assert し、割り込み終了を送り、ネットワークタスクを起こします。フレームは届いたときに処理されます。
**他のターゲットではポーリングです。**virtio-net のドライバには割り込みフックがありますが、割り込みコントローラからそこへ配線されていません。CYW43439 に至っては、受信割り込みが CPU に配線されていません(チップの制約)。フレームは、ドライバが要求したときにバスから出てきます。
TCP
クライアント(能動オープン)とサーバ(受動オープン。OS が小さな HTTP ページを配信する)。3-way ハンドシェイク、データ転送、FIN クローズ。シーケンス番号と確認応答番号は安全に wrap します。
| 同時接続 | 3 本。各接続が端点・シーケンス状態・再送キュー・送信キュー・ウィンドウを自分で持つ |
| 接続の対応づけ | 4-tuple 全体(RFC 793)。着信 SYN は空きスロットに入る |
| 再送 | 未確認セグメントを保持して再送。RTO 400 ms、3 s を上限に倍々、以降は諦める |
| 高速再送 | 重複 ACK 3 回で、失われたセグメントを即座に送り直し、ウィンドウを半分にする |
| 輻輳制御 | 接続毎の cwnd と ssthresh。スロースタート中は RTT あたり 1 セグメント、抜けたらウィンドウあたり 1 セグメント。タイムアウトで閾値を半分にしてスロースタートへ戻る |
| フロー制御 | データはキューに積み、MSS に分割し、min(輻輳ウィンドウ, 相手の広告ウィンドウ) で送出を律速する |
| SACK | 双方向でネゴシエート。順序外の到着を捨てずに保持し、ACK で何が届いたかを名指しし、相手からの SACK で既に届いている分の再送を止める |
| ウィンドウスケーリング | 提示する(相手は 64 KiB を超える広告ができる)。こちら側のシフトは意図的に 0——大きな受信バッファを持たないため |
| アイドルタイムアウト | 相手から 20 秒 |
チェックサム
| 送信 | 受信 | |
|---|---|---|
| TCP | 擬似ヘッダ込みで計算 | 検証し、合わないセグメントは破棄 |
| UDP | 擬似ヘッダ込みで計算 | 送信側が付けていれば検証(0 は省略の意味。IPv4 はそれを許す) |
| IPv4 ヘッダ・ICMP | 計算 | 検証 |
IPv4 のバージョン・ヘッダ長・全長・宛先 IP と、UDP の長さ境界も検証します。リリースビルドに境界チェックは無いため、検証を素通りした不正パケットは範囲外を読みます。不正なトラフィックは入口で捨てられます。
ワイヤ越しの分散
このスタックの上に、アクター層の位置透過が乗ります。リモートのアクターメッセージは、UDP ペイロードとして運ばれ、ローカルのメールボックスに届きます。
**実機で。**Pico 2 W(RP2350、MMU 無し)では、非特権・PMP 隔離のアクターの隣でこのスタックが特権タスクとして走ります。Wi-Fi に join し、DHCP で実 IP を取り、DNS を解決し、そのアクターのメッセージを実 LAN 越しに x86 ノードへ運びます。すべて 1 つのイメージです。
このスタックは、外へ送るだけでなく、**宛先にもなります。**自分のアドレスへの ARP に応え、オフリンクのトラフィックはゲートウェイへ送ります。だから、相手の側から会話を始められるし、別サブネットの相手にも届きます。
**オンリンクかオフリンクかは、ネットマスクとのビット比較で判定します。**マスクは既定で /24、サーバが渡せば DHCP のリースのマスクに置き換わるので、/24 でないサブネットも正しく経路制御されます。
詳細は アクター のページにあります。