1. rcv_scale的确定
缓存的配置对后面三次握手交互时,设置window scale的值有很大的关系,window scale的值是在三次握手时通过tcp option确定。
1.1 client发送syn
在三次握手的过程中会根据配置的缓存大小,确定scale的大小,在发送syn数据包和syn+ack报文中,在创建syn数据包时,调用tcp_connect_init函数,在该函数中tcp_select_initial_window函数,对rcv_wscale进行赋值。
点击(此处)折叠或打开
-
void tcp_select_initial_window(int __space, __u32 mss,
-
__u32 *rcv_wnd, __u32 *window_clamp,
-
int wscale_ok, __u8 *rcv_wscale,
-
__u32 init_rcv_wnd)
-
{
-
unsigned int space = (__space < 0 ? 0 : __space);
-
-
/* If no clamp set the clamp to the max possible scaled window */
-
if (*window_clamp == 0)
-
(*window_clamp) = (65535 << 14);
-
space = min(*window_clamp, space);
-
-
/* Quantize space offering to a multiple of mss if possible. */
-
if (space > mss)
-
space = (space / mss) * mss;
-
-
if (sysctl_tcp_workaround_signed_windows)
-
(*rcv_wnd) = min(space, MAX_TCP_WINDOW);
-
else
-
(*rcv_wnd) = space;
-
(*rcv_wscale) = 0;
-
if (wscale_ok) { /*这里的wscale_ok对应于sysctl_tcp_window_scaling参数,该参数内核默认配置为1,表示启用scale*/
-
space = max_t(u32, sysctl_tcp_rmem[2], sysctl_rmem_max);
-
space = min_t(u32, space, *window_clamp);
-
while (space > 65535 && (*rcv_wscale) < 14) { /*如果可用的space大于win能表示的最大值,并且wsacle小于14,则对rcv_wscale进行加1,对space缩小。*/
-
space >>= 1;
-
(*rcv_wscale)++;
-
}
-
}
-
-
if (mss > (1 << *rcv_wscale)) {
-
if (!init_rcv_wnd) /* Use default unless specified otherwise */
-
init_rcv_wnd = tcp_default_init_rwnd(mss);
-
*rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss);
-
}
-
-
/* Set the clamp no higher than max representable value */
-
(*window_clamp) = min(65535U << (*rcv_wscale), *window_clamp);
- }
1.2 syn_ack报文设置rcv_wscale
在接收到syn报文后,发送syn+ack报文下面是设置rcv_scale的流程,也是调用tcp_select_initial_window函数进行初始化。
点击(此处)折叠或打开
-
static unsigned int tcp_synack_options(struct sock *sk,
-
struct request_sock *req,
-
unsigned int mss, struct sk_buff *skb,
-
struct tcp_out_options *opts,
-
const struct tcp_md5sig_key *md5,
-
struct tcp_fastopen_cookie *foc)
-
{
-
struct inet_request_sock *ireq = inet_rsk(req);
-
unsigned int remaining = MAX_TCP_OPTION_SPACE;
-
-
#ifdef CONFIG_TCP_MD5SIG
-
if (md5) {
-
opts->options |= OPTION_MD5;
-
remaining -= TCPOLEN_MD5SIG_ALIGNED;
-
ireq->tstamp_ok &= !ireq->sack_ok;
-
}
-
#endif
-
-
/* We always send an MSS option. */
-
opts->mss = mss;
-
remaining -= TCPOLEN_MSS_ALIGNED;
-
if (likely(ireq->wscale_ok)) { //设置tcp的选项信息wscale
-
opts->ws = ireq->rcv_wscale;
-
opts->options |= OPTION_WSCALE;
-
remaining -= TCPOLEN_WSCALE_ALIGNED;
-
}
-
if (likely(ireq->tstamp_ok)) {
-
opts->options |= OPTION_TS;
-
opts->tsval = tcp_skb_timestamp(skb);
-
opts->tsecr = req->ts_recent;
-
remaining -= TCPOLEN_TSTAMP_ALIGNED;
-
}
-
if (likely(ireq->sack_ok)) {
-
opts->options |= OPTION_SACK_ADVERTISE;
-
if (unlikely(!ireq->tstamp_ok))
-
remaining -= TCPOLEN_SACKPERM_ALIGNED;
-
}
-
if (foc != NULL && foc->len >= 0) {
-
u32 need = foc->len;
-
-
need += foc->exp ? TCPOLEN_EXP_FASTOPEN_BASE :
-
TCPOLEN_FASTOPEN_BASE;
-
need = (need + 3) & ~3U; /* Align to 32 bits */
-
if (remaining >= need) {
-
opts->options |= OPTION_FAST_OPEN_COOKIE;
-
opts->fastopen_cookie = foc;
-
remaining -= need;
-
}
-
}
-
return MAX_TCP_OPTION_SPACE - remaining;
- }
1.3 解析scale选项
接收到带有tcp选项scale数据报文时,处理流程如下,只针对syn数据包: