SO_TIMESTAMP 數據鏈路層的接收時間戳

    網絡設備在接收到來自網絡中其它主機的數據報,或本地環回接口的數據報之後,交給協議棧的netif_rx函數,該函數首先要爲收到的這個skb打上當前的時間戳(skb->tstamp成員),這個時間戳表示該數據到達的時間,它不是必選的,可以通過套接字選項SO_TIMESTAMP將其打開,該選項打開時間戳時,會將鏈路層的全局變量netstamp_needed加1,netif_rx在檢查到這個變量不爲零時,爲skb打上時間戳。


    softnet_data是類型爲struct softnet_data結構體的全局變量,每個CPU定義一個,它是鏈路層的數據接收隊列,該結構體的定義如下:
    struct softnet_data
    {
        struct net_device   *output_queue;
        struct sk_buff_head input_pkt_queue;
        struct list_head    poll_list;
        struct sk_buff      *completion_queue;
        struct net_device   backlog_dev;
    };

    input_pkt_queue是skb的隊列,接收到的skb全部進入該隊列等待後續處理,netif_rx首先檢查該隊列當前的長度input_pkt_queue.qlen,即當前排在隊列中的skb的數量,當數量超過netdev_max_backlog的值時,直接丟棄新收到的包,netdev_max_backlog在協議棧中定義的缺省值爲1000,可以通過文件/proc/sys/net/core/netdev_max_backlog進行修改。如果當前隊列長度未達到上限,把新收到的skb加到這個隊列中,在加到隊列之前,要確保對這個隊列的接收處理已啓動,如果當前隊列爲空,則要先調用netif_rx_schedule啓動隊列的處理,再把skb加到隊列中。需要注意的是softnet_data是CPU綁定的,但不是網絡設備綁定的,多個網絡設備收到的數據報可能存放在同一個隊列中待處理。


    netif_rx_schedule函數的主要作用是觸發一個軟中斷NET_RX_SOFTIRQ,使中斷處理函數net_rx_action處理接收隊列中的數據報。net_rx_action開始時會記錄下系統的當前時間,然後進行處理,當處理時間持續超過1個時鐘嘀嗒時,它會再觸發一箇中斷NET_RX_SOFTIRQ,並退出,在下一個中斷中繼續處理。一次中斷處理除了時間上有限制,處理的數據報的數量上也有限制。


    softnet_data的成員poll_list中存放的是成員backlog_dev的地址,由netif_rx_schedule存入,backlog_dev的成員poll在系統初始化時被指向函數process_backlog,net_rx_action調用該函數進行實際的數據報處理,process_backlog把數據報從input_pkt_queue隊列中取出,傳給netif_receive_skb,由netif_receive_skb傳給相應的網絡層接收函數。process_backlog的處理時間也有1個時鐘嘀嗒的限制,同時一次處理的數據報的數量不得超過backlog_dev->quota和netdev_budget兩個值中較小的那個值,backlog_dev->quota由netif_rx_schedule初始化爲全局變量weight_p的值,缺省爲64,netdev_budget缺省爲300。從代碼可以看出,process_backlog一次處理最大數據報數量爲64,而net_rx_action爲300。weight_p和netdev_budget這兩個值分別可以在文件/proc/sys/net/core/dev_weight和/proc/sys/net/core/netdev_budget中查看和修改。


    netif_receive_skb是鏈路層接收數據報的最後一站。它根據註冊在全局數組ptype_all和ptype_base裏的網絡層數據報類型,把數據報遞交給不同的網絡層協議的接收函數(INET域中主要是ip_rcv和arp_rcv)。


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