前些日子在IDC實驗docker的時候,爲了不與公司網絡衝突,將bridge設置爲127.x網段的IP,原覺得這樣就OK,後來發如今訪問container內部的服務的時候沒法訪問。開始覺得iptables的問題,搞了半天,後來,才發現系統對127.x.x.x的包根本不會通過bridge。這兩天補習了一下linux的路由實現,才完全明白其中原因。linux
其實,關於環回接口,TCP/IP詳解中已經描述得很清楚,只是本身沒有去仔細閱讀而已。docker
Linu支持環回接口( Loopback Interface),以容許運行在同一臺主機上的客戶程序和服務器程序通TCP/IP進行通訊。 A 類網絡127就是爲環回接口預留的 。根據慣例,大多數系統把IP地址127.0.0.1分配給這個接口,並命名爲localhost。一個傳給環回接口的IP數據報不能在任何網絡上出現。實際上,訪問127.x.x.x的全部IP都是訪問環回接口(lo)。服務器
按理來講,一旦傳輸層檢測到目的端地址是環回地址時,應該能夠省略部分傳輸層和全部網絡層的邏輯操做。可是大多數的產品仍是照樣完成傳輸層和網絡層的全部過程,只是當 I P 數據報離開網絡層時把它返回給本身。Linux的內核實現就是這樣。網絡
幾個關鍵點:oop
(1)傳給環回地址(通常是127.0.0.1 )的任何數據均做爲IP輸入。url
(2)傳給廣播地址或多播地址的數據報復制一份傳給環回接口,而後送到以太網上。這是由於廣播傳送和多播傳送的定包含主機自己。spa
(3)任何傳給該主機I P地址的數據均送到環回接口 。blog
從上面的描述能夠明白,訪問127.0.0.1和本機IP(好比192.168.1.10)都是經過lo來完成的。接口
考慮以下路由表:ip
儘管咱們爲172.16.213.0/24和129.0.0.0/8指定了出口設備(eth0/docker0),但實際上,數據仍然是經過lo來完成的。
內核默認有兩個路由表(不考慮策略路由):
struct fib_table *ip_fib_local_table;
struct fib_table *ip_fib_main_table;
前者用於本地路由,後均可以由管理員配置。
從上面的能夠看到,172.16.213.129,127.0.0.0/8都被認爲是本機IP。
linux在進行路由查找時,先查找local,再查找main:
static inline int fib_lookup(const struct flowi *flp, struct fib_result *res) { if (ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) && ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res)) return -ENETUNREACH; return 0; } |
實際上,若是內核認爲目標地址是本機IP,就會將包的出口設備設置爲loopback_dev(無論路由表將出口設備設置成什麼)。
static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) { ... if (res.type == RTN_LOCAL) { if (!fl.fl4_src) fl.fl4_src = fl.fl4_dst; if (dev_out) dev_put(dev_out); dev_out = &loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) fib_info_put(res.fi); res.fi = NULL; flags |= RTCF_LOCAL; goto make_route; } |
整個數據流過程:
主要參考
[1]TCP/IP詳解
[2]深刻理解linux網絡技術內幕
做者:YY哥
出處:http://www.cnblogs.com/hustcat/ 本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。