IPv4 送信処理
Rev.10を表示中。最新版はこちら。
1. 概要
IP層(IPv4)のパケット送信処理に関するメモ。
2. 処理の流れ
ソケットを使ってデータを送信する際のIP層の処理の流れを図1に示す。
図1 送信時の流れ
3. 送信処理
3.1 IPパケットの作成
UDP,RAWソケットを使用している場合は、プロトコル層は送信データをip_append_data()を使ってsk_buffに格納する。ip_append_data()はsk_buffを割り当てて、データを格納する。
送信データを格納したsk_buffを作成した後は、RAWソケットならip_push_pending_frames()を呼び出して、さきほどip_append_data()で作成したsk_buffにIPヘッダを付けてdst_output()を呼び出す。UDPの場合はudp_push_pending_frames()を呼び出して、UDPヘッダを付けた後、RAWソケットと同じくip_push_pending_frames()を呼び出す。
TCPの場合は、データの送信が必要になった場合は、TCP層からip_queue_xmit()が呼び出される。ip_queue_xmit()はIPヘッダを付けてdst_output()を呼び出す。
3.2 dst_output()
dst_output()はsk_buffに登録されている宛先(struct dst_entry)のoutputハンドラ(skb->dst->output(skb))を呼び出すマクロ。IPv4ではip_output()を呼び出すことになる。
3.3 ip_output()
ip_output()はフィルタ処理(NF_IP_POST_ROUTING)を行なった後、ip_finish_output()を呼び出す。ip_finish_output()は送信データ長をチェックしてMTUを越えるようならip_fragment()を呼び出しIPフラグメント処理を行う。MTU内に収まっていればip_finish_output2()を呼び出して、送信処理に入る。
3.4 ip_finish_output2()
ip_finish_output2()ではIPパケットを送信するため、下位層(Neighborモジュール)にsk_buffを渡す。
この後、NeighborモジュールはパケットにMACヘッダを付けてパケットを送信する(送信キューに積む)。NextHopのMACアドレスが未解決なら、アドレス解決プロトコル(IPv4ではARP)でMACアドレスを解決してからパケットが送信される。Neighbourモジュールについては「アドレス解決プロトコル」参照。
なお、Linuxではある宛先に対するMACヘッダを作った場合、それをキャッシュ(Hard Header Cache)を作成しておき、次回からはそれをコピーするようにして、ヘッダ作成の手間を省いている。ip_finish_output2()では、Neighbourに処理を渡す前にHard Header
Cacheが存在するかチェックし、まだキャッシュがなければ、そのままNeighbourに処理を渡す。キャッシュがあった場合は、キャッシュからMACヘッダをコピーしてからhh->hh_output()を呼び出す。hh->hh_output()では、もう既にMACヘッダがついているので、なにもせずデータを送信キューに積む。
: if (hh) { /* dstにHardHeaderCacheが存在する */ /* HardHeaderCacheからレイヤ2ヘッダをパケットにコピー */ /* パケットを送信 */ return hh->hh_output(skb); } else if (dst->neighbour) (*1) /* HardHeaderCacheがない場合の送信 */ return dst->neighbour->output(skb); (*2)(*1) dst->neighbourはrt_intern_hash()でルーティングエントリをキャッシュする時に arp_bind_neighbour()をコールしてARPエントリを指すようにしている。ARPエントリがないときは空のエントリが作成されそこを指す。
(*2) アドレス解決プロトコル参照。ARP未解決ならこの中でアドレス解決処理が開始される。
関連ページ