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数据包:
