IP資料報的分區與重組 (linux核心)

來源:互聯網
上載者:User

  前面有講到過在函數ip_append_data中實現了對IP資料報的分區,這個講法是錯誤的,需要糾正一下,ip_append_data的主要任務只是建立發送網路資料的通訊端緩衝區(skb),它根據輸出路由查詢得到的輸出網路裝置介面的MTU,把超過MTU長度的應用資料分割開,並建立了多個skb,放入通訊端的發送緩衝隊列(sk_write_queue),但它並沒有為任何一個skb資料加上網路層首部,並且,隨後在ip_push_pending_frames函數中,又把發送緩衝隊列中的所有的skb,以一個鏈表的形式追加到第一個skb的end成員後面的struct
skb_shared_info結構體中的frag_list上,並只為第一個skb加上了網路層首部,所以,實際上,整個應用資料還只是在一個skb中,ip_append_data這樣做只是為接下來的真正的IP資料的分區作好準備。
    ip_push_pending_frames在完成了skb的組裝後,把它交給了函數ip_output,ip_output又調用了函數ip_finish_output,該函數對skb的長度再次進行判斷,如果長度超過輸出裝置的mtu的值,並且符合其它分區條件,則調用ip_fragment進行資料報的分區,否則直接調用ip_finish_output2輸出到資料連結層。
    IP資料的分區涉及到IP首部中的兩個欄位,即結構體struct iphdr的成員frag_off,其高三位是三個標誌位,第二位是不允許分區標誌,置該位,表示該IP資料報不允許被分區,如果發送這樣的資料報,並且資料報本身長度已經超出MTU的很制,則向發送方發一個icmp出錯報文,報文類型為目的不可達(3),代碼為需要進行分區但被設定了不允許分區的位(4);第三位如果置1,表示後面還有分區,置0表示本分區是一個完整的IP資料報的最後一個分區。frag_off的低13位表示本分區的第一個位元組在整個IP資料報中的位移量,單位是位元組數除以8,所以需要把這13位左移3位,才是真正的位移位元組數。
    有了先前ip_append_data的工作,ip_fragment的分區工作相對簡單很多。struct sk_buff的成員cb在inet域被存入了結構體struct inet_skb_parm,其定義如下:
    struct inet_skb_parm
    {
        struct ip_options   opt;
        unsigned char       flags;
#define IPSKB_FORWARDED     1
#define IPSKB_XFRM_TUNNEL_SIZE  2
#define IPSKB_XFRM_TRANSFORMED  4
#define IPSKB_FRAG_COMPLETE 8
#define IPSKB_REROUTED      16
    };
    分區完成的一個IP資料報,它的每一個skb的cb->flags被置上IPSKB_FRAG_COMPLETE標誌。ip_fragment首先為frag_list列表中的每個skb的成員sk和destructor賦上跟第一個skb同樣的值,使它們成為正常的skb。然後,為每個skb從第一個skb中拷貝中繼資料和網路層首部,並設定正確的iphdr->frag_off的值,並把它們一一輸出到資料連結層。至此,網路層的資料發送工作全部完成。
    被分區後的IP資料報,其每一個分區都在網路中獨立傳輸,所以,它們到達目的主機一般是不會同時的,並有可能亂序的。並且,它們在中間的傳輸路徑上有可能被組裝,也有可能被再次分區。由於網路層首部中frag_off的存在,使得重新正確組裝成為可能。下面看看IP資料分區到達目的主機後,是如何被重新組裝起來的。
    協議棧收到一個IP資料報,進入網路層的第一個函數是ip_rcv,ip_rcv對資料報進行一些正確性檢查後,交給ip_rcv_finish,ip_rcv_finish查詢輸入路由後,交給dst_input,dst_input調用skb->dst->input,如果是本地接收的IP資料報,該函數即ip_local_deliver,ip_local_deliver一開始就檢查該資料報的IP首部的frag_off成員,如果發現其低13位不為0,或者高三位中的第三位被置1,則表示這是一個IP分區(第一個分區的低13位為0,但高三位中的第三位被置1,表示後面還有分區,最後一個分區標誌位置0,但低13位不為0,中間的分區,兩者都不為0)。對於IP分區,該函數調用ip_defrag把它與已經收到的IP分區重組,並等待後來的IP分區,直至形成一個完整的IP資料報。
    一個完整IP資料報的全部IP分區組織存放在一個結構體struct ipq中,該結構體儲存有足夠的資訊,等最後一個分區到達後,把它們還原成一個IP資料報。下面是struct ipq的完整定義:
    struct ipq {
        struct hlist_node list;
        struct list_head lru_list;
        u32     user;
        u32     saddr;
        u32     daddr;
        u16     id;
        u8      protocol;
        u8      last_in;
#define COMPLETE        4
#define FIRST_IN        2
#define LAST_IN         1
        struct sk_buff  *fragments;
        int     len;
        int     meat;
        spinlock_t  lock;
        atomic_t    refcnt;
        struct timer_list timer;
        struct timeval  stamp;
        int             iif;
        unsigned int    rid;
        struct inet_peer *peer;
    };
    user是一個標誌,用於標識該IP分區組的來源,協議棧收到的來自網路其它主機或本地環回介面的IP分區,該標識值是IP_DEFRAG_LOCAL_DELIVER,saddr,daddr,id,protocol的值都來源於IP首部,用於確定這些IP分區確實是來自唯一的一個IP資料報。因為一台主機的協議棧可能同時跟網路中多台主機在進行通訊,所以,某一時刻,協議棧一般總有多組IP分區等待被重組,也就是說會有多個struct
ipq結構的執行個體,多個struct ipq被組織在一個雜湊表ipq_hash中,當收到一個IP分區時,首先用IP首部的相應欄位計算一個哈項值,找到雜湊表ipq_hash中的一項,然後去匹配上述欄位完全符合的一個struct ipq,把分區加入到該ipq中即可。如果在雜湊表中找不到跟當前的IP分區首部完全符合的項,則需要重新建立一個struct ipq的執行個體,並加到雜湊表中。新建立的ipq都帶有一個定時器(timer成員),逾時時間預設為IP_FRAG_TIME(30秒),如果30秒後,某一個IP資料報的分區還沒有全部被收到,則這個ipq逾時,逾時處理函數被執行,逾時處理函數會刪除這個ipq,並向接收端發送一個icmp出錯報文,該報文類型為逾時(11),代碼為在資料報組裝期間存留時間為0(1)。
    得到了一個ipq後,開始把收到的分區的skb放到這個ipq中,首先檢查ipq的last_in,如果它的值為COMPLETE,則表示這個分區組已經完整了,新收到的IP分區是錯誤的,直接扔掉。再檢查新收到的skb的cb->flags,因為在發送資料報進行分區時,每一個分區的flag會被置上IPSKB_FRAG_COMPLETE標誌。
    接下來檢查收到的IP分區的IP_MF(frag_off的高三位中的第三位),如果為0,表示這已經是最後一個分區了,置ipq的last_in為LAST_IN,len始終被更新為當前收到的IP分區中位移最大的那個分區的位移值加上長度,最後如果正確,則為整個IP資料報的長度。然後把這個skb剝離網路層首部後,加入到fragments鏈表中,該鏈表以frag_off中的位移量為順序組織,也就是真正的IP分區的順序,如果當前收到的這個分區的位移量為0,則置last_in的值為FIRST_IN,meat始終被更新為當前收到的IP分區的總長,最後,如果正確,meat應該等於len。
    IP分區添加完畢後,如果meat確定等於len了,可以考慮進行重組了,函數ip_frag_reasm完成重組,它取得fragments鏈表,把第二個skb開始的鏈表又重新放到第一個skb的end後面的struct skb_shared_info結構體的frag_list鏈表上,並重設IP首部,一個完整的IP資料報就被重組完成了。返回前,還要釋放ipq。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.