先来一张协议层的框图
传输层
struct proto
struct tcp_prot位于文件net/ipv4/tcp_ipv4.c
struct proto tcp_prot = {
.name = "TCP",
.owner = THIS_MODULE,
.close = tcp_close,
.connect = tcp_v4_connect,
.disconnect = tcp_disconnect,
.accept = inet_csk_accept,
.ioctl = tcp_ioctl,
.init = tcp_v4_init_sock,
.destroy = tcp_v4_destroy_sock,
.shutdown = tcp_shutdown,
.setsockopt = tcp_setsockopt,
.getsockopt = tcp_getsockopt,
.recvmsg = tcp_recvmsg,
.sendmsg = tcp_sendmsg,
.sendpage = tcp_sendpage,
...
};
tcp_sendmsg
tcp_sendmsg
//向队列尾添加一个struct sk_buff *skb
struct sk_buff *skb = tcp_write_queue_tail(sk);
//并使用sk中的数据初始化这个skb
skb_add_data_nocache(sk, skb, from, copy);
tcp_init_xmit_timers
inet_csk_init_xmit_timers(sk, &tcp_write_timer...) => tcp_write_timer
tcp_write_timer_handler(sk)
tcp_retransmit_timer(sk)
//从发送队列取出一块skb进行传输
struct sk_buff *skb = skb_peek_tail(&sk->sk_write_queue)
tcp_retransmit_skb(sk, skb...)
__tcp_retransmit_skb(sk, skb)
tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC)
struct inet_connection_sock *icsk = inet_csk(sk);
icsk->icsk_af_ops->queue_xmit(skb, ...)
tcp_recvmsg
tcp_recvmsg
//从接收skb队列中取出一块skb
struct sk_buff *skb = skb_peek_tail(&sk->sk_receive_queue);
//将skb中的数据赋值到msg中,供用户空间使用
skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used);
网络层
struct inet_connection_sock_af_ops
tcp_sendmsg最终调用了结构体icsk_af_ops中queue_xmit来传输队列中的skb,结构体icsk_af_ops是这么来的:
const struct inet_connection_sock_af_ops ipv4_specific = {
.queue_xmit = ip_queue_xmit,
.send_check = tcp_v4_send_check,
.rebuild_header = inet_sk_rebuild_header,
.sk_rx_dst_set = inet_sk_rx_dst_set,
.conn_request = tcp_v4_conn_request,
.syn_recv_sock = tcp_v4_syn_recv_sock,
.net_header_len = sizeof(struct iphdr),
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
.addr2sockaddr = inet_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in),
.bind_conflict = inet_csk_bind_conflict,
};
tcp_v4_init_sock(struct sock *sk)
struct inet_connection_sock *icsk = inet_csk(sk);
icsk->icsk_af_ops = &ipv4_specific;
ip_queue_xmit
//dst.output赋值
tcp_v4_conn_request
inet_csk_route_req
ip_route_output_flow
__ip_route_output_key
__mkroute_output
rth->dst.output = ip_output
//使用dsp.output=ip_out来发送数据
ip_queue_xmit
ip_local_out(skb)
dst_output(skb)
skb_dst(skb)->output(skb) ==> ip_out
ip_finish_output
ip_fragment(skb, ip_finish_output2)
ip_finish_output2(skb)
dst_neigh_output
neigh_hh_output
dev_queue_xmit(skb)
ip_rcv
//dst.input赋值
tcp_v4_conn_request
inet_csk_route_req
ip_route_output_flow
__ip_route_output_key
__mkroute_output
rth->dst.input = ip_local_deliver
ip_rcv
ip_rcv_finish
dst_input(skb)
skb_dst(skb)->input(skb) ==> ip_local_deliver
ip_local_deliver_finish
//这个handler便是上面struct net_protocol中的handler
ipprot->handler(skb)
在上面ip_local_deliver中最终会调用ipprot->handler,这个handler就是之前在net/ipv4/af_inet.c文件中注册的他会将底层接收的skb放到接收skb队列中去。
static const struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
...
};
tcp_v4_rcv(struct sk_buff *skb)
tcp_v4_do_rcv(sk, skb)
tcp_rcv_established
tcp_queue_rcv
//将底层接收的skb放到接收skb队列中
__skb_queue_tail(&sk->sk_receive_queue, skb);
然而ip_rcv又是在哪里被调用的?
net/ipv4/af_inet.c
static struct packet_type ip_packet_type __read_mostly = {
...
.func = ip_rcv,
};
/net/core/dev.c
netif_receive_skb
__netif_receive_skb(skb)
__netif_receive_skb_core
pt_prev->func ⇒ ip_rcv
当底层(数据链路层)ethernet driver收到网络数据包后会调用在net/core/dev.c文件中的函数netif_receive_skb,最终会调用ip_rcv将skb传递给上层使用。