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

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

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

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

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

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í),在(zài)一個(gè)測試主機上(shàng)ping另一台測試主機的(de)IP,發現已經ping通了(le/liǎo)。

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

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

替換原來(lái)端口交換的(de)邏輯代碼,替換代碼如下:

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

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

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í),在(zài)2端口測試主機上(shàng)ping另一台測試主機的(de)IP,發現ping不(bù)通哦。這(zhè)是(shì)因爲(wéi / wèi)我們現在(zài)的(de)邏輯沒有考慮ARP廣播MAC地(dì / de)址的(de)處理邏輯,導緻其無法正常轉發。本節暫不(bù)處理廣播的(de)泛洪轉發功能,後續文章中與組播一起讨論。
     那如何讓兩邊主機不(bù)發ARP廣播直接發ping的(de)分組呢?了(le/liǎo)解網絡通信原理的(de)人(rén)都知道(dào),這(zhè)個(gè)廣播是(shì)在(zài)ping之(zhī)前發出(chū)的(de)MAC地(dì / de)址學習分組,如果沒有學習到(dào)對端的(de)MAC地(dì / de)址,則ping的(de)分組無法完成二層協議的(de)封裝,無法從協議棧發出(chū)。使用如下命令分别在(zài)兩台主機上(shàng)進行對端IP與對端MAC的(de)靜态綁定設置,ping的(de)分組便能正常發出(chū)了(le/liǎo)。

/*192.168.2.115主機執行*/
#arp –s 192.168.2.117 b8:27:eb:d8:83:20
/*192.168.2.117主機執行*/
#arp –s 192.168.2.115 b8:27:eb:c1:d1:39

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

關注FAST開源社區
FAST一一開源、開放、高速、高效、可編程、可定義!軟硬件協同并行處理。