關於VirtualBox中CentOS7的IP地址的困惑

Windows 10 平臺,安裝了甲骨文的虛擬機軟件VirtualBox 5, 而後在裏面安裝了CentOS 7.linux

內網shell

  • Windows 10系統的IP固定爲192.168.1.2,
  • Virtual Host-Only Network的IPV4地址爲192.168.1.3 (在網絡鏈接界面下設置)
  • VirtualBox實例界面設置->網絡->端口轉發裏面設置的主機地址爲192.168.1.3

不知道 1###

打開CentOS,在終端中輸入如下命令, 查到的IP地址inet不一樣於以上我設置的192.168.1.3, 而是一個會變化的地址, 如10.0.2.15/24.服務器

#ip add

或者用ifconfig也能夠查到inet和ip add獲得的是同樣的10.0.2.15,但就是不一樣於192.168.1.3.網絡

#ifconfig

不知道 2###

用xshell鏈接CentOS時,設置的主機IP地址也是192.168.1.3, 但確實能連上.數據結構

那麼爲何用ip add查看的地址不對呢?架構

看來之後得好好讀讀關於網絡這塊的東西.負載均衡


下面是摘錄別人的解釋:函數

若是你很是理解網絡協議的原理以及網絡的分層架構那麼我想你就不會有這個問題,實際上,每個網卡設備都有一個mac地址,可是卻可 以有多個網絡層地址,好比IP地址,然而這個事實沒法很好地像用戶提供操做接口,因此就引出了ip別名(IP aliases)和輔助ip(secondary IP addresses)的概念。其實很容易理解這個事實,按照分層的思想,下層老是爲上層服務,也就是爲上層提供舞臺,上層利用下層的服務,而沒必要讓下層知 道本身的狀況,若是一個擁有合理mac地址的網卡沒有配置網絡層地址(好比IP地址)這件事合理的話,那麼爲這個設備配置多個IP地址也是合理的,正好像 一個ip能夠對應多個應用層端口同樣,也就是說,下層對上層老是一對多的關係,在分層架構中這種關係是合理的。下面咱們就看一下linux的網卡的ip地 址結構。剛纔說了在linux中,一個網卡能夠有多個IP,那麼這多個ip有什麼關係呢?其實這些ip組成了一個吊鏈結構,所謂吊鏈結構就是一些節點連接 成一條鏈,而後每一個節點帶有本身的一條鏈.佈局

每一個節點表明的ip地址標識一個網段,這個節點的ip就是這個網段的 Primary地址,它下面所帶的ip就是這個網段的Secondary地址,也就是說一個網卡能夠帶有各個節點所帶鏈表長度之和個ip地址,並且這些 ip不是線形的,而是上述的吊鏈結構。咱們看一下這麼作有什麼好處。玩過Cisco路由器的朋友可能都知道有個Secondary IP的概念,這個特性能夠建立邏輯子網,也就是說在一個物理網口上鍊接兩個子網,這咋看起來好像難以想象,其實很簡單,好比這個網口接到一臺交換機上,如 果這個網口沒有配置Secondary IP的話,那麼這臺交換機只能鏈接一個網段的主機,好比192.168.1.1/24,可是,若是它配置了Secondary IP,那麼就能夠鏈接兩個網段的主機,好比192.168.1.1/24和10.0.0.1/24,道理就是這麼簡單,可是卻頗有用,該機制能夠被路由匯 總策略所使用。注意上面這個例子中的Secondary IP不是這裏說的linux的Secondary address,在linux中偏偏相反,只要一個網卡上配置的ip不是一個網段的,那麼都是Primary IP,就是吊鏈結構中上面的那條主鏈中的IP,linux中的Secondary address是主鏈結點的子鏈結點中的IP,這一點必定注意,概念是不能混淆的。前面說的只是吊鏈中主鏈的做用,那麼子鏈呢?其實想象一下也很簡單,比 如一臺機器上運行着一個代理服務器或者負載均衡服務,代理服務器或者負載均衡服務和主服務器要監聽相同的端口,那麼就能夠用secondary address來解決了,只要須要在同一網段監聽同一個端口的應用都是吊鏈中子鏈存在的緣由,所以能夠說,主鏈對外部或者說對下面鏈路層虛擬了多塊網卡, 而子鏈向上層虛擬了多臺機器,配置了吊鏈結構的linux主機若是說只有一塊網卡,那麼外部會認爲它有多塊網卡,對於內部,應用層會認爲彼此在不一樣的主機 上,這就是效果。atom

除了上面大致的介紹以外,還有不少細節,吊鏈在主鏈上是沒有主次的,子鏈除了第一個節點其它節點也不分主次,都是平行的關係,可是子鏈中的第一個節點老是 連接在主鏈中,它們攜帶的地址就是primary地址,它們下面隸屬的子鏈攜帶的地址就是這個primary地址的secondary地址,如此看來,一 旦主鏈上一個節點被刪除了,那麼它的子鏈也將不復存在,所謂皮之不存毛將焉附。可是這種策略老是顯得不是那麼優美,由於父親犯錯,兒子也要受連累,這在現 代社會早就不時行了,那麼就須要改變機制了,所以linux中特地有了一個選項,就是當一個primary地址被刪除時,若是它有secondary地址 的話,那麼它的第一個secondary地址(長子)繼承被刪除的primary地址的位置成爲primary地址,這樣就顯得很合理了,要否則在刪除 primary地址的時候,若是有程序用secondary地址,那麼要麼延遲刪除,要麼程序崩潰,採用自動提高策略的話就不會出現問題。

至於說IP aliases,那是之前版本有的了,就是一個實現問題,解決的問題和如今的secondary IP機制同樣,它主要就是在物理網卡名字後面加上後綴從而成爲虛擬網絡接口,本質上和secondary IP機制沒有區別,區別就是IP aliases顯得不是那麼直觀,而secondary IP倒是真正讓應用看到了一個網卡的多個地址,好比你要是用IP aliases的話,有的時候你老是會問eth0:0是什麼?我就曾經在內核裏面拼命找eth0:0這個網絡設備的註冊代碼,都要瘋掉了也沒有找到,其實 我並非很傻,可是我卻由於那個該死的名字做出了傻事。

下面就能夠看看linux內核的實現代碼了,首先弄明白一些數據結構,最重要的就是net_device,其次就是in_device,而後就是in_ifaddr,明白了這三個數據結構,一切就明白了,這是真的。

struct net_device 
{ 
... 
     void                    *ip_ptr;       //指向一個in_device結構,這字段從net_device中分離代表一個網卡能夠支持多種網絡層協議的 
... 
} 
struct in_device 
{ 
         struct net_device       *dev;           //指向它隸屬的net_device,也就是網卡 
         atomic_t                refcnt;         //引用計數 
         int                     dead; 
         struct in_ifaddr        *ifa_list;      //全部的ip地址鏈表 
... 
}; 
struct in_ifaddr   //表明一個ip地址 
{ 
         struct in_ifaddr        *ifa_next;       //上面的in_device中的ifa_list字段就是靠這個字段連成鏈的 
         struct in_device        *ifa_dev;        //回指in_device結構 
         struct rcu_head         rcu_head; 
         u32                     ifa_local;       //ip地址 
         u32                     ifa_address; 
         u32                     ifa_mask;        //掩碼 
         u32                     ifa_broadcast;   //廣播地址 
         u32                     ifa_anycast; 
         unsigned char           ifa_scope;  
         unsigned char           ifa_flags;           //只有IFA_F_SECONDARY標誌,由於除了這個就是primary地址了 
         unsigned char           ifa_prefixlen; 
         char                    ifa_label[IFNAMSIZ]; //名字,在ip aliases時代,它就多是ethx:y的形式,在secondary ip時代,它統一就是ethx 
};

注 意,上面的結構並無將linux網卡的ip地址結構表示爲吊鏈結構,所謂的吊鏈結構只是邏輯上的,在數據結構上,一個網卡全部的ip地址所有都在 ifa_list中被連接成一個線性的鏈表,至因而primary地址仍是secondary地址就看in_ifaddr的ifa_flags字段了。每 當有新的地址被設置的時候,inet_insert_ifa老是被調用,linux爲什麼沒有在代碼上將ip地址表示爲吊鏈結構呢?我也不知道,我的感受一 個net_device帶有一個primary ip鏈表,而後每一個primary ip節點帶有一個secondary ip鏈表,這樣會更好一些的,我以爲inet_insert_ifa實現的十分拙劣。添加地址能夠經過兩個用戶空間程序搞定,一個是ifconfig,另 一個是ip addr add,ifconfig是基於ioctl進行地址添加的,而ip程序是基於netlink進行地址添加的,無論哪種方式均可以達到目的,如今就能夠看 看另外一個問題了:爲什麼用ip addr add添加的ip地址用ifconfig看不到,而ifconfig設置的地址ip addr show倒是能夠看到。這個問題經過看代碼一眼就能夠明白,在ifconfig得到ip地址的時候,代碼:

for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) 
{ 
    if (!strcmp(ifr.ifr_name, ifa->ifa_label) && sin_orig.sin_addr.s_addr == ifa->ifa_address) 
    { 
        break; 
    } 
}

取 的是這個被找到的ifa的ip地址,而咱們知道,全部的ifa連接成一個線性鏈表,那麼找到了第一個就不會再日後走了,所以只能獲得一個結果,就是鏈表最 前面的那個,而ip add show就不一樣了,具體在函數inet_dump_ifaddr中實現,該函數遍歷全部的ifa,而且傳到用戶空間緩衝區。這裏能夠作一個實驗:首先用 ip addr add添加幾個不在同一個網段的primary ip地址,而後再ifconfig一個和前面的ip都不在一個網段的ip,而後能夠用ifconfig查看一下,發現不是剛剛用ifconfig設置進去 的那個ip,而是用ip addr add添加進去的,這就說明ifconfig永遠都是取的ifa鏈表最前面的那一個,還有一點要注意,就是若是你用ip addr add添加了不少的secondary ip地址,那麼剛好你用ifconfig設置的ip地址和那些secondary ip在一個網段,那麼全部的secondary ip都將被刪除,這些都是sencondary ip的規範決定的,並且在代碼中也有體現。另外還要注意,路由表的表項都是基於primary ip的,由於全部的操做都是以primary ip爲主的,好比在添加路由的時候:

void fib_add_ifaddr(struct in_ifaddr *ifa) 
{ 
         struct in_device *in_dev = ifa->ifa_dev; 
         struct net_device *dev = in_dev->dev; 
         struct in_ifaddr *prim = ifa; 
... 
         if (ifa->ifa_flags&IFA_F_SECONDARY) {   //若是ifa是個sencondary地址,那麼就找到它隸屬的primary地址後而後以這個primary爲主進行設置 
                 prim = inet_ifa_byprefix(in_dev, prefix, mask); 
                 if (prim == NULL) { 
                         printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL/n"); 
                         return; 
                 } 
         } 
         fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);    //添加進路由表 
... 
}

到 此爲止咱們知道了很多東西,最重要的就是linux中網卡ip地址的吊鏈結構以及這麼設計的好處,另外就是設置ip地址的方式有ioctl和 netlink。其實網卡擁有多個ip並不會帶來什麼衝突,本質上ip和網卡沒有什麼關係,它們惟一的關係就是靠網絡分層模型聯繫在一塊兒的,細節上就是靠 路由聯繫在一塊兒的,好比我添加路由的時候指定了一個目的地址和下一跳ip地址以及一個網卡出口,那麼內核會根據提供的目的地址將路由插在合式的位置,而後 將nh的網絡設備設置爲你提供的網卡出口,等到傳輸數據的時候就會查找路由從而找到出口,就是這麼簡單,你本身手動設置的路由能夠隨意設置,即便徹底錯誤 內核也會將之加入路由表的,還有一種路由是內核自動生成的,就是在網卡剛剛up的時候,這時經過網卡的net_device找到其in_device而後 找到其ip地址,這樣的路由稱爲鏈路路由。

經過secondary IP機制,你能夠認爲你的機器有不少網卡,對於應用,監聽同一端口的應用會認爲它們在局域網中不一樣的機器上,你能夠隨意使用這些ip地址而不會發生混亂,路由和底層的arp會處理好這一切,固然前提是你將路由設置對。
附: 用戶空間有ifup/ifdown,/sbin/ip,ifconfig,還有netplugd守護進程,這些有何關係嗎?這中間ip程序是最基本的,沒 有任何策略,策略就是參數指定,要麼就是別的程序調用它,而netplugd就是一個監控守護進程,經過netlink監控網卡狀態,而後根據不一樣的監控 結果調用/etc/netplug.d/netplug腳本,進而可能調用ifup/ifdown腳本,然後者就是腳本,其中會調用ifup-eth腳 本,最終整理好參數後調用ip程序(典型的就是:ip link set eth0 up/down),固然ip程序徹底能夠本身調用,好比ip addr add以及ip route add等等,而ifconfig沒有那麼繞圈子,就是經過ioctl進行設置,能夠經過strace來觀察。這其中奧妙大了去了,說白了就是策略和機制分 離,另外還體現出linux中的不少功能都是很小的程序組合而成的。

Linux的ip地址的吊鏈結構以及ip地址的尋址特性(詳見《關於IP網段間互訪的問題—路由是根本》)充分說明了linux的協議棧實現多麼的完美,徹底符合分層和封裝模型,使得下層的邏輯和上層的邏輯徹底解除耦合,也就是說ip層徹底不依賴鏈路層以及物理層的物理佈局,最後記住,ip層事情好比尋址路由只由ip層實現,之全部有鏈路層發現的路由,徹底是爲了方便。

相關文章
相關標籤/搜索