路由表項


本地路由表項由rt_base指針管理,記錄本機路由表,當一個IP包需要傳輸到本子網以外的網絡時,就需要通過網關使用路由器來轉發,那怎么找到網關呢,就查找由rt_base指針所管理的路由表。

在linux下,我們會用 route add default gw 192.168.1.1命令來設置默認網關,把默認網關設置到路由表中,使用route命令可以查看本機設置的路由表。

如下是一個設置網關的函數

static int set_gateway(void)

{

    static int sock_fd = -1;

    struct rtentry rt;

    U32 dstaddr, gwaddr;

 

    dstaddr = inet_addr("0.0.0.0");

    gwaddr = inet_addr("192.168.1.1");

 

    /* Get an internet socket for doing socket ioctls. */

    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);

    memset(&rt, 0, sizeof(rt));

 

    /*set Destination addr*/

    SET_SA_FAMILY (rt.rt_dst, AF_INET);

    SIN_ADDR(rt.rt_dst) = dstaddr;

 

    /*set gw addr*/

    SET_SA_FAMILY (rt.rt_gateway, AF_INET);

    SIN_ADDR(rt.rt_gateway) = gwaddr;

 

    /*set genmask addr*/

    SET_SA_FAMILY (rt.rt_genmask, AF_INET);

    SIN_ADDR(rt.rt_genmask) = 0L;

    rt.rt_dev = "eth0";

    rt.rt_flags = RTF_GATEWAY;

    if(ioctl(sock_fd, SIOCADDRT, &rt) < 0)

    {

       close(sock_fd);

       KK_ERROR("[set_gateway]ioctl failed:line:%d\n",__LINE__);       

       return FAIL;

    }

    return OK;

}

函數最終會調用ioctl函數來完成。對於路由來說,完成ioctl的函數就是

int ip_rt_ioctl(unsigned int cmd, void *arg),這個函數會根據傳入的cmd是SIOCADDRT,還是SIOCDELRT,來決定是創建一個路由表項,還是刪除一個路由表項。

對於創建路由表項,系統着會再調用rt_new來繼續工作

rt_new函數會對我們傳入的參數進行判斷,看是否符合創建路由表項的條件。

首先,函數先從傳入的rt.rt_dev來判斷要創建路由表項的設備是否存在,如果不存在則退出,因為創建一個路由表項,其實就是要對路由表項結構體的各個成員進行賦值的,其結構體如下

struct rtable

{

       struct rtable           *rt_next;/*指向下一個rtable表項 */

       unsigned long        rt_dst;/*目的IP地址*/

       unsigned long        rt_mask;/*子網掩碼*/

       unsigned long        rt_gateway;/*網關地址 */

       unsigned char         rt_flags;/*標志位*/

       unsigned char         rt_metric;/*度量值(代價值*/

       short                     rt_refcnt;/*使用計數*/

       unsigned long        rt_use;/*被使用標志 */

       unsigned short        rt_mss;/*MSS值*/

       unsigned long        rt_window;/*窗口大小 */

       struct device          *rt_dev;/*與該路由項綁定的接口*/

};

其中關鍵的字段包括rt_dst,rt_mask,rt_gateway,rt_flags,rt_dev。

rt_dev即是跟路由器相連的本地網卡了,我們要發送IP包,如果目的IP不是在本地子網內,就需要把數據通過路由器轉發出去了,如果找不到本地接口設備,則表明要發送數據的媒介都沒有了,那如何發送,因此,也不需要創建路由表項了。

接着對從用戶端傳入的參數進行整理,主要是對rt_flags,rt_dst,rt_mask,rt_gateway這幾個參數進行整理,接着就調用ip_rt_add函數,創建一個路由表項,填充各成員,並把表項插入到由rt_base管理的指針。

 

當IP協議要發送一個數據包時,會判斷是否找到了目標地址所對應MAC,如果沒有找到,則會根據數據包的localroute屬性,來判斷數據包是要發往本地子網的,還是發往外網的,從而決定是調用ip_rt_local函數,還是調用ip_rt_route,要發往外網,則需要把數據發送到網關,由網關轉發,此時就要用到路由器了。由於我們設置的默認網關的目的地址是0.0.0.0,因此,任何一個往外網發送的數據包,經過路由表項目的地址跟目的地址異或后,再跟本地子網相與,都得到0值,因此,發往外網的數據包,如果沒有找到其他路由時,最終都會從默認網關發出,ip_rt_local函數返回的設備是本地設備,但是其中包含了網關的IP地址(默認網關是被排列在rt_base指針鏈表的最后一項)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM