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_slow
ip_route_input_slow()
{
  …
  rth->u.dst.input = ip_forward;
  …
  rth->u.dst.input= ip_local_deliver;
}

參考:

1.《understanding the linux kernel》

2. 謝寶友Linux kernel 2.6.11.12源碼註釋

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章