http://www.cs.ccu.edu.tw/~cwr87u/Project_undergraduate/linux_firewall/www/net/ipv4/route.c.html
net/ipv4/route.c
author: elvis
linux 在設定 route 有兩個機制,一個是 fib,一個是 dynamic 產生的 routing
fib 是利用 route (man 8 route) 指定來靜態 route table
而 net/ipv4/route.c 所做的則是動能產生 routing hash,以加快 route decision 的速度
範例:
- 靜態 route table
# route -F
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.3 * 255.255.255.255 UH 0 0 0 eth0 140.123.103.156 * 255.255.255.255 UH 0 0 0 eth1 192.168.1.0 * 255.255.255.0 U 0 0 0 eth0 140.123.0.0 * 255.255.0.0 U 0 0 0 eth1 127.0.0.0 * 255.0.0.0 U 0 0 0 lo default CSIE-C5505 0.0.0.0 UG 0 0 0 eth1
- 動態 route table
# route -CKernel IP routing cache Source Destination Gateway Flags Metric Ref Use Iface infomedia.cs.cc 140.123.103.255 140.123.103.255 ri 0 6 0 eth1 CSIE-C5505 not-a-legal-add not-a-legal-add ibl 0 796989 0 lo fish.cs.ccu.edu 140.123.103.255 140.123.103.255 ri 0 2 0 eth1 didi.cs.ccu.edu 140.123.103.255 140.123.103.255 ri 0 31 0 eth1 lena.cs.ccu.edu 140.123.103.255 140.123.103.255 ri 0 2438 0 eth1 filter.cs.ccu.e 140.123.103.255 140.123.103.255 ri 0 265 0 eth1 CSIE-C5505 ALL-SYSTEMS.MCA ALL-SYSTEMS.MCA ml 0 7273 0 lo vivi.cs.ccu.edu 140.123.103.255 140.123.103.255 ri 0 7 0 eth1 gigi.cs.ccu.edu 140.123.103.255 140.123.103.255 ri 0 3 0 eth1 scoap.cs.ccu.ed 140.123.103.255 140.123.103.255 ri 0 12 0 eth1 bist.cs.ccu.edu 140.123.103.255 140.123.103.255 ri 0 86 0 eth1 macgyver.cs.ccu 140.123.103.255 140.123.103.255 ri 0 11 0 eth1
- RFC 1122 有關 IP 層 routing 的說明 這裡
一個 skb 要決定行走的路徑(input) 時 會呼叫如 ip_route_input(skb,...); 來決定他的 rtable 流程大概是 1.ip_route_input 查看是否有存在的 rtable 2.呼叫 ip_route_input_slow 產生 rtable 3.ip_route_input_slow 呼叫 fib_lookup 4.fib_lookup 從 fib_rules 找出 fib_rule 5.fib_lookup 呼叫 fib_get_table 來取得 fib_table 6.fib_lookup 使用 fib_table 呼叫 tb->tb_lookup 取得 fib_result 7.fib_lookup 將 fib_rule 設定給 fib_result 8.ip_route_input_slow 利用 rt_intern_hash 設定 rtable 9.返回 ip_route_input 此時 skb 已有設定好的 rtable還有 input/output 方法 10.返回原呼叫者 11.原呼叫者呼叫 dst->input() 處理table
/* IPv4 routing cache flags */ #define RTCF_DEAD RTNH_F_DEAD #define RTCF_ONLINK RTNH_F_ONLINK /* Obsolete flag. About to be deleted */ #define RTCF_NOPMTUDISC RTM_F_NOPMTUDISC #define RTCF_NOTIFY 0x00010000 #define RTCF_DIRECTDST 0x00020000 #define RTCF_REDIRECTED 0x00040000 #define RTCF_TPROXY 0x00080000 #define RTCF_FAST 0x00200000 #define RTCF_MASQ 0x00400000 #define RTCF_SNAT 0x00800000 #define RTCF_DOREDIRECT 0x01000000 #define RTCF_DIRECTSRC 0x04000000 #define RTCF_DNAT 0x08000000 #define RTCF_BROADCAST 0x10000000 #define RTCF_MULTICAST 0x20000000 #define RTCF_REJECT 0x40000000 #define RTCF_LOCAL 0x80000000 #define RTCF_NAT (RTCF_DNAT|RTCF_SNAT) routing type enum { RTN_UNSPEC, RTN_UNICAST, /* Gateway or direct route */ RTN_LOCAL, /* Accept locally */ RTN_BROADCAST, /* Accept locally as broadcast, send as broadcast */ RTN_ANYCAST, /* Accept locally as broadcast, but send as unicast */ RTN_MULTICAST, /* Multicast route */ RTN_BLACKHOLE, /* Drop */ RTN_UNREACHABLE, /* Destination is unreachable */ RTN_PROHIBIT, /* Administratively prohibited */ RTN_THROW, /* Not in this table */ RTN_NAT, /* Translate this address */ RTN_XRESOLVE, /* Use external resolver */ }; scope 的值 enum rt_scope_t { RT_SCOPE_UNIVERSE=0, /* User defined values */ RT_SCOPE_SITE=200, RT_SCOPE_LINK=253, RT_SCOPE_HOST=254, RT_SCOPE_NOWHERE=255 };
●用來查詢 fib table 的鍵值 struct rt_key @include/net/route.h { __u32 dst; 目的 ip 位址 __u32 src; 來源 ip 位址 int iif; input interface int oif; output interface __u8 tos; type of service __u8 scope; Unknown }; ●route table 最主要的結構 一些判斷位址的 macro #define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000)) 127.0.0.0/255.0.0.0 loopback #define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000)) class D 1110 開頭 #define BADCLASS(x) (((x) & htonl(0xf0000000)) == htonl(0xf0000000)) class E 保留的區段,不應該有人用到 11110 開頭 #define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000)) class A 且 netid 為 0000000 (七個 0) #define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000)) class D multicast ip 且 只有最小的 8bit struct rtable @include/net/route.h { union { struct dst_entry dst; struct rtable *rt_next; } u; unsigned rt_flags; RTCF_MULTICAST 之類的 flag unsigned rt_type; RTN_UNICAST 之類的型態,用來表示此 route rule 是哪種型態 __u32 rt_dst; /* Path destination */ __u32 rt_src; /* Path source */ int rt_iif; incoming interface /* Info on neighbour */ __u32 rt_gateway; /* Cache lookup keys */ struct rt_key key; /* Miscellaneous cached information */ __u32 rt_spec_dst; /* RFC1122 specific destination */ inet_peer 的結構是個 avl tree 用來紀錄各個 peer 的資訊 詳細 implement 在 inetpeer.h 與 inetpeer.c struct inet_peer *peer; /* long-living peer info */ }; ●rt_hash_table 使用的結構 struct rt_hash_bucket { @net/ipv4/route.c struct rtable *chain; rwlock_t lock; 鎖定狀態 } __attribute__((__aligned__(8))) ●route table 最主要操作的結構, 在 ip_rt_init 中配置空間且初始化 route rules 依 hash 串起來,其中 rt_hash_table[hash] 為一串 static struct rt_hash_bucket *rt_hash_table;table
static __inline__ unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos)
- 功能:產生 hash 的值
- 參數:位址和服務類型
- 回傳:hash 值
- 說明:rt_hash_table[hash]
- 功能:給 proc fs 用的函式
- 功能:給 proc fs 用的函式
- 功能:釋放 rtable->dst
- 參數:rtable
- 回傳:無
- 說明:dst_free((&rt->u.dst)
- 功能:丟棄 rtable
- 參數:rtable
- 回傳:無
- 說明:
- ip_rt_put(); //dst_release(rt) 減少 rt->u.dst.__refcnt dst 使用的次數
- dst_free((&rt->u.dst)
- 功能:檢查是不是 broadcast/multicast
- 說明:broadcast/multicast 的 rtable 應該優先被捨棄
- 功能:檢查是不是 redirect/notify rtable
- 功能:檢查 rtable 是否過期應該廢棄
- 參數:tmo1,tmo2 (tmo2 > tmo1,tmo2 harder than tmo1)
- 回傳:是否過期
- 說明:
- 349:還有在使用(__refcnt不會0) 則回傳否
- 353:已達這個 rtable 的 expire time,回傳是
- 359:age = 距最後一次使用的時間
假如 age <= tmo1 且不是屬於 broadcast 或 multicast rtable 則回傳否
都優先清除 broadcast/multicast 的 rtable
(使用 rt_fast_clean)
假如 age <= tmo2 且 rtable 是屬於 redirected 或 notify
雖已經超過 tmo1 也回傳否(比較重要)
(使用 rt_valuable) - 362:預設是 expire
- 功能:強制 rt_free 掉 rt_hash_table[] chain 中的 expire entries
- 說明:此函數為 timer 的 timer function
每 ip_rt_gc_interval 呼叫一次
- 功能:
- 清除所有的 rtable
- rt_flush_timer 的 timer function
- also called by rt_cache_flush()
- 說明:依序將 rt_hash_table[] 中的 rtable rt_free 掉
- 功能:delay 幾個 jiffies 後,call rt_flush_timer()
- 說明:
- 449:移除 rt_flush_timer,重算 delay
- 472:重設 rt_deadline
- 475:加上 rt_flush_timer
第一次的 rt_flush_timer 在這裡被掛上
- Note:delay 一開始不為 0,怎麼才會呼叫 rt_run_flush()
不過似乎只會用 0,-1 來呼叫
- 功能:maintain routing cache
動態調整routing cache 的有效時間,使其產生/過期的 rtable 速率相同 - 說明:
- 506:檢查上次的執行時間,garbage collection 不需要太常做(很費資源)
(時間間格太小或要清掉的東西不夠多,不做) - 511-527:計算現在要清除過期 rtable的個數
- 529:記錄這次 garbage collection 的時間
- 537-585:開始做 garbage collection
- 540-559:從上次做完的 hash chain 開始(rover)
541:用 rt_may_expire檢查是否 expire
把 tmo 減半增加來找 expire 的 entries的機率
(因為有可能是因為 traffic 太高,需要做快速的 expire - 583:要清的 entries 小於 rtable 的最大值就不需要做了
- 577:expire >>=1
要是 traffic 過高,很可能一個 hash chain 做不完
減小 expire 來限制 routing cache 的大小
- 540-559:從上次做完的 hash chain 開始(rover)
- 585:從 interrupt 呼叫這個 function 則只跑過一次
就強制返回 - 589:net_ratelimit()
限制 garbage collection 的速率 - 594:重設 expire
- 506:檢查上次的執行時間,garbage collection 不需要太常做(很費資源)
- 功能:將 rtable 加入 chain 中
- 說明:
- 616:從 rt_hash_table[hash] 中找相同 key 的 rtable
使用次數 +1 並將傳入的 rt rt_drop 掉 - 638:找不到現存的 rtable,若 rtable type 為 unicast forwarding path 或為 output route
則產生一個 dst - arp_bind_neighbour()
output route 或 unicast forward 時要 bind arp,因為是出去 - 653: arp_bind_neighbour 失敗, 做 rt_garbage_collect 來縮小 route table
然後重新再行執行一次 - 670:將新產生的 rtable 掛上 rt_hash_table[hash].chain
- 616:從 rt_hash_table[hash] 中找相同 key 的 rtable
- 功能:建立 rt->peer
- 說明:
- 692:inet_getpeer(); 定義在 net/ipv4/inetpeer.c
- 700:假如已經存在 rt->peer,則把產生的 peer 拿掉(inet_putpeer())
- Note:peer 是各點(每個ipv4 addess)資訊
- 功能:強制產生 ip id
- 說明:只有在 __ip_select_ident 中 rt_bind_peer 失敗才會執行這個函數來強生 random 的 ip id
- 原註解:
/*
* Peer allocation may fail only in serious out-of-memory conditions. However
* we still can generate some output.
* Random ID selection looks a bit dangerous because we have no chances to
* select ID being unique in a reasonable period of time.
* But broken packet identifier may be better than no packet at all.
*/
- 功能:
- 說明:
- 730:rt_bind_peer
- 735:rt_bind_peer 成功或 rt->peer本來就存在
inet_getid() 給予 ip id - 742:rt_bind_peer fail
ip_select_fb_ident()
- 功能:移除指定hash中的 rtable
- 參數:hash,rtable
- 回傳:
- 說明:從 rt_hash_table[hash] 中找出 rt,rt_free() 掉它
- 功能:redirect,設定新的 rtable
- 說明:找到原來的 rtable,將原來的資訊複制後
修改 gateway,flags 等轉送要改的資訊,移除原來的 rtable - 使用:net/ipv4/icmp.c icmp_redirect()
- 功能:處理毀損的 dst
- 說明:
- 891:obsolete,ip_rt_put() it
- 894:redirect 的 dst 或 expire 掉的 rt_del掉
- 功能:轉送 skb
- 說明: called by ip_forward()
- 942:經過 ip_rt_redirect_silence 長的時間沒轉送過 skb 則 reset 狀態
- 948:太多 redirect 封包,忽略(假定 host 不理我們的 redirect 封包,ip_forward() 就得幫他送 -_-")
上次 rate_last設為現在時間 - 956:check load
- 958:傳送 icmp 封包
- 功能:檢查 rt->u.dst.error
然後利用icmp_send() 送出對應的錯誤訊息 - 說明:1001:上一個發生 ip_error() 的 時間太短也不送
- 從 mtu_plateau[] 中找出小於且最接近 old_mut 的 mtu 值
預設是 68
- 功能:拆開封包,需要重新計算 mtu
- 說明:
- 1045:找到這個 ip header 所用的 rtable
- 1056-1079:計算新的 mtu
- 功能:設定新的 mtu
- 說明:
- 1096:設定 dst 的有效時間
dst_set_expires() 定義在 include/net/dst.h
- 1096:設定 dst 的有效時間
- 功能:用法 unknown
- 說明:ipv4_dst_ops 的 check funtion
release 傳進的 dst //dst_release();
- 功能:用法 unknown
- 說明:ipv4_dst_ops 的 reroute function
- Note:Linux 在 2.2/2.4 kernel 皆未實作它
- 功能:回收 dst peer
- 說明:
- 1118:rt->peer = NULL;
- 1119:inet_putpeer(peer); 定義在 include/net/inetpeer.h 將 rt->peer 放到 unused list
- 功能:利用 icmp 告知目的位址無法連結
- 參數:skb
- 說明:
- 1127:送出 icmp 告知目的位址無法連結
- 1130:設定此路徑立即失效(expire time == 0)
- 功能:輸出 skb 資訊,並 kfree_skb()
ip_route_input_mc() 指定為 dst 的 output function (rth->u.dst.output= ip_rt_bug;)
- 功能:取得 source address,從哪個 interface 出去的,ip address 就設為它
- 說明:因為沒有 cache outgoing route 的 source address
所以利用這個函數取得- 1157:iif==0,直接指定 rt->rt_src 給他
- 1159:從 fib 找
- 1169:用 inet_select_addr() 找
- 功能:依據 fib_result 的資訊來設定下一個 hop 的資訊
- 功能:利用 rt_key 找出 input 的 rtable
- 說明:
- 1633-1655:從 rt_hash_table[] 中找出相符 rt_key 的 rtable(且oif==0)
- 1505:實際產生 rt_intern_hash() 不檢查 tos(因為 tos 不同..rt_hash_code() 出來的也不會一樣)
- 1668-1686:假如是 multicast address,且在 dev 的 multicast list 中
呼叫 ip_route_input_mc() 來產生 entry - 1687:不是 multicast 也沒找到已經產生的 entry
利用 ip_route_input_slow() 新增 entry
- Note:called by
net/ipv4/arp.c arp_rcv() net/ipv4/ipip.c ipip_err() net/ipv4/ip_gre.c ipgre_err() net/ipv4/ip_input.c ip_rcv_finish() net/ipv4/ip_options.c ip_options_rcv_srr() net/ipv4/netfilter/ip_fw_compat.c fw_in()
- 功能:判斷從外面收進的 skb 的去處
- 說明:
- 前置工作
- 1336-1346:初始化 key,跟算出 hash
key.dst daddr key.src saddr key.tos tos key.iif dev->ifindex key.oif 0 沒有 output dev key.scope RT_SCOPE_UNIVERSE - 1352:檢查 saddr,不可為 multicast(class D address), badclass(class E address),loopback address
- 1355-1365:除了 0xffffffff 外的 zeronet saddr 皆為 bad source
1355:若為 broadcast(daddr 為 0xffffffff 或 saddr/daddr 都為 0x0), 跳到 brd_input 處理,這些都是 broadcast - 1364:檢查 daddr,不可為 badclass(class E address), zeronet,loopback
- 1370:fib_lookup 依據 key 值找出 res (result)
- 1404:為 broadcast type brd_input
- 1407:為 local type
- 1336-1346:初始化 key,跟算出 hash
- 真正進行 route 產生
- Ⅰ‧ip_forward()
一般的 route table(需轉送)- 1437:fib_validate_source 檢查來源是否正確,not broadcast or our local address 確定 spec_dst
- 1445:flags 加上 RTCF_DOREDIRECT
表示並不是最佳的路徑,redirect host - 1458:dst_alloc() 一個新的 route table
1462-1491:填入 route table 資料out_dev in_dev_get(FIB_RES_DEV(res)) spec_dst fib_validate_source() flags |= RTCF_DIRECTSRC if fib_validate_source err flags |= RTCF_DOREDIRECTSRC if 該通知轉送 rth->u.dst.__refcnt 1 rth->key.dst daddr rth->rt_dst daddr rth->key.tos tos rth->key.src saddr rth->rt_src saddr rth->rt_gateway daddr rth->rt_iif dev->ifindex rth->key.iif dev->ifindex rth->u.dst.dev out_dev->dev rth->u.dst.dev.refcnt ++ rth->key.oif 0 rth->rt_spec_dst spec_dst rth->u.dst.input ip_forward rth->u.dst.output ip_output rth->rt_flags flags - 1485:dst.input = ip_forward
- 1505:實際產生 rt_intern_hash()
- Ⅱ‧ip_local_deliver()
broadcast route table
- 設定 type/flags 檢查 saddr,因為不需要 forward 出去
利用 local input route table部份 code 來產生 route table 資料spec_dst inet_select_addr(dev, 0, RT_SCOPE_LINK) if ZERONET spec_dst fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,&itag) if not ZERONET flags |= RTCF_DIRECTSRC if fib_validate_source err flags |= RTCF_BROADCAST res.type RTN_BROADCAST
- 1409:fib_valid_source()
- 1414:if (result) flags 加上 RTCF_DIRECTSRC
- 配置 route table 並填入資料
如果 res.type == RTN_UNREACHABLErth->u.dst.output ip_rt_bug ip_rt_bug() rth->u.dst.__refcnt 1 rth->key.dst daddr rth->rt_dst daddr rth->key.tos tos rth->key.src saddr rth->rt_src saddr rth->rt_iif dev->ifindex rth->key.iif dev->ifindex rth->u.dst.dev &loopback_dev rth->u.dst.dev->refcnf ++ rth->key.oif 0 rth->rt_gateway daddr rth->rt_spec_dst spec_dst = daddr rth->u.dst.input ip_local_deliver ip_local_deliver() rth->rt_flags |= RTCF_LOCAL rth->rt_rype res.type rth->u.dst.input ip_error ip_error rth->u.dst.error -err rth->rt_flags &= ~RTCF_LOCAL 把剛設的拿掉 - 1563:input 正常的話為 ip_local_deliver() 往上層丟
- 1566:unreachable 則為 ip_error() 來處理
- 1505:實際產生 rt_intern_hash()
- 設定 type/flags 檢查 saddr,因為不需要 forward 出去
- Ⅲ‧no route
- route type = unreachable then do Ⅲ‧local_input
- Ⅰ‧ip_forward()
- 前置工作
- 功能:產生 multicast address 的 input rtable
- 說明:
- 1238-1248:檢查 saddr/daddr 的正確性
- 1250-1285:填入資訊, 如果在 device 的 multicast list,則 input function 為 ip_local_deliver()
- 1294:rt_intern_hash()
- 功能:利用 rt_key 找出 output 的 rtable
- 參數:rtable
- 說明:
- Note:2.2 版的相對應函數為 ip_route_output()
- 功能:產生 output routing cache/rtable
- 說明:
- 1722:if (oldkey-gtsrc)
- 1724:檢查 oldkey->src 的位址型態(multicast/badclass/zeronet return error)
- 1730:利用 src 找出去的第一個 device ip_dev_find() net/ipv4/fib_frontend.c
- 1742-1761:oldkey->oif ==0 且 oldkey->dst 是 multicast 或 0xffffffff
key.oif = dev_out->ifindex,直接 make route - 1762-1764:檢查完後 dev_out 不需要了
- 1766-1790:if (oldkey->oif)
依 oldkey->dst 型態找出 key.src - 1792-1804:沒有 key.dst,設成 loopback,make route
- 1806:if (fib_lookup()) if(找得到 fib entry)
- 存在 oldkey->oif,則 type = unicast ,不經 gateway make_route
否則 error
- 存在 oldkey->oif,則 type = unicast ,不經 gateway make_route
- 1843-1856:loopback, 設定 dev,oif make route
- 1863-1873:以上皆不符合,預設資料設定
- 1864:fib_select_default()
- 1867:FIB_RES_PREFSRC()
include/net/ip_fib.h
#define FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __fib_res_prefsrc(&res)) - 1869:取消先前找出的 dev_out
dev_out = FIB_RES_DEV
inlcude/net/ip_fib.h
#define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev) - 1872:dev_hold() dev_out->refcnt++
- 1875:make_route:
- 1876:no loopback src address error
- 1879-1884:依 dst 位址型態設定 res.type
no badclass/zeronet dst address error - 1889-1894:處理 broadcast
fib_info_put() include/net/ip_fib.h fi 不使用了
不知道為啥要 broadcast 就 dec fi - 1912-1965:配置 dst 並填 rth/rth->dst 資料
- 1967:rt_set_nexthop
- 1972:rt_intern_hash
- 1722:if (oldkey-gtsrc)
- 功能:在 multicast 狀態改變時要清掉 cache
called by net/ipv4/igmp.c#451 ip_mc_inc_group() #471 ip_mc_dec_group(0
called by net/ipv4/ipmr.c#232 vif_delete() #775 ip_mroute_setsockopt() - 參數:in_device
- 回傳:
- 說明:
- 2230:強制 rt_cache_flush(0);
清掉 routing table cache no delay
- 2230:強制 rt_cache_flush(0);
- 功能:kernel 一開始初始 route table 的初始函數
- 參數:
- 回傳:
- 說明:初始化流程
- 2474:kmem_cache_create() 建立 kernel cache for ip dst cache
- 2482-2497:配置 rt_hash_table 的記憶體
- 2506:rt_hash_table initial
- 2512,2513:初始化 ipv4_dst_ops.gc_thresh ip_rt_max_size
- 2515:devinet_init();
- 2516:ip_fib_init();
- 2517:rt_flush_timer 雖然被宣告,也指定 timer function
但是從未被初始化過,只有在第一次呼叫完了 rt_cache_flush() 後
才會真正被啟動 - 2519-2526:add_timer(&rt_periodic_timer); timer function 為 rt_check_expire
- 2528,2529:proc fs 相關的資訊
- RTCF_DIRECTSRC 不知道幹嘛的 唯一用到的地方 icmp.c icmp_address_reply() if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC)) return;