Linux网络收发包流程

关于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_skb                                               sk->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_finish  ip_route_input    ip_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地址,然后传给网卡驱动发包。

当然,网络子系统非常复杂,不过这些对了解网络流程,对排查网络故障会起很大的作用。

文章只是一个引子,更深的学习,一定要深入代码细节,等到代码都看明白的时候,你将进入另一重世界。不说了,我去修炼了。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值