TCP输入 tcp_queue_rcv

static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen,
          bool *fragstolen)
{
    int eaten;

    /* 取队尾 */
    struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue);

    __skb_pull(skb, hdrlen);

    /* 尝试进行分段合并 */
    eaten = (tail &&
         tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0;

    /* 更新下一个期望接收的序号 */
    tcp_rcv_nxt_update(tcp_sk(sk), TCP_SKB_CB(skb)->end_seq);

    /* 未合并 */
    if (!eaten) {
        /* 添加到队列尾部 */
        __skb_queue_tail(&sk->sk_receive_queue, skb);

        /* 关联控制块 */
        skb_set_owner_r(skb, sk);
    }
    return eaten;
}

tcp_try_coalesce函数进行合并数据段操作,若合并成功,则更新CB中的对应字段值;

static bool tcp_try_coalesce(struct sock *sk,
                 struct sk_buff *to,
                 struct sk_buff *from,
                 bool *fragstolen)
{
    int delta;

    *fragstolen = false;

    /* Its possible this segment overlaps with prior segment in queue */
    /* 序号对不上 */
    if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq)
        return false;

    /* 尝试合并到前一个数据段 */
    if (!skb_try_coalesce(to, from, fragstolen, &delta))
        return false;

    /* 调整内存使用 */
    atomic_add(delta, &sk->sk_rmem_alloc);
    sk_mem_charge(sk, delta);
    NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVCOALESCE);

    /* 更新cb相关字段 */
    TCP_SKB_CB(to)->end_seq = TCP_SKB_CB(from)->end_seq;
    TCP_SKB_CB(to)->ack_seq = TCP_SKB_CB(from)->ack_seq;
    TCP_SKB_CB(to)->tcp_flags |= TCP_SKB_CB(from)->tcp_flags;
    return true;
}

skb_try_coalesce函数为详细的合并过程,在进行了必要的合并检查之后进行合并;其中当skb线性区域有数据的时候,会将该线性区域处理成frag,并合并到模板skb中;对于非线性区域,则直接进行拷贝,如果是clone的,还需要增加frag的引用计数;合并完成之后,调整skb数据长度值;

bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
              bool *fragstolen, int *delta_truesize)
{
    int i, delta, len = from->len;

    *fragstolen = false;

    /* 不能为克隆 */
    if (skb_cloned(to))
        return false;

    /* to尾部能够容纳得下新数据 */
    if (len <= skb_tailroom(to)) {
        /* from拷贝到to尾部 */
        if (len)
            BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len));
        *delta_truesize = 0;
        return true;
    }

    /* to或者from有分片 */
    if (skb_has_frag_list(to) || skb_has_frag_list(from))
        return false;

    /* 线性缓冲区数据长度不为0 */
    if (skb_headlen(from) != 0) {
        struct page *page;
        unsigned int offset;

        /* 达到最大frags限制 */
        if (skb_shinfo(to)->nr_frags +
            skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
            return false;
        /* skb被锁定 */
        if (skb_head_is_locked(from))
            return false;

        /* 计算数据增量,去掉头部 */
        delta = from->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));

        /* 找到对应的页和偏移 */
        page = virt_to_head_page(from->head);
        offset = from->data - (unsigned char *)page_address(page);

        /* 根据from的页和偏移在to的frags上增加一个frag */
        skb_fill_page_desc(to, skb_shinfo(to)->nr_frags,
                   page, offset, skb_headlen(from));
        *fragstolen = true;
    } else {

        /* 达到最大frags限制 */
        if (skb_shinfo(to)->nr_frags +
            skb_shinfo(from)->nr_frags > MAX_SKB_FRAGS)
            return false;

        /* 计算增量,减掉所有头部和无数据线性区域 */
        delta = from->truesize - SKB_TRUESIZE(skb_end_offset(from));
    }

    WARN_ON_ONCE(delta < len);

    /* 拷贝frags */
    memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags,
           skb_shinfo(from)->frags,
           skb_shinfo(from)->nr_frags * sizeof(skb_frag_t));
    /* 增加frags数量 */
    skb_shinfo(to)->nr_frags += skb_shinfo(from)->nr_frags;

    /* 不是克隆的,设置from的frags为0 */
    if (!skb_cloned(from))
        skb_shinfo(from)->nr_frags = 0;

    /* if the skb is not cloned this does nothing
     * since we set nr_frags to 0.
     */
    /* 克隆的,则需要对frags增加引用 */
    for (i = 0; i < skb_shinfo(from)->nr_frags; i++)
        skb_frag_ref(from, i);

    /* 总长度加上增量 */
    to->truesize += delta;

    /* 总数据长度增加 */
    to->len += len;
    /* 非线性数据长度增加 */
    to->data_len += len;

    /* 记录增量 */
    *delta_truesize = delta;
    return true;
}
posted @ 2019-07-01 23:14  codestacklinuxer  阅读(321)  评论(0编辑  收藏  举报