TCP ack study

kernel version v4.5

两个重要并且容易混淆的函数:

  • tcp_v4_rcv
  • tcp_v4_do_rcv

类似于中断处理的上半部和下半部,
tcp的处理分为了的总入口函数是tcp_v4_rcv,
tcp_v4_do_rcv则是真正处理tcp报文,
并传送到用户空间。

其他的像拥塞控制,乱序调整等都在tcp_v4_do_rcv之前被做掉了。

1
2
3
4
5
6
7
8
1506 static const struct net_protocol tcp_protocol = {
1507 .early_demux = tcp_v4_early_demux,
1508 .handler = tcp_v4_rcv,
1509 .err_handler = tcp_v4_err,
1510 .no_policy = 1,
1511 .netns_ok = 1,
1512 .icmp_strict_tag_validation = 1,
1513 };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1539 int tcp_v4_rcv(struct sk_buff *skb)
1540 {
...
转换 tcp头部信息并保存到 TCP_SKB_CB
1580 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1581 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1582 skb->len - th->doff * 4);
1583 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1584 TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
1585 TCP_SKB_CB(skb)->tcp_tw_isn = 0;
1586 TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
1587 TCP_SKB_CB(skb)->sacked = 0;

查找对应的tcp socket
1589 lookup:
1590 sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
1591 if (!sk)
1592 goto no_tcp_socket;

如果是tcp server:(LISTEN socket):
1643 if (sk->sk_state == TCP_LISTEN) {
1644 ret = tcp_v4_do_rcv(sk, skb);
1645 goto put_and_return;
1646 }


一般的的tcp连接:
如果正在被用户锁定,那么就进入backlog队列。
否则则尝试进入prequeue队列。如果进入队列失败,
则直接调用 tcp_v4_do_rcv,做tcp的下半段处理。
1650 bh_lock_sock_nested(sk);
1651 tcp_sk(sk)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs);
1652 ret = 0;
1653 if (!sock_owned_by_user(sk)) {
1654 if (!tcp_prequeue(sk, skb))
1655 ret = tcp_v4_do_rcv(sk, skb);
1656 } else if (unlikely(sk_add_backlog(sk, skb,
1657 sk->sk_rcvbuf + sk->sk_sndbuf))) {
1658 bh_unlock_sock(sk);
1659 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
1660 goto discard_and_relse;
1661 }
1662 bh_unlock_sock(sk);
1663
1664 put_and_return:
1665 sock_put(sk);
1666
1667 return ret;
1