Index ソフト・ハード Linuxタスク | ネットワーク |
スタックの階層 スタックの特徴 全体図 ネットワークの実装 プロトコル登録・削除 ソケットシステムコール ラッパーとして実装 送受信データ glibc によるラッパー sockfs struct sk_buff NICとカーネルIF IPv4ソケット作成 ルーティング仕組み ルーティング処理 受信処理 送信処理 IPヘッダチェックサム リアセンブル処理 ARP解決 ICMP UDP |
LinuxのTCP/IPプロトコルスタックの階層 ・システムコールインターフェース ・(VFS) ・ソケット層 任意のプロセス間での通信インターフェース 下位層へ様々な通信プロトコルを定義 遠隔地ホスト上のプロセスとも通信可・INET ・TCP、UDP、IP ・IP層(ネットワーク層) ・イーサネット LinuxのTCP/IPプロトコルスタックの特徴 ・新規にストレートな実装を採用(STREAMS等の汎用機構は使わない) ・階層構造をもつ イーサネット等の物理デバイスを制御するデバイスドライバ上にIPプロトコルドライバ を配置、IPプロトコルドライバ上にTCP・UDP・ICMPプロトコルドライバを配置・積極的に遅延処理を用いて、スループットを向上 ・マルチプロセッサ構成時に実行並列度が向上するように工夫 ・ネットワーク実装の全体図
Linuxのネットワーク(Berkeley ソケットインターフェース)実装 ・プロセス(APがNWを利用) ・socket/file interface (system call) ・sockfs、struct file、struct dentry ・struct socket、struct proto_ops ソケットインターフェースの実装 プロトコルにあまり依存しない処理を行う。 struct socket、ソケットの実態 struct socketを小さく保つため、struct sock(sock 構造体は大きい)と分離 struct proto_ops、メソッド・struct sock、struct proto (TCP/IPネットワークプロトコル) よりプロトコルに依存した処理を行う。 TCPは、socket構造体とsock構造体を切り離して管理する。 struct sock、ソケットの実態 struct proto、メソッド・・・・ ・struct packet_type (TCP/IPネットワークプロトコル) ・(パケットスケジューラ) ・ネットワークデバイス ・イーサネット ソケット専用システムコール ・ソケット作成(socket システムコール)、ファイルデスクリプタを得る。 ・通信先へ接続(connnect/bind/listen/accept システムコール) ・データ授受(send/recv システムコール) ・接続終了(shutdown システムコール) ・ファイルデスクリプタを得る(close) ソケットAPIを、glibc によるラッパーとして実装 ・ソケット関連のシステムコールへ1つのシステムコール番号だけ割当て(CPUによる) システムコールの実態は、socketcall・socket API→glibc→socketcall→system call発行→sys_socketcall→switch分岐→sys_XXX int socketcall (ソケットAPI, 引数)・ソケット作成(sys_socket システムコール)、ファイルデスクリプタを得る。 ・通信先へ接続(sys_connnect/sys_bind/sys_listen/sys_accept システムコール) ・データ授受(sys_send/sys_recv システムコール) ・接続終了(sys_shutdown システムコール) ・ファイルデスクリプタを得る(close) ソケットが管理する送受信データ ・ソケットは疑似ファイルシステム(sockfs)として実装 ・ソケットバッファ(struct sk_buff)が管理 プロトコル処理でデータのコピーを発生させない作り ソケットバッファのデータ部を共有する。 メモリ上の任意のページをソケットバッファのデータとしても登録できる。sockfs(疑似ファイルシステム) ・マウントできない(MS_NOUSERフラグチェックで、EINVALエラー終了) openシステムコールで、ファイルデスクリプタを取得できない。 対応するカーネル内の構造体も生成できない。・socket/socket_pair/accept システムコールで構造体確保、ファイルデスクリプタと関連付け プロトコル処理でデータのコピーを発生させない作りstruct sk_buff ・プロトコル層の移動 各層のヘッダへのポインタを持つ(すばやくアクセス) クローン sk_buff 構造体のみコピーし、それが指しているデータはコピーしない。 コピー sk_buff 構造体が指しているデータまでコピー 全て(skb_copy) ヘッダだけ(pskb_copy)・パケット処理機能 NICとカーネルのインターフェース ・割り込みを契機としたコンテキストで処理するAPI ・NWからくるデータのパケットタイプと処理する関数を struct packet_type へ登録 該当パケット受信時にSW割込み発生、パケットタイプに応じた関数を呼び出す。・NWから受け取ったデータをIP層へ渡す。 NICはパケットを受け取ると割込みを上げる。 対応する割込みパンドラが受信処理を行い、 プロトコル層へパケットを引き渡すため、netif_rx() を呼び出す。 netif_rx() 処理後、後の処理は、SW割込みで行う。IPv4通信 IPv4ソケット作成 ・作成関数の登録 「struct net_prot_family inet_family_ops」のcreateメンバーへ、 「inet_create」関数を指定static struct net_prot_family inet_family_ops = { .family = PF_NET, .create = inet_create, .owner = THIS_MODULL,}; ・「sock_register」関数を実行 ・IPv4ソケットタイプ(TCP、UDP、RAW)の登録、削除 inet_protosw構造体(struct inet_protosw)を用いる。 配列inetsw_array inet_register_protosw 登録 inet_unregister_protosw 削除・sock構造体(struct sock) ソケット固有の情報を保持・inet_sock構造体(struct inet_sock) IP固有の情報を保持・tcp_sock/udp_sock構造体(struct tcp_sock、struct udp_sock) TCP/UDP固有の情報を保持・sock構造体から各構造体への変換関数 inet_sk、tcp_sk、udp_sk・パケット受信パンドラ(処理ルーチン)の登録 dev_add_packで登録 受信したいパケットタイプとしてip_packet_typeを指定 「struct packet_type ip_packet_type」の.funcメンバーへ、 「ip_rcv」関数(パケット受信関数)を指定static struct packet_type ip_packet_type = { .type = __constant_htons(ETH_P_IP), .func = ip_rcv,}; IPヘッダのプロトコルによって処理関数が異なる。 net_proprotcol構造体(struct net_proprotcol)とプロトコル値を指定 inet_add_protocol 登録 inet_del_protocol 削除 上位のプロトコルの受信関数(ip_rcvと互いにリンク) tcp_v4_rcv() icmp_rcv() udp_rcv()・各NWデバイスのHWアドレス、ネットマスク、MTU情報の保持 in_device構造体ルーティング仕組み ・flowi構造体 (ルーティング処理に必要な情報を格納) ・fib (forwarding information base)「静的ルーティングテーブル」 ネットマスク毎に管理 ip_fib_main_table (ユニキャスト、ルータへの送信経路情報) fib_local_table (ローカルホスト上の転送経路、マルチキャスト、ブロードキャスト)・カーネルのコンフィグレーション設定で複数のテーブルを追加使用 ・inet_peer構造体 (宛先IPアドレス毎に管理する情報) IPパケットのid、TCPで使用するタイムスタンプ AVLツリーで管理・hh_cache構造体 データリンク層で使用するアドレスのキャッシュ、パケット送信情報・近隣キャッシュ(neighbour) ・dst_entry構造体、rtable構造体 ルーティング処理 ・TCP/IPでパケットを送るときに参照 比較基準は、longest match 全ての通信の宛先IPアドレスは、テーブル内の行のいずれかに必ず合致・ルーティングテーブルキャッシュを検索 ・見つからなかったら、ルーティングテーブルを検索 ・検索結果の各種チェック ・正当なものならば、rtable構造体を確保してメンバーを初期化 ・rt_intern_hash()でルーティングテーブルキャッシュへ追加 ・ルーティングテーブルとの比較 Destination Addressとネットマスクからネットワークを算出 ネットワークとテーブルの受信先サイトが一致していれば、その行は合致する候補 複数の行が合致候補になった場合、ネットマスクが一番大きい行が最終的な合致結果 ネットマスクも同じ大きさの場合は、Metricが小さいほうが最終的な合致結果受信処理(関数の流れ) ・ネットワークデバイス ・netif_receive_skb() ・deliver_skb() ・ip_rcv() IPパケット・Mのソフトウェア割り込み(コンテキスト)で、ip_rcvへソケットバッファが来る。 ip_rcv関数でipヘッダのチェックサム計算、OKならip_rcv_finishへ処理を渡す。・ip_rcv_finish関数 必要があればルーティング処理(ip_route_input())を行う。 必要があればipヘッダのオプション解析(ip_options_compile())を行う。 dst_input関数を呼び出す。・dst_input() ・自ホストで受信の場合、ip_local_deliver() 必要ならリアッセンブル、ip_defrag() すべてのフラグメントがそろうと受信処理を呼ぶ、ip_local_deliver_finish()・転送処理の場合、ip_forward()、dst_output() ・上位レイヤーへ tcp_v4_rcv() icmp_rcv() udp_rcv()送信処理(関数の流れ) ・ip_queue_xmit() ・ソケットの宛先のキャッシュの確認 (__sk_dst_check()) ・キャッシュされてない場合ルーティング処理(ip_route_output_flow())を行う。 ルーティングテーブルキャッシュ、ルーティングテーブルの順に調べる(fib_lookup())・IPのidの割り当て (ip_select_ident_more()) ・dst_output()からip_output()を呼ぶ。 ・パケットが大きい場合、フラグメント処理 (ip_fragment()) ・ARPが解決されていれば、dev_queue_xmit()を呼びパケットを送信 ARPが解決されていなければ、neigh_resolve_output()・ARP解決を処理するタイマーを開始 ・ARPが解決された再び、neigh_resolve_output() 送信 ・送信に使われるメディアに合わせてアドレス解決等の処理を行い、 ・実際の送信は、直接相閧ノ送るか、Gatewayに転送するのどちらかをとる ・メディアがイーサネットの場合 Interfaceのところで示されているNICを使って送信 必要なMACアドレスをARPを使い取得後、NICからイーサネットに送り出す (MACアドレスは一定時間記憶され、再利用)IPヘッダチェックサム ・IPパケットにある、データの通信経路上での破損を確認できるデータ ・IPヘッダ部分のみ対象 ・計算 チェックサムフィールドを0にする。 ヘッダーに対して16ビットの1の補数合計を計算 その結果に対して1の補数を計算し、それをチェックサムとする。・受信側は、ヘッダーを合計してすべてのビットが0を確認する。 ・転送する場合は、TTLを1減じて、チェックサムに1を足す。 リアセンブル処理 ・フラグメント化された複数のIPパケットを元のIPパケットに組み立てる。 ・IPパケットの組み立てAPI ip_append_data ip_append_page ip_push_pending_framesARP解決 ・タイマーがneigh_timer_handler関数呼び出し ・arp_solicit関数からARP要求パケットを作成し送信 ・ARP応答パケット受信(arp_rcv()) パケットを解析(arp_process())し、neighbour構造体を更新(neigh_update())・ARPが解決された場合、ハードウェアヘッダーキャッシュを更新(neigh_update_hhs()) ・送信処理の関数ポインタの書き換え(neigh_connect()) ・ARP待ちになっていたパケットを送信 ICMP ・ICMPパケット受信処理(icmp_rcv()) それぞれタイプに応じた処理を行う。 ICMPメッセージタイプをインデックスとした配列(icmp_pointers)で処理を分岐・ICMPパケット送信処理(icmp_reply() or icmp_send()) 短時間に多量に送信しない。UDP ・UDP受信処理 (関数の流れ) チェックサム計算の初期化処理(udp_checksum_init()) 受信したパケットに対応するソケットを検索(udp_v4_lookup()) 見つかれば受信キューにつなぐ(udp_queue_rcv_skb()、sock_queue_rcv_skb()) 見つからなければ、チェックサム計算を完了し、パケットを破棄 チェックサムが正しければ、ICMPエラーを返す データ到着をソケットに通知 プロセス受信処理(udp_recvmsg()) 受信待ちキューからソケットバッファを取り出し、ユーザー空間にデータコピー・UDP送信処理 (関数の流れ) プロセスから(udp_sendmsg() or udp_sendpage())が呼ばれる。 データ作成(ip_append_data()、ip_append_page()) UDPヘッダ完成(udp_push_pending_frames())させ、送信(ip_push_pending_frames()) |
All Rights Reserved. Copyright (C) ITCL |