0731-84728105
15116127200
二層交換機(jī)原型設計與實現(三)
發布時間:2021-05-10
     二層交換機(jī)的(de)主要功能就是在端口之間搬移分組,當然是要根據正确的(de)目标地(dì)址來搬移,涉及到以太網幀格式的(de)解析、源和(hé)目的(de)MAC地(dì)址的(de)提取,MAC表的(de)設計、查找和(hé)老化等等一(yī)系列的(de)系統功能實現。我們開始設計交換機(jī)并不考慮那麽多,從簡單入手,輕裝上陣,你也許會走得更好。
     上一(yī)篇文章(zhāng)我們學(xué)會了打印分組的(de)基本信息和(hé)将分組發送到指定端口輸出。今天我們就可(kě)以來實現一(yī)個簡單的(de)交換功能,完成兩台主機(jī)之間的(de)正常通信了。
     1)端口交換
     顧名思義,就是隻識别判斷端口号就将分組進行(xíng)交換轉發,先實現一(yī)個基于端口的(de)交換功能。固定邏輯隻能實現固定的(de)兩個端口交換,我們可(kě)以将要交換的(de)兩個端口從程序啓動時作為(wèi)參數輸入,這樣就可(kě)以在啓動命令時按需要指定要交換的(de)兩個端口參數了。
     增加兩個端口變量的(de)全局定義,并在main函數的(de)參數輸入中獲取輸入的(de)值,如(rú):

/*端口交換要使用的(de)兩個全局端口号變量*/
int port1 = 0,port2 = 0;

/*main函數中添加如(rú)下代碼*/
else if(argc == 5)
{
debug = atoi(argv[1]);
mid = atoi(argv[2]);
port1 = atoi(argv[3]);
port2 = atoi(argv[4]);
}

/*callback函數中添加如(rú)下代碼*/
if(pkt->um.inport == port1)
pkt->um.outport = port2;
else
pkt->um.outport = port1;

      2)驗證
     編譯代碼并執行(xíng)生成文件命令,觀察打印消息。

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

     同時,在一(yī)個測試主機(jī)上ping另一(yī)台測試主機(jī)的(de)IP,發現已經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)思考
     從上述交換打印分析,前兩個報文應該是ARP分組,32字節metadata加60字節以太幀數據。第1個是廣播請求,第2個是單播應答。第3和(hé)第4個報文就是第1組ping的(de)交互數據了,标準ping的(de)98字節(130-32=98)。
     先不往大了說,至少我們前面添加了幾行(xíng)代碼就實現了我們的(de)一(yī)個最基本的(de)原型交換了,如(rú)果要換端口測試,隻需要在啓動命令時更改相應的(de)端口号參數就行(xíng)了。那交換機(jī)端口多了,用戶多了之後呢(ne)?我們豈不是要不斷回來的(de)啓動程序和(hé)設置端口來保證他們通信呢(ne)?這是不是跟解放前的(de)電話接線員工作有(yǒu)點類似?接線員接到電話後,先要詢問打電話的(de)人要打給誰,然後再把線給連過去(qù)。當然,原來的(de)電話通信與分組交換還是有(yǒu)些較大區别,隻是類比一(yī)下,不擴展細說。
      在分組交換的(de)頭部攜帶有(yǒu)該分組要去(qù)往的(de)目的(de)地(dì)址,我們管他叫目的(de)MAC地(dì)址。在以太網網絡中,任意一(yī)個通信終端都必須具備一(yī)個唯一(yī)的(de)MAC地(dì)址,用作通信內(nèi)容标識。在基于端口交換的(de)基礎上,我們也可(kě)以很容易的(de)實現一(yī)個基于MAC地(dì)址的(de)簡單交換功能。至于為(wèi)什麽選目的(de)MAC作為(wèi)交換判斷參數,大家細想肯定能明白。
      1)MAC交換
     根據以太網幀格式定義,從分組頭部位置提取目的(de)MAC作為(wèi)判斷參數,實現一(yī)個基于MAC地(dì)址的(de)交換功能。既然要根據目的(de)MAC地(dì)址來做(zuò)轉發,我們需要知道(dào)哪一(yī)個MAC地(dì)址的(de)主機(jī)連接在交換機(jī)的(de)哪一(yī)個端口上面,假設我們已經獲取了這些信息如(rú)下:

主機(jī)MAC地(dì)址:B8:27:EB:D8:83:20,交換機(jī)端口:0
主機(jī)MAC地(dì)址:B8:27:EB:C1:D1:39,交換機(jī)端口:2

替換原來端口交換的(de)邏輯代碼,替換代碼如(rú)下:

/*新增兩個MAC的(de)內(nèi)存格式定義,與S4平台(ARM)相關哦*/
u64 mac1 = 0x2083D8EB27B8,mac2 = 0x39D1C1EB27B8;

/*注釋原來端口轉發邏輯,添加MAC轉發邏輯*/
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函數是判斷兩個MAC地(dì)址是否相等,詳情參閱代碼。
     兩個MAC地(dì)址的(de)定義準确來說要根據MAC的(de)順序方式表示後再做(zuò)網絡序轉換,為(wèi)簡化邏輯和(hé)方便驗證,直接定義成了小端平台下反序方式,這樣正好跟網絡序的(de)MAC地(dì)址對比相等。關于平台數據的(de)大小端的(de)問題或主機(jī)序與網絡序問題,請網上搜索學(xué)習。
     2)驗證
編譯代碼并執行(xíng)生成文件命令,觀察打印消息。

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

     同時,在2端口測試主機(jī)上ping另一(yī)台測試主機(jī)的(de)IP,發現ping不通哦。這是因為(wèi)我們現在的(de)邏輯沒有(yǒu)考慮ARP廣播MAC地(dì)址的(de)處理(lǐ)邏輯,導緻其無法正常轉發。本節暫不處理(lǐ)廣播的(de)泛洪轉發功能,後續文章(zhāng)中與組播一(yī)起讨論。
     那如(rú)何讓兩邊主機(jī)不發ARP廣播直接發ping的(de)分組呢(ne)?了解網絡通信原理(lǐ)的(de)人都知道(dào),這個廣播是在ping之前發出的(de)MAC地(dì)址學(xué)習分組,如(rú)果沒有(yǒu)學(xué)習到對端的(de)MAC地(dì)址,則ping的(de)分組無法完成二層協議的(de)封裝,無法從協議棧發出。使用如(rú)下命令分别在兩台主機(jī)上進行(xíng)對端IP與對端MAC的(de)靜态綁定設置,ping的(de)分組便能正常發出了。

/*192.168.2.115主機(jī)執行(xíng)*/
#arp –s 192.168.2.117 b8:27:eb:d8:83:20
/*192.168.2.117主機(jī)執行(xíng)*/
#arp –s 192.168.2.115 b8:27:eb:c1:d1:39

     現在,在任意一(yī)台主機(jī)上執行(xíng)ping均能可(kě)以看到ping通了。
     3)思考
     我們現在終于可(kě)以根據主機(jī)的(de)MAC地(dì)址來進行(xíng)分組交換轉發了,但這隻是兩台主機(jī)的(de)固定交換轉發,如(rú)果機(jī)器MAC多了怎麽辦?如(rú)果機(jī)器連接交換機(jī)的(de)端口變了怎麽辦?我們需要有(yǒu)一(yī)張記錄表,能夠記錄哪個MAC地(dì)址在哪個端口就好了,通過每個分組的(de)目的(de)MAC來查找其對應的(de)輸出端口,這樣就很容易實現分組交換了。
     1)交換過程的(de)核心數據字段
     從上述實驗可(kě)以看出,目前交換裏面用到的(de)就兩個字段,一(yī)個是端口号,另一(yī)個是MAC地(dì)址。那目的(de)MAC地(dì)址與輸出端口号從哪獲得?其實就是從分組頭的(de)源MAC地(dì)址和(hé)輸入端口轉換變成目的(de)MAC和(hé)輸出端口。故在交換過程中,其核心數據就2個:端口号和(hé)MAC地(dì)址。
     2)MAC轉發表設計與驗證
     MAC轉發表就是我們前面提到的(de)記錄表,這張表記錄了一(yī)個MAC地(dì)址與其對應端口号的(de)綁定關系,這一(yī)關系要從輸入分組數據中提取而來,由分組的(de)輸入端口與源MAC地(dì)址組成這一(yī)綁定關系,在查表中便可(kě)通過目的(de)MAC來獲取其正确的(de)輸出端口了。下一(yī)篇文章(zhāng)我們聊一(yī)下MAC轉發表的(de)設計。
      歡迎您和(hé)學(xué)生們加入FAST開源項目群溝通與探讨,一(yī)起體驗不一(yī)樣的(de)系統設計過程。請先加微信号15116127200後邀請入群。

關注FAST開源社區
FAST一(yī)一(yī)開源、開放、高(gāo)速、高(gāo)效、可(kě)編程、可(kě)定義!軟硬件協同并行(xíng)處理(lǐ)。