关于linux网络包的收发流程,网上随便一搜都可以搜一桶,但自己不动手永远都搞不原理。最近在家比较闲,对网络这一块也不太了解,小编习惯熟悉内核子系统原理从低版本内核开始.
Linux(2.6.11.12)网络收包流程图:

device driver interrupt handler
netif_rx()cpu_raise_softirq()do_softirq()net_rx_atcion()dev->poll(dev, &budget)( process_backlog)(注0)process_backlog()netif_receive_skb()skb_bond(skb); 如果网卡绑定,则取netdev 的master设备pt_prev->func() (注1)type = skb->protocol(L3层 ipv4 or ipv6 ..)ip_rcv()NF_HOOK(PF_INET,NF_IP_PRE_ROUTING,skb, dev, NULL,ip_rcv_finish);ip_rcv_finish()dst_input()skb->dst->input();(注2)(ip_local_deliver或ip_forward)ip_local_deliver()NF_HOOK(PF_INET,NF_IP_LOCAL_IN, skb, skb->dev, NULL,ip_local_deliver_finish);ip_local_deliver_finish()ipprot->handler(skb);(L4层 udp_rcv/tcp_v4_rcv..)udp_rcv()udp_queue_rcv_skb()sock_queue_rcv_skbsk->sk_data_ready() (sock_def_readable)static void sock_def_readable(structsock *sk, int len){read_lock(&sk->sk_callback_lock);if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))wake_up_interruptible(sk->sk_sleep);sk_wake_async(sk,1,POLL_IN);read_unlock(&sk->sk_callback_lock);}sys_recvfrom()sock_recvmsg()sock->ops->recvmsg()(sock_common_recvmsg)sock_common_recvmsg()sk->sk_prot->recvmsg()(udp_recvmsg)udp_recvmsg()skb_recv_datagram()wait_for_packet()static int wait_for_packet(structsock *sk, int *err, long *timeo_p){…DEFINE_WAIT(wait);prepare_to_wait_exclusive(sk->sk_sleep,&wait,TASK_INTERRUPTIBLE);…}注0:net_dev_init(){…queue->backlog_dev.poll = process_backlog;…}注1:void __init ip_init(void){dev_add_pack(&ip_packet_type);}static struct packet_type ip_packet_type = {.type = __constant_htons(ETH_P_IP),.func = ip_rcv,};void __init ipv6_packet_init(void){dev_add_pack(&ipv6_packet_type);}static struct packet_type ipv6_packet_type = {.type = __constant_htons(ETH_P_IPV6),.func = ipv6_rcv,};void dev_add_pack(struct packet_type *pt){…list_add_rcu(&pt->list, &ptype_base[hash]);…}注2:ip_rcv_finiship_route_inputip_route_input_slowip_route_input_slow(){…rth->u.dst.input = ip_forward;…rth->u.dst.input= ip_local_deliver;}
前段时间写了Linux网络收包流程一文,没想到很多人感兴趣,现上货网络发包流程。

sys_write()
file->f_op->write()(sock_writev)(注0)
sock_writev()
sock_sendmsg()
sock->ops->sendmsg()
(inet_sendmsg)
structsock *sk = sock->sk;
sk->sk_prot->sendmsg(); (注1)
udp_sendmsg()
udp_push_pending_frames()
ip_push_pending_frames()
dst_output()
ip_output()
/ip_mc_output()
ip_finish_output()
dev_queue_xmit()
注0:
sock_map_fd()
file->f_op =SOCK_INODE(sock)->i_fop =
&socket_file_ops
注1:
struct proto_opsinet_stream_ops = {
…
.sendmsg = inet_sendmsg
…
}
struct proto udp_prot ={
…
.name = "UDP",
.sendmsg = udp_sendmsg,
…
}
网络收包简单总结:
首先网卡驱动申请一个著名的数据结构sk_buffer,根据数据包中的网络类型 type = skb->protocol(L3层 ipv4 or ipv6 ..) ,去调用提前注册在内核中的ipv4 or ipv6 ..协议处理函数,比如调用ip_rcv(),然后进一步解包,比如根据目的MAC地址和目的IP地址确定是否转发包,然后从包中解出是TCP or UDP,同样调用内核中注册好的回调函数处理,然后根据网络包的信息(hash一下,怎么hash看源码:) )对接上收包之前sys_recvfrom()建立的sock,最后进一步唤醒等待收包的进程。
网络发包简单总结:
发包相对容易理解一些,比如首先调用sys_sendto(),比如在L4层确定TCP or UDP,同样调用L4层注册好的函数,L3层根据路由表子系统确定IP地址,L2层根据邻居子系统确定MAC地址,然后传给网卡驱动发包。
当然,网络子系统非常复杂,不过这些对了解网络流程,对排查网络故障会起很大的作用。
文章只是一个引子,更深的学习,一定要深入代码细节,等到代码都看明白的时候,你将进入另一重世界。不说了,我去修炼了。
1万+

被折叠的 条评论
为什么被折叠?



