亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

從ip addr add和ifconfig的區(qū)別看linux網(wǎng)卡ip地

系統(tǒng) 2142 0

今天一個老外在郵件列表上問了一個問題,就是ip addr add和ifconfig的區(qū)別,我給他進行了解答,可能因為英語不好吧,解答的很簡單,因此我還是要在這里詳細說明一下。其實它們之間沒有什么區(qū)別,只 是表述方式不同罷了。如果你非常理解網(wǎng)絡(luò)協(xié)議的原理以及網(wǎng)絡(luò)的分層架構(gòu)那么我想你就不會有這個問題,實際上,每一個網(wǎng)卡設(shè)備都有一個mac地址,但是卻可 以有多個網(wǎng)絡(luò)層地址,比如IP地址,然而這個事實無法很好地像用戶提供操作接口,所以就引出了ip別名(IP aliases)和輔助ip(secondary IP addresses)的概念。其實很容易理解這個事實,按照分層的思想,下層總是為上層服務(wù),也就是為上層提供舞臺,上層利用下層的服務(wù),而不必讓下層知 道自己的情況,如果一個擁有合理mac地址的網(wǎng)卡沒有配置網(wǎng)絡(luò)層地址(比如IP地址)這件事合理的話,那么為這個設(shè)備配置多個IP地址也是合理的,正好像 一個ip可以對應(yīng)多個應(yīng)用層端口一樣,也就是說,下層對上層總是一對多的關(guān)系,在分層架構(gòu)中這種關(guān)系是合理的。下面我們就看一下linux的網(wǎng)卡的ip地 址結(jié)構(gòu)。剛才說了在linux中,一個網(wǎng)卡可以有多個IP,那么這多個ip有什么關(guān)系呢?其實這些ip組成了一個吊鏈結(jié)構(gòu),所謂吊鏈結(jié)構(gòu)就是一些節(jié)點鏈接 成一條鏈,然后每個節(jié)點帶有自己的一條鏈,如下圖所示:
clip_image001 clip_image002 clip_image003 clip_image004
每個節(jié)點代表的ip地址標(biāo)識一個網(wǎng)段,這個節(jié)點的ip就是這個網(wǎng)段的 Primary地址,它下面所帶的ip就是這個網(wǎng)段的Secondary地址,也就是說一個網(wǎng)卡可以帶有各個節(jié)點所帶鏈表長度之和個ip地址,而且這些 ip不是線形的,而是上述的吊鏈結(jié)構(gòu)。我們看一下這么做有什么好處。玩過Cisco路由器的朋友可能都知道有個Secondary IP的概念,這個特性可以創(chuàng)建邏輯子網(wǎng),也就是說在一個物理網(wǎng)口上連接兩個子網(wǎng),這咋看起來好像不可思議,其實很簡單,比如這個網(wǎng)口接到一臺交換機上,如 果這個網(wǎng)口沒有配置Secondary IP的話,那么這臺交換機只能連接一個網(wǎng)段的主機,比如192.168.1.1/24,但是,如果它配置了Secondary IP,那么就可以連接兩個網(wǎng)段的主機,比如192.168.1.1/24和10.0.0.1/24,道理就是這么簡單,但是卻很有用,該機制可以被路由匯 總策略所使用。注意上面這個例子中的Secondary IP不是這里說的linux的Secondary address,在linux中恰恰相反,只要一個網(wǎng)卡上配置的ip不是一個網(wǎng)段的,那么都是Primary IP,就是吊鏈結(jié)構(gòu)中上面的那條主鏈中的IP,linux中的Secondary address是主鏈結(jié)點的子鏈結(jié)點中的IP,這一點一定注意,概念是不能混淆的。前面說的只是吊鏈中主鏈的作用,那么子鏈呢?其實想象一下也很簡單,比 如一臺機器上運行著一個代理服務(wù)器或者負載均衡服務(wù),代理服務(wù)器或者負載均衡服務(wù)和主服務(wù)器要監(jiān)聽相同的端口,那么就可以用secondary address來解決了,只要需要在同一網(wǎng)段監(jiān)聽同一個端口的應(yīng)用都是吊鏈中子鏈存在的原因,因此可以說,主鏈對外部或者說對下面鏈路層虛擬了多塊網(wǎng)卡, 而子鏈向上層虛擬了多臺機器,配置了吊鏈結(jié)構(gòu)的linux主機如果說只有一塊網(wǎng)卡,那么外部會認為它有多塊網(wǎng)卡,對于內(nèi)部,應(yīng)用層會認為彼此在不同的主機 上,這就是效果。
除了上面大體的介紹之外,還有很多細節(jié),吊鏈在主鏈上是沒有主次的,子鏈除了第一個節(jié)點其它節(jié)點也不分主次,都是平行的關(guān)系,但是子鏈中的第一個節(jié)點總是 鏈接在主鏈中,它們攜帶的地址就是primary地址,它們下面隸屬的子鏈攜帶的地址就是這個primary地址的secondary地址,如此看來,一 旦主鏈上一個節(jié)點被刪除了,那么它的子鏈也將不復(fù)存在,所謂皮之不存毛將焉附。但是這種策略總是顯得不是那么優(yōu)美,因為父親犯錯,兒子也要受連累,這在現(xiàn) 代社會早就不時行了,那么就需要改變機制了,因此linux中特意有了一個選項,就是當(dāng)一個primary地址被刪除時,如果它有secondary地址 的話,那么它的第一個secondary地址(長子)繼承被刪除的primary地址的位置成為primary地址,這樣就顯得很合理了,要不然在刪除 primary地址的時候,如果有程序用secondary地址,那么要么延遲刪除,要么程序崩潰,采用自動提升策略的話就不會出現(xiàn)問題。
至于說IP aliases,那是以前版本有的了,就是一個實現(xiàn)問題,解決的問題和現(xiàn)在的secondary IP機制一樣,它主要就是在物理網(wǎng)卡名字后面加上后綴從而成為虛擬網(wǎng)絡(luò)接口,本質(zhì)上和secondary IP機制沒有區(qū)別,區(qū)別就是IP aliases顯得不是那么直觀,而secondary IP卻是真正讓應(yīng)用看到了一個網(wǎng)卡的多個地址,比如你要是用IP aliases的話,有的時候你總是會問eth0:0是什么?我就曾經(jīng)在內(nèi)核里面拼命找eth0:0這個網(wǎng)絡(luò)設(shè)備的注冊代碼,都要瘋掉了也沒有找到,其實 我并不是很傻,但是我卻因為那個該死的名字作出了傻事。
下面就可以看看linux內(nèi)核的實現(xiàn)代碼了,首先弄明白一些數(shù)據(jù)結(jié)構(gòu),最重要的就是net_device,其次就是in_device,然后就是in_ifaddr,明白了這三個數(shù)據(jù)結(jié)構(gòu),一切就明白了,這是真的。
struct net_device
{
...
void *ip_ptr; //指向一個in_device結(jié)構(gòu),這個字段從net_device中分離表明一個網(wǎng)卡可以支持多種網(wǎng)絡(luò)層協(xié)議的
...
}
struct in_device
{
struct net_device *dev; //指向它隸屬的net_device,也就是網(wǎng)卡
atomic_t refcnt; //引用計數(shù)
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結(jié)構(gòu)
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標(biāo)志,因為除了這個就是primary地址了
unsigned char ifa_prefixlen;
char ifa_label[IFNAMSIZ]; //名字,在ip aliases時代,它就可能是ethx:y的形式,在secondary ip時代,它統(tǒng)一就是ethx
};
注 意,上面的結(jié)構(gòu)并沒有將linux網(wǎng)卡的ip地址結(jié)構(gòu)表示為吊鏈結(jié)構(gòu),所謂的吊鏈結(jié)構(gòu)只是邏輯上的,在數(shù)據(jù)結(jié)構(gòu)上,一個網(wǎng)卡所有的ip地址全部都在 ifa_list中被鏈接成一個線性的鏈表,至于是primary地址還是secondary地址就看in_ifaddr的ifa_flags字段了。每 當(dāng)有新的地址被設(shè)置的時候,inet_insert_ifa總是被調(diào)用,linux為何沒有在代碼上將ip地址表示為吊鏈結(jié)構(gòu)呢?我也不知道,個人感覺一 個net_device帶有一個primary ip鏈表,然后每個primary ip節(jié)點帶有一個secondary ip鏈表,這樣會更好一些的,我覺得inet_insert_ifa實現(xiàn)的十分拙劣。添加地址可以通過兩個用戶空間程序搞定,一個是ifconfig,另 一個是ip addr add,ifconfig是基于ioctl進行地址添加的,而ip程序是基于netlink進行地址添加的,不管哪一種方式都可以達到目的,現(xiàn)在就可以看 看另一個問題了:為何用ip addr add添加的ip地址用ifconfig看不到,而ifconfig設(shè)置的地址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鏈接成一個線性鏈表,那么找到了第一個就不會再往后走了,因此只能得到一個結(jié)果,就是鏈表最 前面的那個,而ip add show就不同了,具體在函數(shù)inet_dump_ifaddr中實現(xiàn),該函數(shù)遍歷所有的ifa,并且傳到用戶空間緩沖區(qū)。這里可以做一個實驗:首先用 ip addr add添加幾個不在同一個網(wǎng)段的primary ip地址,然后再ifconfig一個和前面的ip都不在一個網(wǎng)段的ip,然后可以用ifconfig查看一下,發(fā)現(xiàn)不是剛剛用ifconfig設(shè)置進去 的那個ip,而是用ip addr add添加進去的,這就說明ifconfig永遠都是取的ifa鏈表最前面的那一個,還有一點要注意,就是如果你用ip addr add添加了很多的secondary ip地址,那么恰好你用ifconfig設(shè)置的ip地址和那些secondary ip在一個網(wǎng)段,那么所有的secondary ip都將被刪除,這些都是sencondary ip的規(guī)范決定的,而且在代碼中也有體現(xiàn)。另外還要注意,路由表的表項都是基于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為主進行設(shè)置
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中網(wǎng)卡ip地址的吊鏈結(jié)構(gòu)以及這么設(shè)計的好處,另外就是設(shè)置ip地址的方式有ioctl和 netlink。其實網(wǎng)卡擁有多個ip并不會帶來什么沖突,本質(zhì)上ip和網(wǎng)卡沒有什么關(guān)系,它們唯一的關(guān)系就是靠網(wǎng)絡(luò)分層模型聯(lián)系在一起的,細節(jié)上就是靠 路由聯(lián)系在一起的,比如我添加路由的時候指定了一個目的地址和下一跳ip地址以及一個網(wǎng)卡出口,那么內(nèi)核會根據(jù)提供的目的地址將路由插在合式的位置,然后 將nh的網(wǎng)絡(luò)設(shè)備設(shè)置為你提供的網(wǎng)卡出口,等到傳輸數(shù)據(jù)的時候就會查找路由從而找到出口,就是這么簡單,你自己手動設(shè)置的路由可以隨意設(shè)置,即使完全錯誤 內(nèi)核也會將之加入路由表的,還有一種路由是內(nèi)核自動生成的,就是在網(wǎng)卡剛剛up的時候,這時通過網(wǎng)卡的net_device找到其in_device然后 找到其ip地址,這樣的路由稱為鏈路路由。
通過secondary IP機制,你可以認為你的機器有很多網(wǎng)卡,對于應(yīng)用,監(jiān)聽同一端口的應(yīng)用會認為它們在局域網(wǎng)中不同的機器上,你可以隨意使用這些ip地址而不會發(fā)生混亂,路由和底層的arp會處理好這一切,當(dāng)然前提是你將路由設(shè)置對。
附: 用戶空間有ifup/ifdown,/sbin/ip,ifconfig,還有netplugd守護進程,這些有何關(guān)系嗎?這中間ip程序是最基本的,沒 有任何策略,策略就是參數(shù)指定,要么就是別的程序調(diào)用它,而netplugd就是一個監(jiān)控守護進程,通過netlink監(jiān)控網(wǎng)卡狀態(tài),然后根據(jù)不同的監(jiān)控 結(jié)果調(diào)用/etc/netplug.d/netplug腳本,進而可能調(diào)用ifup/ifdown腳本,而后者就是腳本,其中會調(diào)用ifup-eth腳 本,最終整理好參數(shù)后調(diào)用ip程序(典型的就是:ip link set eth0 up/down),當(dāng)然ip程序完全可以自己調(diào)用,比如ip addr add以及ip route add等等,而ifconfig沒有那么繞圈子,就是通過ioctl進行設(shè)置,可以通過strace來觀察。這其中奧妙大了去了,說白了就是策略和機制分 離,另外還體現(xiàn)出linux中的很多功能都是很小的程序組合而成的。

Linux的ip地址的吊鏈結(jié)構(gòu)以及ip地址的尋址特性(詳見《關(guān)于IP網(wǎng)段間互訪的問題—路由是根本》)充分說明了linux的協(xié)議棧實現(xiàn)多么的完美,完全符合分層和封裝模型,使得下層的邏輯和上層的邏輯完全解除耦合,也就是說ip層完全不依賴鏈路層以及物理層的物理布局,最后記住,ip層事情比如尋址路由只由ip層實現(xiàn),之所有有鏈路層發(fā)現(xiàn)的路由,完全是為了方便。

從ip addr add和ifconfig的區(qū)別看linux網(wǎng)卡ip地址的結(jié)構(gòu)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 奇米影音第四色 | 国产精品国产三级国产无毒 | 久久精品国产亚洲aa | 特黄aa级毛片免费视频播放 | 国产欧美日韩精品第三区 | 成人网18免费视频 | 天天爱天天做天天爽天天躁 | 精品国产三级 | 国产精品u任我爽爆在线播放 | 狠色狠色狠狠色综合久久 | 99久久亚洲国产高清观看 | 高清国产性色视频在线 | 91手机在线观看 | 日本不卡高清中文字幕免费 | 日韩成人小视频 | 不卡午夜视频 | 一级毛片免费视频网站 | 手机国产日韩高清免费看片 | 国产一级视频 | 久久午夜青青草原影院 | 亚洲第一二三四区 | 91aaa免费观看在线观看资源 | 国产香蕉98碰碰久久人人 | 中文字幕专区高清在线观看 | 久久中文网中文字幕 | 久久久99视频 | 日韩中文精品亚洲第三区 | 色狠狠一区二区三区香蕉蜜桃 | 手机国产日韩高清免费看片 | 伊人久久大香 | 日本一区二区网站 | 免费欧美一级 | 亚洲精品亚洲人成在线 | 性欧美videos高清喷水 | 激情网婷婷 | 四虎影视国产永久免费 | 福利免费在线 | 国产欧美日韩精品高清二区综合区 | 色老头福影院韩国激情影院 | 夜夜操免费视频 | 中文字幕在线精品视频入口一区 |