🗂

ネットワーク通信がアプリケーションによって利用されるまで

2024/03/01に公開

疑問

ネットワーク通信は、電気信号や光の強弱によってビット列を表現しているはずです。しかし、その通信内容を利用するプロセスは自身に割り当てられたメモリ上の値を読んでいるはずです。
電気信号や光の強弱といった刹那的な情報が、メモリという(マシンの電源がついている間は)永続的な情報に変換されるまでの工程がわからなかったので、調べてみました。

結論

NIC (Network Interface Card) の DMA (Direct Memory Access) という機能によって、特定のメモリ領域に通信内容が直接書き込まれる。その後、OS 上のプロトコルスタックが各種処理を行う。

工程

NIC

LAN とコンピュータの繋ぎ目となっているのは NIC というハードウェアです。NIC は自身宛てのパケットを OS の指定したメモリ領域に直接書き込みます。以下では、Intel E1000 という NIC のデータシートをもとに説明します。

NIC がケーブルからパケットが流れてきたのを感知すると、NIC はまず自分宛てでないパケットを自動的にフィルタリングし、NIC 中のバッファキューに格納します(データシート3.2節冒頭)。続いて、バッファに格納されたパケットをホストマシンの特定のメモリ領域にあるリングバッファに DMA を使って転送します。このメモリ領域は Receive Buffer あるいは Receive Descriptor Ring と呼ばれています。

Receive Descriptor Ring

NIC に Receive Buffer のアドレスを教えるために、NIC の初期化時に OS のデバイスドライバは Receive Buffer のアドレスを NIC のレジスタに書き込みます(データシート14.4節参照)。

NIC はハードウェア割り込みを発生させて、OS にパケットの存在を知らせます。割り込みのタイミングとしては、一定間隔で行う設定やパケットが Receive Buffer に格納されるたびに行う設定が可能なようです(データシート3.2.7節)。

デバイスドライバ

NIC が発生させた割り込みは NIC に対応するデバイスドライバが処理します。E1000 のデバイスドライバのソースコード を見てみます。

割り込みハンドラとして登録されているのは、以下のe1000_intr関数です。

https://github.com/torvalds/linux/blob/cf1182944c7cc9f1c21a8a44e0d29abe12527412/drivers/net/ethernet/intel/e1000/e1000_main.c#L3740-L3788

ハンドラ内では、NAPI (New API) の__napi_schedule関数に&adapter->napiという構造体を渡しています。

NAPI

先ほど登場した__napi_schedule関数は____napi_schedule関数を呼び、その中で__raise_softirq_irqoff(NET_RX_SOFTIRQ)関数が呼ばれます。
https://github.com/torvalds/linux/blob/cf1182944c7cc9f1c21a8a44e0d29abe12527412/net/core/dev.c#L4473
この関数は NET_RX_SOFTIRQ ソフトウェア割り込みを発生させます。この割り込みのハンドラはnet_rx_action関数です。

https://github.com/torvalds/linux/blob/cf1182944c7cc9f1c21a8a44e0d29abe12527412/net/core/dev.c#L6741-L6803
net_rx_actionは続いてnapi_poll関数を実行し、その中で__napi_schedule関数に引数として渡されたnapi_struct構造体のpollメンバを実行します。

E1000 の場合、pollとして登録されているのは以下のe1000_clean関数です。
https://github.com/torvalds/linux/blob/cf1182944c7cc9f1c21a8a44e0d29abe12527412/drivers/net/ethernet/intel/e1000/e1000_main.c#L3790-L3819

この後、napi_gro_receive関数などを通してNAPIにパケットが渡され、IPやTCP/UDPなどのプロトコルスタックの処理が行われたのち、ソケット API などを通してアプリケーションにデータが渡されます。

Discussion