2012/08/06

網卡收到封包到網路應用程式的過程

網卡收到封包到應用程式的過程 (rtl819x, ipv4, TCP/IP)

解析網卡驅動程式

module_init(re865x_probe);
.ndo_open = re865x_open,
rc = request_irq(dev->irq, interrupt_isr, IRQF_DISABLED, dev->name, dev);
/* rtl819x 採用中斷,呼叫 interrupt_isr() */

rtl_rx_interrupt_process(status, cp);    /* 呼叫 rx 中斷處理 */
  interrupt_dsr_rx((unsigned long)cp);
    rtl_processRxFrame(&info);
      rtl_processRxToProtcolStack(skb, cp_this);
        netif_receive_skb(skb);    /* net/core/dev.c */
          rtl865x_ipMulticastFastFwd(skb)
          rtl_netif_receive_skb_hooks(skb)
          vlan_hwaccel_do_receive(skb)
          deliver_skb(skb, pt_prev, orig_dev);    /* list_for_each_entry_rcu() 找對應的 protocol。
RCU 參考 */
            pt_prev->func(skb, skb->dev, pt_prev, orig_dev);    /* 傳到第三層 */
/* 以 ip 封包當解析對象繼續 Trace */

ip_rcv(skb, skb->dev, pt_prev, orig_dev)
  ip_rcv_finish(skb);
    ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev);    /* /net/ipv4/route.c */
      ip_route_input_slow(skb, daddr, saddr, tos, dev);    /* 要看封包怎樣送到 socket,所以追蹤 local_input */
        rth->u.dst.input= ip_local_deliver;    /* 後面的 rt_intern_hash() 會呼叫 rth->u.dst.input */
        rt_intern_hash(hash, rth, &skb->rtable);    /* ip_local_deliver 在 /net/ipv4/ip_input.c */
          ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER)    /* 片段重組 /net/ipv4/ip_fragment.c */
          ip_local_deliver_finish(skb);
            ipprot = rcu_dereference(inet_protos[hash]);    /* 又是 RCU
              /* 這次要找 /net/ipv4/af_inet.c 的 inet_init() 裡面 tcp 的部分 */

              /* inet_add_protocol(&tcp_protocol, IPPROTO_TCP) */
              /* struct net_protocol tcp_protocol = { .handler =tcp_v4_rcv, } */
            ret = ipprot->handler(skb);    /* ipprot->handler 就是 tcp_v4_rcv 在 /net/ipv4/tcp_ipv4.c */
/* 轉到第四層的 tcp 封包處理 */
tcp_v4_rcv(skb)
  sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);    /* 找到對應的 socket */
    /* 在 /net/ipv4/inet_hashtables.c 的 __inet_lookup_listener() */
  ret = tcp_v4_do_rcv(sk, skb);
    tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)    /* /net/ipv4/tcp_input.c */
      __skb_queue_tail(&sk->sk_async_wait_queue, skb);
      sk->sk_data_ready(sk, 0);    /* /include/net/sock.h */

L3 Protocol RCU

第三層通訊協定程式會在 init 階段呼叫 dev_add_pack() 將自己加入 RCU 裡面。才能在 list_for_each_entry_rcu() 找到配對。
例如 net/ipv4/arp.c
void __init arp_init(void){} 裡面呼叫 dev_add_pack(&arp_packet_type);
static struct packet_type arp_packet_type __read_mostly = {
    .type =cpu_to_be16(ETH_P_ARP),    /* type 編號,ETH_P_??? 定義在 include/linux/if_ether.h */
    .func =arp_rcv,    /* 第三層應用程式呼叫的 function */
}
很大部分的封包會是 ETH_P_IP 0x0800
net/ipv4/af_inet.c
    .type = cpu_to_be16(ETH_P_IP),
    .func = ip_rcv,    /* 在 net/ipv4/ip_input.c */

沒有留言: