TCP连接建立之后的SACK选项解析

这几天有点犯糊涂,搞不清楚连接建立之后,SACK选项的解析在什么地方处理。内核中唯一能解析SACK选项的函数就是tcp_parse_options,但是就找不到tcp_rcv_established函数在哪里调用它。这里犯了一个错误,一直以为tcp_validate_incoming函数仅是验证报文,其中的tcp_fast_parse_options只是快速解析timestamps选项。

static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
                  const struct tcphdr *th, int syn_inerr)
{
    struct tcp_sock *tp = tcp_sk(sk);
    bool rst_seq_match = false;

    /* RFC1323: H1. Apply PAWS check first. */
    if (tcp_fast_parse_options(sock_net(sk), skb, th, tp) &&
        tp->rx_opt.saw_tstamp &&
        tcp_paws_discard(sk, skb)) {
        if (!th->rst) {
            NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
            if (!tcp_oow_rate_limited(sock_net(sk), skb,
                          LINUX_MIB_TCPACKSKIPPEDPAWS,
                          &tp->last_oow_ack_time))
                tcp_send_dupack(sk, skb);
            goto discard;
        }
        /* Reset is accepted even if it did not pass PAWS. */

然而,在tcp_fast_parse_options函数的处理中,如果报文存在SACK选项数据,timestamps选项的快速解析必然失败。快速解析是建立在TCP选项数据中仅有timestamps一个选项的基础上的。当有SACK选项时,必须执行后面的正常选项解析函数tcp_parse_options,其将解析所有的选项数据,包括SACK选项。

static bool tcp_fast_parse_options(const struct net *net,
                   const struct sk_buff *skb, const struct tcphdr *th, struct tcp_sock *tp)
{
    /* In the spirit of fast parsing, compare doff directly to constant
     * values.  Because equality is used, short doff can be ignored here.
     */
    if (th->doff == (sizeof(*th) / 4)) {
        tp->rx_opt.saw_tstamp = 0;
        return false;
    } else if (tp->rx_opt.tstamp_ok &&
           th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4)) {
        if (tcp_parse_aligned_timestamp(tp, th))
            return true;
    }

    tcp_parse_options(net, skb, &tp->rx_opt, 1, NULL);
	
    if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
        tp->rx_opt.rcv_tsecr -= tp->tsoffset;

    return true;

内核版本 5.0

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页