TCP:伝送制御プロトコル(一)


関連プロトコル分析はtcp/ipプロトコル学習ノート(8)TCP伝送制御プロトコルを参照する
TCP転送制御ブロックの管理、ソケットオプション、ioctl、エラー処理およびキャッシュ管理は、以下のファイルに関連する.
include/linux/tcp.h TCPセグメントのフォーマット、TCP伝送制御ブロックなどの構造、マクロと関数プロトタイプを定義する
include/net/sock.h基本的な伝送制御ブロック構造、マクロ、関数プロトタイプを定義する
include/net/inet_connection_sock.h接続要求ブロック等の関連インタフェース、マクロ及び関数の定義
include/net/inet_hashtables.h転送制御ブロックを管理するハッシュリストを定義する
net/ipv4/af_inet.cネットワーク層と伝送層インタフェース
net/ipv4/tcp_ipv4.c伝送制御ブロックとネットワーク層との間のインタフェース実装
net/ipv4/tcp.c伝送制御ブロックとアプリケーション層との間のインタフェース実装
net/core/stream.c TCP中流メモリ管理の実現
TCP転送制御ブロック
TCP転送制御ブロックは、接続の確立、データの転送、混雑した制御、および接続の終了を含むTCP全体のプロセスにおいて核心的な役割を果たす.TCP接続の全過程において、以下の3種類のTCP伝送制御ブロックを順次使用する.
1、第1のタイプはtcp_request_sockは、接続を確立する過程で使用され、存在時間が比較的短い
2、第2タイプはtcp_sockは、接続確立後に終了する前に使用され、TCP状態はESTABLISHEDである.このような伝送制御ブロックは、最も長い周期を宣言し、送信および受信セグメントは制御する必要がある.
3、第三のタイプはtcp_timewait_sockは、接続を終了する過程で使用され、その存在過程も比較的短い
inet_connection_sock_af_ops
ネットワーク層に送信されるインタフェース、送信層のsetsockoptインタフェースなど、伝送層に関連する一連の動作セットがカプセル化され、TCPの例はipv 4_である.specific
tcp_options_received
主に受信したTCPオプション情報(タイムスタンプ、SACKなど)を保存するとともに、ウィンドウ拡大係数、ACKなどのエンドツーエンドサポートの特性を示す.
tcp_skb_cb
TCP層は、SKB領域にプライベート情報制御ブロック、すなわちskb_を有するbuff構造のcbメンバーで、TCPはこのフィールドを利用してtcp_を格納します.skb_cb構造.TCP層ではマクロTCP_SKB_CBは、コードの可読性を向上させるために、この情報ブロックへのアクセスを実現する.このプライベート情報制御ブロックに対する付与は、一般に、本層がセグメントまたは送信セグメントを受信する前に行われる.例えばtcp_v4_rcv()はTCP層受信エントリ関数であり、TCPセグメントを受信して必要な検証を行うと、このセグメントのtcp_skb_cbを設定します.一方,送信過程では,TCPセグメントを生成する際,あるいはTCPセグメントをセグメント化する際に設定することが多い.
TCPの初期化
トランスポート層TCPモジュールの初期化関数tcp_Init()IPv 4プロトコルファミリーによる初期化関数inet_Init()呼び出し
void __init tcp_init(void)
{
	struct sk_buff *skb = NULL;
	unsigned long nr_pages, limit;
	int i, max_share, cnt;

	BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));

	percpu_counter_init(&tcp_sockets_allocated, 0);
	percpu_counter_init(&tcp_orphan_count, 0);
	tcp_hashinfo.bind_bucket_cachep =
		kmem_cache_create("tcp_bind_bucket",
				  sizeof(struct inet_bind_bucket), 0,
				  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

	/* Size and allocate the main established and bind bucket
	 * hash tables.
	 *
	 * The methodology is similar to that of the buffer cache.
	 */
	tcp_hashinfo.ehash =
		alloc_large_system_hash("TCP established",
					sizeof(struct inet_ehash_bucket),
					thash_entries,
					(totalram_pages >= 128 * 1024) ?
					13 : 15,
					0,
					&tcp_hashinfo.ehash_size,
					NULL,
					thash_entries ? 0 : 512 * 1024);
	tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size;
	for (i = 0; i < tcp_hashinfo.ehash_size; i++) {
		INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
		INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].twchain, i);
	}
	if (inet_ehash_locks_alloc(&tcp_hashinfo))
		panic("TCP: failed to alloc ehash_locks");
	tcp_hashinfo.bhash =
		alloc_large_system_hash("TCP bind",
					sizeof(struct inet_bind_hashbucket),
					tcp_hashinfo.ehash_size,
					(totalram_pages >= 128 * 1024) ?
					13 : 15,
					0,
					&tcp_hashinfo.bhash_size,
					NULL,
					64 * 1024);
	tcp_hashinfo.bhash_size = 1 << tcp_hashinfo.bhash_size;
	for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
		spin_lock_init(&tcp_hashinfo.bhash[i].lock);
		INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain);
	}


	cnt = tcp_hashinfo.ehash_size;

	tcp_death_row.sysctl_max_tw_buckets = cnt / 2;
	sysctl_tcp_max_orphans = cnt / 2;
	sysctl_max_syn_backlog = max(128, cnt / 256);

	/* Set the pressure threshold to be a fraction of global memory that
	 * is up to 1/2 at 256 MB, decreasing toward zero with the amount of
	 * memory, with a floor of 128 pages, and a ceiling that prevents an
	 * integer overflow.
	 */
	nr_pages = totalram_pages - totalhigh_pages;
	limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
	limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
	limit = max(limit, 128UL);
	limit = min(limit, INT_MAX * 4UL / 3 / 2);
	sysctl_tcp_mem[0] = limit / 4 * 3;
	sysctl_tcp_mem[1] = limit;
	sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2;

	/* Set per-socket limits to no more than 1/128 the pressure threshold */
	limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7);
	max_share = min(4UL*1024*1024, limit);

	sysctl_tcp_wmem[0] = SK_MEM_QUANTUM;
	sysctl_tcp_wmem[1] = 16*1024;
	sysctl_tcp_wmem[2] = max(64*1024, max_share);

	sysctl_tcp_rmem[0] = SK_MEM_QUANTUM;
	sysctl_tcp_rmem[1] = 87380;
	sysctl_tcp_rmem[2] = max(87380, max_share);

	printk(KERN_INFO "TCP: Hash tables configured "
	       "(established %d bind %d)
", tcp_hashinfo.ehash_size, tcp_hashinfo.bhash_size); tcp_register_congestion_control(&tcp_reno); }

TCP転送制御ブロックの管理
TCP転送制御ブロックの作成に成功すると、合理的な管理が必要になります.TCPには複数の状態が存在し、一部の状態が存在する時間は比較的短く、TCPの両端が相互作用する過程で、これらの状態はすぐに別の状態に移行する.対照的に、LISTENとESTABLISHEDの2つの状態は常態である.異なる状態にあるトランスポート制御ブロックを適切に管理およびアクセスするために、TCPは、状態に応じてトランスポート制御ブロックを複数の異なるハッシュリストに格納する.
inet_hashinfo
struct inet_hashinfo {
	/* This is for sockets with full identity only.  Sockets here will
	 * always be without wildcards and will have the following invariant:
	 *
	 *          TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE
	 *
	 * TIME_WAIT sockets use a separate chain (twchain).
	 */
	struct inet_ehash_bucket	*ehash;
	spinlock_t			*ehash_locks;
	unsigned int			ehash_size;
	unsigned int			ehash_locks_mask;

	/* Ok, let's try this, I give up, we do need a local binding
	 * TCP hash as well as the others for fast bind/connect.
	 */
	struct inet_bind_hashbucket	*bhash;

	unsigned int			bhash_size;
	/* 4 bytes hole on 64 bit */

	struct kmem_cache		*bind_bucket_cachep;

	/* All the above members are written once at bootup and
	 * never written again _or_ are predominantly read-access.
	 *
	 * Now align to a new cache line as all the following members
	 * might be often dirty.
	 */
	/* All sockets in TCP_LISTEN state will be in here.  This is the only
	 * table where wildcard'd TCP sockets can exist.  Hash function here
	 * is just local port number.
	 */
	struct inet_listen_hashbucket	listening_hash[INET_LHTABLE_SIZE]
					____cacheline_aligned_in_smp;

	atomic_t			bsockets;
};
struct inet_ehash_bucket *ehash;
unsigned int ehash_size;
ehashはehash_というサイズを指すsizeのinet_ehash_bucket構造型のハッシュリストで、LISTEN以外のTCP状態の伝送制御ブロックのハッシュリストを管理する
struct inet_ehash_bucket { struct hlist_nulls_head chain; struct hlist_nulls_head twchain; }; chain、twchainは、転送制御ブロックをリンクするために使用される
struct inet_bind_hashbucket *bhash;
unsigned int bhash_size; サイズはbhash_sizeのbhashハッシュ・リストは、主にバインドされたポートの情報を格納するために使用されます.
struct inet_bind_hashbucket { spinlock_t lock; struct hlist_headchain; };
chainポートバインド情報ブロックの確立
struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE];
LISTEN状態を管理する転送制御ブロックのハッシュリストを格納する
転送制御ブロックの作成に成功すると、転送インタフェースレイヤのhashインタフェースが呼び出され、転送制御ブロックが解放されるまでehashハッシュリストに転送制御ブロックが追加される.TCPではhashインタフェースを実現する関数はtcp_v4_hash().
転送制御ブロックが不要な場合、転送インタフェースレイヤのunhashインタフェースが呼び出され、その転送制御ブロックがehashハッシュリストから削除される.TCPではhashインタフェースを実現する関数はtcp_unhash().
Listenシステム呼び出しを呼び出すと、ソケットインタフェースがLISTEN状態になり、__が呼び出されます.inet_hash()は、listening_に転送制御ブロックを追加するhashハッシュリストでは、リスニング状態にあるソケットインタフェースを迅速に検索できます.