MAC 地址為什么不需要全球唯一
為什么這么設(shè)計(Why’s THE Design)是一系列關(guān)于計算機(jī)領(lǐng)域中程序設(shè)計決策的文章,我們在這個系列的每一篇文章中都會提出一個具體的問題并從不同的角度討論這種設(shè)計的優(yōu)缺點、對具體實現(xiàn)造成的影響。如果你有想要了解的問題,可以在文章下面留言。
MAC 地址(Media access control address)是分配給網(wǎng)絡(luò)接口控制器(Network interface controller, NIC)的唯一標(biāo)識符,它會在網(wǎng)絡(luò)段中充當(dāng)網(wǎng)絡(luò)地址使用[^1],所有具有網(wǎng)卡的主機(jī)都有單獨(dú)的 MAC 地址,該地址總共包含 48 位,占 6 字節(jié)的空間,可以表示 281,474,976,710,656 個網(wǎng)絡(luò)設(shè)備,一個正常的 MAC 地址如下所示的格式表示,每個字節(jié)都會使用兩位 16 進(jìn)制的數(shù)字:
6e:77:0f:b8:8b:6b因為 MAC 地址需要保證唯一,所以 IEEE 會根據(jù)設(shè)備的制造商分配地址段,48 位 MAC 地址的前 24 位是設(shè)備制造商的標(biāo)識符[^2],也就是組織唯一標(biāo)識符(Organizationally Unique Identifier,OUI),后面的 24 位是序列號;如果每個設(shè)備制造商都能保證在同一個命名空間中的全部 MAC 地址唯一,那么全世界所有的 MAC 地址就可以保證唯一。

MAC 地址可以使用兩種不同的格式表示,分別是 48 位的 EUI-48 和 64 位的 EUI-64[^3],本文會使用 EUI-48 格式的 MAC 地址,EUI-64 主要用于 IPv6 協(xié)議,我們在這篇文章就不展開討論了。在通常情況下,MAC 地址會使用 24 位表示組織的序列號,但是因為很多組織不會生產(chǎn)這么多的設(shè)備,所以在實際操作中會劃分出三種不同大小的地址塊[^4]:

MA-L(MAC Address Block Large) - 包含 24 位組織標(biāo)識符和 24 位地址; MA-M(MAC Address Block Medium) - 包含 28 位組織標(biāo)識符和 20 位地址; MA-S(MAC Address Block Small) - 包含 36 位組織標(biāo)識符和 12 位地址;
這三種不同大小的地址塊價格也完全不同,MA-L 的注冊價格為 2995 美金,而 MA-S 的注冊價格為 755 美金,感興趣并且有需要的讀者可以在 IEEE 的官方購買[^5],在理想情況下,所有的地址加起來價值大概在 52 萬億美金左右,果然定義和掌握了標(biāo)準(zhǔn)就可以躺著等別人注冊來賺錢。
這種由機(jī)構(gòu)分發(fā) MAC 地址段并由設(shè)備商保證地址唯一的方式就是為了保證全世界所有硬件的網(wǎng)絡(luò)地址唯一,但是在實際操作中,全球唯一是無法保證的而且我們也并不需要地址的全球唯一,這主要因為以下兩個原因:
在不同操作系統(tǒng)上,我們都可以通過軟件直接修改網(wǎng)卡的 MAC 地址; 只需要保證一個局域網(wǎng)內(nèi)的 MAC 地址不重復(fù),網(wǎng)絡(luò)就可以正常工作;
修改地址
無論是在 Linux 上還是在 macOS 上,修改網(wǎng)絡(luò)設(shè)備的 MAC 地址都是非常簡單的。在 Linux 操作系統(tǒng)中我們可以使用命令 ifconfig 修改設(shè)備上的 MAC 地址:
$ ifconfig eth0 | grep etherether 6e:77:0f:b8:8b:6b txqueuelen 1000 (Ethernet)$ ifconfig eth0 down$ ifconfig eth0 hw ether 6e:77:0f:b8:8b:6a$ ifconfig eth0 up$ ifconfig eth0 | grep etherether 6e:77:0f:b8:8b:6a txqueuelen 1000 (Ethernet)
只要我們使用上述的命令就可以輕松地修改當(dāng)前網(wǎng)卡的 MAC 地址,不過建議不要在遠(yuǎn)程的 Linux 機(jī)器上使用,最好在本地的 Linux 上測試相關(guān)的命令,在修改測試完成之后也最好使用命令將 MAC 地址改回去;在 macOS 上修改 MAC 地址也可以使用 ifconfig 命令,使用的方式與 Linux 幾乎完全相同。
因為 MAC 地址是與硬件綁定的,所以這種修改 MAC 地址的方式其實都是臨時的,一旦操作系統(tǒng)重啟,這些變更就會被系統(tǒng)撤銷,想要讓類似的變更永久生效需要在系統(tǒng)重啟時執(zhí)行相應(yīng)的命令或者修改對應(yīng)的網(wǎng)卡配置文件[^6]。
局域網(wǎng)通信
所有的計算機(jī)和終端設(shè)備都需要通過網(wǎng)絡(luò)適配器連接到局域網(wǎng)中,每一個適配器都有唯一的鏈路層地址,也被叫做 LAN 地址或者 MAC 地址,MAC 地址被設(shè)計成了扁平結(jié)構(gòu),它們不會隨著所處網(wǎng)絡(luò)的不同而發(fā)生改變。
當(dāng)設(shè)備的網(wǎng)絡(luò)適配器想要向其他的適配器發(fā)送數(shù)據(jù)幀時,它會將目的適配器的 MAC 地址插入到如下所示的以太網(wǎng)幀中,每個以太網(wǎng)幀都與 IP 數(shù)據(jù)報類似,包含源地址和目標(biāo)地址,只是以太網(wǎng)幀中的地址是 MAC 地址,而 IP 數(shù)據(jù)報中的地址是 IP 地址:

局域網(wǎng)中的數(shù)據(jù)傳輸不是通過網(wǎng)絡(luò)層的 IP 地址進(jìn)行路由和轉(zhuǎn)發(fā)的,然而 IP 地址一般都是發(fā)送數(shù)據(jù)主機(jī)知道的唯一信息,想要在局域網(wǎng)中發(fā)送數(shù)據(jù),還是需要知道它們的 MAC 地址。當(dāng)我們的設(shè)備想要向其他的設(shè)備發(fā)送數(shù)據(jù)時,它會先通過 ARP(Address Resolution Protocol,地址解析協(xié)議) 在局域網(wǎng)中獲取目的 IP 地址對應(yīng)的 MAC 地址:
源主機(jī)會向當(dāng)前局域網(wǎng)中發(fā)送 ARP 請求,目標(biāo)的 MAC 地址是 FF-FF-FF-FF-FF-FF,這表示當(dāng)前請求是一個廣播請求,局域網(wǎng)內(nèi)的所有設(shè)備都會收到該請求;接收到 ARP 請求的主機(jī)都會檢查目的 IP 和自己的 IP 地址是否一致; 如果 IP 地址不一致,主機(jī)會忽略當(dāng)前的 ARP 請求; 如果 IP 地址一致,主機(jī)會直接向源主機(jī)發(fā)送 ARP 響應(yīng); 源主機(jī)在接收到 ARP 的響應(yīng)之后,會更新本地的緩存表并繼續(xù)向目的主機(jī)發(fā)送數(shù)據(jù);

在局域網(wǎng)中我們一般會使用集線器(Hub)或者交換機(jī)(Switch)來連接不同的網(wǎng)絡(luò)設(shè)備。因為在集線器連接的局域網(wǎng)中,所有的數(shù)據(jù)幀都會被廣播給局域網(wǎng)內(nèi)的全部主機(jī),所以使用相同的 MAC 地址一般也不會出現(xiàn)太多的問題;但是交換機(jī)會學(xué)習(xí)局域網(wǎng)中不同設(shè)備的 MAC 地址并將數(shù)據(jù)幀轉(zhuǎn)發(fā)給特定主機(jī),所以如果局域網(wǎng)是由交換機(jī)構(gòu)成的,就會影響網(wǎng)絡(luò)的通信。

假設(shè)局域網(wǎng)中的具有兩臺 MAC 地址完全相同的網(wǎng)絡(luò)設(shè)備 A 和 B,即 6e:77:0f:b8:8b:6b,當(dāng)設(shè)備 A 想要向設(shè)備 B 發(fā)送以太網(wǎng)幀時會遇到如下所示的情況:
設(shè)備 A 在構(gòu)造的以太網(wǎng)幀中將源地址和目的地址都設(shè)置為 6e:77:0f:b8:8b:6b并向交換機(jī)發(fā)送數(shù)據(jù);交換機(jī)接收到了設(shè)備 A 發(fā)送的數(shù)據(jù)幀后,會從數(shù)據(jù)幀的源地址學(xué)習(xí)到設(shè)備 A 的 MAC 地址并將 6e:77:0f:b8:8b:6b -> A這條記錄插入本地緩存中;交換機(jī)發(fā)現(xiàn)收到數(shù)據(jù)幀的目的地址會指向了網(wǎng)絡(luò)設(shè)備 A,所以它會將該數(shù)據(jù)轉(zhuǎn)發(fā)回 A;
因為交換機(jī)的 MAC 地址學(xué)習(xí)策略,所以我們不能在同一個局域網(wǎng)中使用相同的 MAC 地址,但是因為 MAC 地址是鏈路層網(wǎng)絡(luò)中的概念,跨局域網(wǎng)的網(wǎng)絡(luò)傳輸需要通過網(wǎng)絡(luò)層的 IP 協(xié)議,所以在不同的局域網(wǎng)中使用相同的 MAC 地址就不存在類似的問題了。
總結(jié)
MAC 地址是鏈路層網(wǎng)絡(luò)中的重要概念,在局域網(wǎng)中會通過 MAC 地址轉(zhuǎn)發(fā)以太網(wǎng)數(shù)據(jù)幀,全球唯一的 MAC 地址是非常理想的情況,然而在實際的網(wǎng)絡(luò)場景中,我們不需要保證如此強(qiáng)的限制:
MAC 地址可以通過軟件進(jìn)行修改,而第三方的山寨廠商不會在 IEEE 中申請獨(dú)立的 MAC 地址段,它們也可能會盜用其他廠商申請的 MAC 地址; 保證 MAC 地址在局域網(wǎng)中唯一就不會造成網(wǎng)絡(luò)問題,不同局域網(wǎng)中的 MAC 地址可以相同;
上述的結(jié)論不是說全球唯一的 MAC 地址沒有意義,與此相反,我們應(yīng)該盡可能保證 MAC 地址的唯一,這樣在組建局域網(wǎng)時才不需要手動確認(rèn)所有設(shè)備的 MAC 地址,減少網(wǎng)絡(luò)工程師的工作量。到最后,我們還是來看一些比較開放的相關(guān)問題,有興趣的讀者可以仔細(xì)思考一下下面的問題:
MAC 地址和 IP 地址之間有什么樣的關(guān)系? 為什么我們有了 MAC 地址還需要 IP 地址?
如果對文章中的內(nèi)容有疑問或者想要了解更多軟件工程上一些設(shè)計決策背后的原因,可以在博客下面留言,作者會及時回復(fù)本文相關(guān)的疑問并選擇其中合適的主題作為后續(xù)的內(nèi)容。
推薦閱讀
站長 polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場和創(chuàng)業(yè)經(jīng)驗
Go語言中文網(wǎng)
每天為你
分享 Go 知識
Go愛好者值得關(guān)注
