Linux协议栈(8)——传输层实现

Linux协议栈(8)——传输层实现

ip_local_deliver负责分发IP分组传输的数据内容。基于IP的主要传输协议分别是UDP和TCP。处理函数分别是udp_rcv和tcp_rcv。

1.1.1.1  接收

1.1.1.1.1          tcp接收

函数tcp_v4_rcv()定义在net/ipv4/tcp_ipv4.c中负责接收来自网络层的TCP数据包。相比UDP,TCP在内核中实现要困难得多,其状态转换如下图,珍藏多年的一张好图,高清图可以从网上 https://download.csdn.net/download/notbaron/10283521下载。

Linux协议栈(8)——传输层实现_第1张图片

  tcp报头定义在include/uapi/linux/tcp.h

struct tcphdr {         

        __be16  source; 

        __be16  dest;   

        __be32  seq;    

        __be32  ack_seq;

#if defined(__LITTLE_ENDIAN_BITFIELD)

        __u16   res1:4

                doff:4

                fin:1,  

                syn:1,

                rst:1,

                psh:1,  

                ack:1,

                urg:1,  

                ece:1,

                cwr:1;  

#elif defined(__BIG_ENDIAN_BITFIELD)

        __u16   doff:4,

                res1:4

                cwr:1,  

                ece:1,  

                urg:1,  

                ack:1,  

                psh:1,  

                rst:1,  

                syn:1,

                fin:1;  

#else 

#error  "Adjust your defines"

#endif                  

        __be16  window; 

        __sum16 check;  

        __be16  urg_ptr;

};

tcp协议对象,位于net/ipv4/af_inet.c文件中

static struct net_protocol tcp_protocol = {

        .early_demux    =       tcp_v4_early_demux,

        .early_demux_handler =  tcp_v4_early_demux,

        .handler        =       tcp_v4_rcv,

        .err_handler    =       tcp_v4_err,

        .no_policy      =       1,  

        .netns_ok       =       1,  

        .icmp_strict_tag_validation = 1,

};

 在inet_init(net/ipv4/af_inet.c)函数中调用inet_add_protocol(net/ipv4/protocol.c)函数来添加协议。

  tcp定时器定义在net/ipv4/tcp_timer.c中,有四个定时器:重传定时器、延迟确认定时器、存活定时器、零窗口探测定时器。

TCP的接收入口是tcp_v4_rcv, 调用__inet_lookup_skb函数,该函数会调用__inet_lookup,调用

__inet_lookup_established函数,检测套接字,没有套接字就调用__inet_lookup_listener.

  根据链接的状态,如果sk->sk_state == TCP_LISTEN,调用tcp_v4_do_rcv,进入TCP状态自动机。

  代码流程图如下:

Linux协议栈(8)——传输层实现_第2张图片

 


1.1.1.1.2          udp接收

  udp_rcv是处理UDP数据包的函数,定义在net/ipv4/udp.c,该函数是__udp4_lib_rcv函数的包装函数。入参包含套接字缓冲区。会调用__udp4_lib_lookup_skb函数在udptable中找套接字,找到则调用udp_queue_rcv_skb函数。

            udp包头文件定义在:include/uapi/linux/udp.h 文件中。

struct udphdr {

        __be16  source;

        __be16  dest;

        __be16  len;

        __sum16 check;  

};

Linux协议栈(8)——传输层实现_第3张图片 

1.1.1.2  发送

1.1.1.2.1          tcp发送分组

  tcp分组的发送从tcp_sendmsg函数调用开始。tcp_sendmsg(net/ipv4/tcp.c)函数会首先检查已经建立的 TCP connection 的状态,然后获取该连接的MSS,开始发送流程。

  构造 TCP 段的 playload:它在内核空间中创建该 packet 的 sk_buffer 数据结构的实例 skb,从 用户空间的 buffer 中拷贝 packet 的数据到 skb 的 buffer。构造 TCP header。

  计算 TCP 校验和(checksum)和 顺序号 (sequence number)。TCP的校验和是必需的。然后发到 IP 层处理:调用 IP handler 句柄 ip_queue_xmit,将 skb 传入 IP 处理流程。

  SOCK_STREAM类socket的TCP层操作函数集实例为tcp_prot定义在net/ipv4/tcp_ipv4.c文件中。之后调用tcp_write_xmit()来把sock发送队列中的skb尽量地发送出去。

传输层协议inet_sendmsg的proto指向的操作也不一样,而对于TCP协议,inet_sendmsg指向tcp_sendmsg函数,

 

1.1.1.2.2          udp发送分组
对于 UDP socket 来说, sendto 调用,真正去做工作的是 udp_sendmsg 这个函数 , 定义在 net/ipv4/udp.c文件中

你可能感兴趣的:(Linux,网络,linux网络协议栈)