/* This function synchronize snd mss to current pmtu/exthdr set. tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts for TCP options, but includes only bare TCP header. tp->rx_opt.mss_clamp is mss negotiated at connection setup. It is minimum of user_mss and mss received with SYN. It also does not include TCP options. inet_csk(sk)->icsk_pmtu_cookie is last pmtu, seen by this function. tp->mss_cache is current effective sending mss, including all tcp options except for SACKs. It is evaluated, taking into account current pmtu, but never exceeds tp->rx_opt.mss_clamp. NOTE1. rfc1122 clearly states that advertised MSS DOES NOT include either tcp or ip options. NOTE2. inet_csk(sk)->icsk_pmtu_cookie and tp->mss_cache are READ ONLY outside this function. --ANK (980731) *///注释很重要,仔细看unsignedinttcp_sync_mss(structsock*sk,u32 pmtu){structtcp_sock*tp=tcp_sk(sk);structinet_connection_sock*icsk=inet_csk(sk);int mss_now;if (icsk->icsk_mtup.search_high > pmtu)icsk->icsk_mtup.search_high = pmtu; //根据PMTU值计算MSS,这里除了标准的IP、TCP首部外,还会考虑IP选项、TCP选项 mss_now =tcp_mtu_to_mss(sk, pmtu); //调整MSS为当前发送窗口的一半 mss_now =tcp_bound_to_half_wnd(tp, mss_now); /* And store cached results */ //将PMTU缓存到icsk_pmtu_cookie中icsk->icsk_pmtu_cookie = pmtu;if (icsk->icsk_mtup.enabled) mss_now =min(mss_now,tcp_mtu_to_mss(sk,icsk->icsk_mtup.search_low)); //最终决策出来的MSS保存在mss_cache中tp->mss_cache = mss_now;return mss_now;}
tcp_mtu_to_mss()
该函数将MTU转变为MSS值,会考虑IP选项、TCP选项。
/* Not accounting for SACKs here. */inttcp_mtu_to_mss(structsock*sk,int pmtu){structtcp_sock*tp=tcp_sk(sk);structinet_connection_sock*icsk=inet_csk(sk);int mss_now; /* Calculate base mss without TCP options: It is MMS_S - sizeof(tcphdr) of rfc1122 */ //从MTU中减去标准TCP首部、IP首部 mss_now = pmtu -icsk->icsk_af_ops->net_header_len -sizeof(struct tcphdr); /* Clamp it (mss_clamp does not include tcp options) */ //MSS不能超过对端通告的MSSif (mss_now >tp->rx_opt.mss_clamp) mss_now =tp->rx_opt.mss_clamp; /* Now subtract optional transport overhead */ //减去扩展首部,启用IPsec时,会有扩展首部 mss_now -=icsk->icsk_ext_hdr_len; /* Then reserve room for full set of TCP options and 8 bytes of data */ //MSS最小不能小于48字节if (mss_now <48) mss_now =48; /* Now subtract TCP options size, not including SACKs */ //减去TCP选项长度(不包括选择ACK选项),tp->tcp_header_len的值是该TCP连接中可能的最大TCP //首部长度,该值是在三次握手过程中根据双方对TCP选项的支持情况确定的 mss_now -=tp->tcp_header_len -sizeof(struct tcphdr);return mss_now;}