一、概述
二層交換機(jī)的主要功能就是在端口之間搬移分組,當(dāng)然是要根據(jù)正確的目標(biāo)地址來(lái)搬移,涉及到以太網(wǎng)幀格式的解析、源和目的MAC地址的提取,MAC表的設(shè)計(jì)、查找和老化等等一系列的系統(tǒng)功能實(shí)現(xiàn)。我們開始設(shè)計(jì)交換機(jī)并不考慮那么多,從簡(jiǎn)單入手,輕裝上陣,你也許會(huì)走得更好。
二、基于端口號(hào)的交換與驗(yàn)證
上一篇文章我們學(xué)會(huì)了打印分組的基本信息和將分組發(fā)送到指定端口輸出。今天我們就可以來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的交換功能,完成兩臺(tái)主機(jī)之間的正常通信了。
1)端口交換
顧名思義,就是只識(shí)別判斷端口號(hào)就將分組進(jìn)行交換轉(zhuǎn)發(fā),先實(shí)現(xiàn)一個(gè)基于端口的交換功能。固定邏輯只能實(shí)現(xiàn)固定的兩個(gè)端口交換,我們可以將要交換的兩個(gè)端口從程序啟動(dòng)時(shí)作為參數(shù)輸入,這樣就可以在啟動(dòng)命令時(shí)按需要指定要交換的兩個(gè)端口參數(shù)了。
增加兩個(gè)端口變量的全局定義,并在main函數(shù)的參數(shù)輸入中獲取輸入的值,如:
/*端口交換要使用的兩個(gè)全局端口號(hào)變量*/
int port1 = 0,port2 = 0;
/*main函數(shù)中添加如下代碼*/
else if(argc == 5)
{
debug = atoi(argv[1]);
mid = atoi(argv[2]);
port1 = atoi(argv[3]);
port2 = atoi(argv[4]);
}
/*callback函數(shù)中添加如下代碼*/
if(pkt->um.inport == port1)
pkt->um.outport = port2;
else
pkt->um.outport = port1;
2)驗(yàn)證
編譯代碼并執(zhí)行生成文件命令,觀察打印消息。
root@HNXS:/home/hnxs/l2switch# make
gcc -o ul2switch main_ul2switch.c -lua -lreg -lpthread
root@HNXS:/home/hnxs/l2switch# ./ul2switch 1 130 0 2
fastU->REG Version:20180827,OpenBox HW Version:2020210329
fastU->Register UA to FAST Kernel! Wait Reply......
fastU->UA->pid:2132,mid:130,Register OK!
fastU->libua version:20180827
fastU->fast_ua_recv......
inport:2,dstmid:130,len:92,dmac:FF:FF:FF:FF:FF:FF,smac:B8:27:EB:C1:D1:39
pkt_send_normal->0xb5500470,outport:0,len:92
inport:0,dstmid:130,len:92,dmac:B8:27:EB:C1:D1:39,smac:B8:27:EB:D8:83:20
pkt_send_normal->0xb5500470,outport:2,len:92
inport:2,dstmid:130,len:130,dmac:B8:27:EB:D8:83:20,smac:B8:27:EB:C1:D1:39
pkt_send_normal->0xb5500470,outport:0,len:130
inport:2,dstmid:130,len:130,dmac:B8:27:EB:D8:83:20,smac:B8:27:EB:C1:D1:39
pkt_send_normal->0xb5500470,outport:0,len:130
同時(shí),在一個(gè)測(cè)試主機(jī)上ping另一臺(tái)測(cè)試主機(jī)的IP,發(fā)現(xiàn)已經(jīng)ping通了。
64 bytes from 192.168.2.117: icmp_seq=10 ttl=64 time=2.02 ms
64 bytes from 192.168.2.117: icmp_seq=11 ttl=64 time=0.742 ms
64 bytes from 192.168.2.117: icmp_seq=12 ttl=64 time=0.597 ms
3)思考
從上述交換打印分析,前兩個(gè)報(bào)文應(yīng)該是ARP分組,32字節(jié)metadata加60字節(jié)以太幀數(shù)據(jù)。第1個(gè)是廣播請(qǐng)求,第2個(gè)是單播應(yīng)答。第3和第4個(gè)報(bào)文就是第1組ping的交互數(shù)據(jù)了,標(biāo)準(zhǔn)ping的98字節(jié)(130-32=98)。
先不往大了說(shuō),至少我們前面添加了幾行代碼就實(shí)現(xiàn)了我們的一個(gè)最基本的原型交換了,如果要換端口測(cè)試,只需要在啟動(dòng)命令時(shí)更改相應(yīng)的端口號(hào)參數(shù)就行了。那交換機(jī)端口多了,用戶多了之后呢?我們豈不是要不斷回來(lái)的啟動(dòng)程序和設(shè)置端口來(lái)保證他們通信呢?這是不是跟解放前的電話接線員工作有點(diǎn)類似?接線員接到電話后,先要詢問(wèn)打電話的人要打給誰(shuí),然后再把線給連過(guò)去。當(dāng)然,原來(lái)的電話通信與分組交換還是有些較大區(qū)別,只是類比一下,不擴(kuò)展細(xì)說(shuō)。
三、基于MAC地址交換與驗(yàn)證
在分組交換的頭部攜帶有該分組要去往的目的地址,我們管他叫目的MAC地址。在以太網(wǎng)網(wǎng)絡(luò)中,任意一個(gè)通信終端都必須具備一個(gè)唯一的MAC地址,用作通信內(nèi)容標(biāo)識(shí)。在基于端口交換的基礎(chǔ)上,我們也可以很容易的實(shí)現(xiàn)一個(gè)基于MAC地址的簡(jiǎn)單交換功能。至于為什么選目的MAC作為交換判斷參數(shù),大家細(xì)想肯定能明白。
1)MAC交換
根據(jù)以太網(wǎng)幀格式定義,從分組頭部位置提取目的MAC作為判斷參數(shù),實(shí)現(xiàn)一個(gè)基于MAC地址的交換功能。既然要根據(jù)目的MAC地址來(lái)做轉(zhuǎn)發(fā),我們需要知道哪一個(gè)MAC地址的主機(jī)連接在交換機(jī)的哪一個(gè)端口上面,假設(shè)我們已經(jīng)獲取了這些信息如下:
主機(jī)MAC地址:B8:27:EB:D8:83:20,交換機(jī)端口:0
主機(jī)MAC地址:B8:27:EB:C1:D1:39,交換機(jī)端口:2
替換原來(lái)端口交換的邏輯代碼,替換代碼如下:
/*新增兩個(gè)MAC的內(nèi)存格式定義,與S4平臺(tái)(ARM)相關(guān)哦*/
u64 mac1 = 0x2083D8EB27B8,mac2 = 0x39D1C1EB27B8;
/*注釋原來(lái)端口轉(zhuǎn)發(fā)邏輯,添加MAC轉(zhuǎn)發(fā)邏輯*/
if(!ether_addr_equal(pkt->data,(u8 *)&mac1))
pkt->um.outport = 0;
else if(!ether_addr_equal(pkt->data,(u8 *)&mac2))
pkt->um.outport = 2;
ether_addr_equal函數(shù)是判斷兩個(gè)MAC地址是否相等,詳情參閱代碼。
兩個(gè)MAC地址的定義準(zhǔn)確來(lái)說(shuō)要根據(jù)MAC的順序方式表示后再做網(wǎng)絡(luò)序轉(zhuǎn)換,為簡(jiǎn)化邏輯和方便驗(yàn)證,直接定義成了小端平臺(tái)下反序方式,這樣正好跟網(wǎng)絡(luò)序的MAC地址對(duì)比相等。關(guān)于平臺(tái)數(shù)據(jù)的大小端的問(wèn)題或主機(jī)序與網(wǎng)絡(luò)序問(wèn)題,請(qǐng)網(wǎng)上搜索學(xué)習(xí)。
2)驗(yàn)證
編譯代碼并執(zhí)行生成文件命令,觀察打印消息。
root@HNXS:/home/hnxs/l2switch# make
gcc -o ul2switch main_ul2switch.c -lua -lreg -lpthread
root@HNXS:/home/hnxs/l2switch# ./ul2switch
fastU->REG Version:20180827,OpenBox HW Version:2020210329
fastU->Register UA to FAST Kernel! Wait Reply......
fastU->UA->pid:2255,mid:129,Register OK!
fastU->libua version:20180827
fastU->fast_ua_recv......
inport:0,dstmid:129,len:92,dmac:FF:FF:FF:FF:FF:FF,smac:B8:27:EB:D8:83:20
pkt_send_normal->0xb5400470,outport:0,len:92
inport:0,dstmid:129,len:92,dmac:FF:FF:FF:FF:FF:FF,smac:B8:27:EB:D8:83:20
pkt_send_normal->0xb5400470,outport:0,len:92
inport:0,dstmid:129,len:92,dmac:FF:FF:FF:FF:FF:FF,smac:B8:27:EB:D8:83:20
pkt_send_normal->0xb5400470,outport:0,len:92
同時(shí),在2端口測(cè)試主機(jī)上ping另一臺(tái)測(cè)試主機(jī)的IP,發(fā)現(xiàn)ping不通哦。這是因?yàn)槲覀儸F(xiàn)在的邏輯沒(méi)有考慮ARP廣播MAC地址的處理邏輯,導(dǎo)致其無(wú)法正常轉(zhuǎn)發(fā)。本節(jié)暫不處理廣播的泛洪轉(zhuǎn)發(fā)功能,后續(xù)文章中與組播一起討論。
那如何讓兩邊主機(jī)不發(fā)ARP廣播直接發(fā)ping的分組呢?了解網(wǎng)絡(luò)通信原理的人都知道,這個(gè)廣播是在ping之前發(fā)出的MAC地址學(xué)習(xí)分組,如果沒(méi)有學(xué)習(xí)到對(duì)端的MAC地址,則ping的分組無(wú)法完成二層協(xié)議的封裝,無(wú)法從協(xié)議棧發(fā)出。使用如下命令分別在兩臺(tái)主機(jī)上進(jìn)行對(duì)端IP與對(duì)端MAC的靜態(tài)綁定設(shè)置,ping的分組便能正常發(fā)出了。
/*192.168.2.115主機(jī)執(zhí)行*/
#arp –s 192.168.2.117 b8:27:eb:d8:83:20
/*192.168.2.117主機(jī)執(zhí)行*/
#arp –s 192.168.2.115 b8:27:eb:c1:d1:39
現(xiàn)在,在任意一臺(tái)主機(jī)上執(zhí)行ping均能可以看到ping通了。
3)思考
我們現(xiàn)在終于可以根據(jù)主機(jī)的MAC地址來(lái)進(jìn)行分組交換轉(zhuǎn)發(fā)了,但這只是兩臺(tái)主機(jī)的固定交換轉(zhuǎn)發(fā),如果機(jī)器MAC多了怎么辦?如果機(jī)器連接交換機(jī)的端口變了怎么辦?我們需要有一張記錄表,能夠記錄哪個(gè)MAC地址在哪個(gè)端口就好了,通過(guò)每個(gè)分組的目的MAC來(lái)查找其對(duì)應(yīng)的輸出端口,這樣就很容易實(shí)現(xiàn)分組交換了。
四、總結(jié)與下一步
1)交換過(guò)程的核心數(shù)據(jù)字段
從上述實(shí)驗(yàn)可以看出,目前交換里面用到的就兩個(gè)字段,一個(gè)是端口號(hào),另一個(gè)是MAC地址。那目的MAC地址與輸出端口號(hào)從哪獲得?其實(shí)就是從分組頭的源MAC地址和輸入端口轉(zhuǎn)換變成目的MAC和輸出端口。故在交換過(guò)程中,其核心數(shù)據(jù)就2個(gè):端口號(hào)和MAC地址。
2)MAC轉(zhuǎn)發(fā)表設(shè)計(jì)與驗(yàn)證
MAC轉(zhuǎn)發(fā)表就是我們前面提到的記錄表,這張表記錄了一個(gè)MAC地址與其對(duì)應(yīng)端口號(hào)的綁定關(guān)系,這一關(guān)系要從輸入分組數(shù)據(jù)中提取而來(lái),由分組的輸入端口與源MAC地址組成這一綁定關(guān)系,在查表中便可通過(guò)目的MAC來(lái)獲取其正確的輸出端口了。下一篇文章我們聊一下MAC轉(zhuǎn)發(fā)表的設(shè)計(jì)。
五、結(jié)語(yǔ)
歡迎您和學(xué)生們加入FAST開源項(xiàng)目群溝通與探討,一起體驗(yàn)不一樣的系統(tǒng)設(shè)計(jì)過(guò)程。請(qǐng)先加微信號(hào)15116127200后邀請(qǐng)入群。
關(guān)注FAST開源社區(qū)
FAST一一開源、開放、高速、高效、可編程、可定義!軟硬件協(xié)同并行處理。