SylixOS網絡協議棧數據收發流程

1. SylixOS網絡協議棧基本介紹

    SylixOS網絡協議棧使用目前非常流行的嵌入式TCP/IP協議棧lwiplwip是瑞典計算機科學院(SICS)Adam Dunkels 開發的一個小型開源的TCP/IP協議棧。lwip特點是對RAMROM的佔用非常少,只需十幾KBRAM40K左右的ROM就可以運行,非常適合嵌入式系統使用。

    本文將會介紹基於dm9000網卡的數據包收發流程。

 

2. pbuf 結構介紹

        pbuf是lwip中用來表示數據包的結構體,數據包在協議棧各層的流動也是通過pbuf來實現的,基本結構如程序清單 2.1所示。

                                                                                  程序清單2.1

/* Main packet buffer struct */struct pbuf {2
    struct pbuf *next;            /* 下一個pbuf結構                      */
    void *payload;               /* 實際數據起始地址                     */
    u16_t tot_len;               /* pbuf鏈總長度                        */
    u16_t len;                  /* 當前pbuf長度                        */
    u8_t type_internal;            /* pbuf類型                          */
    u8_t flags;LWIP_PBUF_REF_T ref;    /* 初始化爲1,pbuf->next指向自己時ref加1       */
    u8_t if_idx;void *if_out;
};

        pbuf的字段type_internal表示pbuf類型,lwip中有四種類型PBUF_RAM、PBUF_ROM、PBUF_REF和PBUF_POOL:

    1) PBUF_RAM類型的pbuf結構是一塊很大的內存空間,內存首部是pbuf結構,實際數據接在後面,發送數據時常使用這種類型。如圖 2.1所示;

圖片.png

圖 2.1 PBUF_RAM類型的pbuf結構

    2) PBUF_POOL類型是由多個pbuf結構組合而成,使用next字段將這些pbuf結構連接起來。其中tot_len表示此節點和next之後所有節點的長度和,len表示當前節點的數據長度。接收數據時常使用這類型的pbuf結構。如圖 2.2所示;

圖片.png

圖 2.2 BUF_POOL類型的pbuf結構

    3) PBUF_REF與PBUF_ROM類似,pbuf結構是單獨的一塊內存空間,而data是另一塊內存,二者並不相連,如圖 2.3所示;

圖片.png

圖 2.3 BUF_REF和PBUF_ROM類型的pbuf結構

    Lwip協議棧使用pbuf結構在各層之間傳遞數據包,通過移動payload指針的方式在數據中添加報文頭和剔除報文頭,從而實現“零拷貝”機制,提高報文處理效率。

 

3. UDP 數據包發送流程

UDP數據包的發送是通過sendto()發起的(其他接口類似),整體實現流程如下:

    1) 通過文件描述符fd獲取文件結構並提取lwipfd,再通過lwipfd從socket表中獲取socket結構。Socket結構中包含了此udp鏈接中的connect信息;

    2) 使用netbuf_alloc()創建netbuf結構,這其中包含了pbuf結構。向這個結構導入需要發送的數據;

    3) Netbuf結構最終會傳入udp_send()或udp_sendto(),這其中會通過ip_route()確定最終需要發送的網卡結構netif;

    4) Udp_sendto_if_src()添加udp包頭;

    5) If_output_if_src()添加IP包頭;

    6) 根據網卡結構netif獲取發送接口netdev_netif_linkoutput(),最終調用網卡發送函數dm9000_transmit();

發送流程圖如圖 3.1所示;

圖片.png

圖 3.1 發送流程圖

 

4. UDP 數據包接收流程

    數據包接收包括兩個部分。首先網卡獲取一個數據包並使用中斷通知系統,系統解析這個數據包放入緩衝隊列中。再由應用層調用接口recv()或recvfrom()獲取這個數據包。

4.1 中斷接收

    1) 系統在初始化時會註冊網卡中斷,處理函數爲dm9000IntIsr()。當接收到一個數據包時會執行中斷處理,中斷處理內容很簡短,僅添加一個接收處理函數dm9000_receive()到任務隊列中,數據包主要在接受處理函數中被處理,減少了中斷開銷;

    2) 在dm9000_receive()中首先會創建一個POOL類型的pbuf結構,再調用驅動接口priv->inblk()從網卡中提取報文放入pbuf結構中,執行tcpip_input()處理這個數據包;

    3)通過消息隊列發送數據到網絡線程“t_netproto”,使用一個單獨的線程處理此數據包;

    4) 進入線程後執行ip4_input()進行網絡層處理,提取出運輸層數據再通過udp_input()進行udp數據包處理;

    5) 根據ip與port找到對應的udp鏈接信息即udp_pcb結構,提取pcb中對應的接收處理函數pcb->recv()即recv_udp()和鏈接結構connect,recv_udp()中會將此數據包發送到此udp鏈接的消息隊列中,等待用戶層提取;

網卡中斷接收流程如圖 4.1所示;

圖片.png

圖 4.1 網卡中斷接收流程

4.2 recvfrom()

    1) 過文件描述符fd獲取文件結構,並提取lwipfd。再通過lwipfd從socket表中獲取socket結構。Socket結構中包含了此udp鏈接中的connect信息;

    2) 根據connect信息獲取對應UDP鏈接的接收消息隊列,並通過調用netconn_recv_data()從消息隊列中獲取一條報文;

recvfrom()處理流程如圖 4.2所示;

圖片.png

圖 4.2 recvfrom()處理流程


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