Linuxカーネルに関する技術情報を集めていくプロジェクトです。現在、Linuxカーネル2.6解読室の第2章までを公開中。
IPv4だけに限って説明する。IPv4とIPv6はtcp_funcテーブルにより処理を切り替えるが、ここではIPv4用の方だけを説明する。
アプリケーションからのデータ送信処理要求は、socketレイヤを経由しinet_sendmsg関数を呼び出す(struct proto_ops inet_stream_opsインターフェイステーブル経由)ことにより実現される。inet_sendmsg関数は、即tcp_v4_sendmsg関数を呼び出す。(struct proto tcp_protインターフェイステーブル経由)。
tcp_v4_sendmsg関数は即tcp_do_sendmsg関数を呼び出す。
tcp_do_sendmsg関数は、アプリケーションに指定されたデータ量を格納できるだけのパケット(sk_buff)を複数確保(sock_wmalloc)し、データを格納し送信を試みる(tcp_send_skb関数)(もしバッファが上限いっぱいになりパケットを確保できなときは、確保できるまで待ちに入る)ユーザ空間からパケットへデータをコピーするときには、同時にチェックサムも計算する(csum_and_copy_form_user関数)。
データをパケットにコピーするとき、もし既にソケットのwrite_queueにリンクされているが、まだ送信が開始されてないパケット(send_headが指しているパケット)に空き領域があれば(skb_tailroom関数)、まずこの空き領域に送信データを詰める。
tcp_send_skb関数は、渡されたパケットをソケットのwrite_queueへリンクし、write_seqシーケンス番号をそのパケットサイズ分進める。もし即送信可能な場合(tcp_snd_test関数)、パケットの複製を行い(skb_clone関数)送信を開始する(tcp_transmit_skb関数)。ソケットのsnd_nxtシーケンス番号も送信パケットのサイズ分進める。
このとき、送信処理が失敗したときに動作する再送タイマ(tcp_retransmit_timer関数)の起動要求も行う(tcp_reset_timer(TIME_RETRANS)関数)。
もし全く相手が受信を受け付けない状態にあるときは、プローブタイマ(tcp_probe_timer関数)の起動要求を行う(tcp_reset_timer(TIME_PROBE0)関数)。プローブタイマ(tcp_probe_timer関数)は、シーケンス番号を進めずデータなしのパケットを相手に送りつけることにより、相手から最新のACKまたは最新のウィンドウサイズを返してもらう。(ウィンドウサイズが0の状態でACKパケットがロストした場合、送受信が止まったまま再開されなくなることを避けるため)
tcp_transmit_skb関数はTCPヘッダの作成を行い、チェックサムの計算(tcp_v4_send_check)を行ない(これは2回目のチェックサム計算だが、前回は行ったデータ部分のチェックサム結果に、ヘッダ部分のチェックサムを計算し加える操作を行う)、IPレイヤの送信関数(ip_queue_xmit)を呼び出す。ACK情報は今回送出したパケットに載せてあるため、遅延ACK要求は必要なくなり、要求をクリア(clear_delayed_ack関数)する。
注意 送信処理が終了しても、送信パケットが解放されずソケットにリンクされたままになっていることに注意。ウィンドウサイズを越えた送信パケットだけでなく、実際に送信を行ったパケットも再送の可能性があるため一定時間保留しておく。
(NIS)HirokazuTakahashi
2000年06月11日 (日) 22時29分57秒 JST1
[PageInfo]
LastUpdate: 2008-08-27 14:45:47, ModifiedBy: hiromichi-m
[Permissions]
view:all, edit:login users, delete/config:members