0731-84728105
15116127200
二層交換機(jī)原型設計與實現(五)
發布時間:2021-05-24
     MAC地(dì)址的(de)學(xué)習是指使用分組中的(de)源MAC地(dì)址進行(xíng)查表,最後添加或更新到MAC轉發表中。目的(de)MAC查找是指使用分組中的(de)目的(de)MAC進行(xíng)查表,獲得該MAC在學(xué)習中保存的(de)端口号信息。兩個過程都需要對表進行(xíng)遍曆操作,根據邏輯功能的(de)不同,其輸入輸出參數也不一(yī)樣。二層交換的(de)核心邏輯就是這兩個功能函數。
     1)源MAC提取
     首先,源MAC地(dì)址獲取要根據MAC層協議來解析,從其對應的(de)位置提取相應的(de)數據。其次,源MAC的(de)提取有(yǒu)多種方式,主要取決于對MAC地(dì)址的(de)操作方式,如(rú)相等比較。由于MAC地(dì)址是不規整的(de)數據類型,通常可(kě)以使用內(nèi)存塊的(de)比較方式或拆分成幾部分的(de)方式比較,拆分一(yī)般可(kě)分為(wèi)2+2+2;兩種方式都要使用指針傳遞參數。

/*分組源MAC指針獲取*/
&pkt->data[MAC_LEN]/*MAC_LEN宏定義為(wèi)6,表示MAC地(dì)址占6個字節*/
/*判斷兩個MAC地(dì)址是否相等*/
int ether_addr_equal(u8 *addr1,u8 *addr2)
{
u16 *a = (u16 *)addr1;
u16 *b = (u16 *)addr2;
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
}

      2)學(xué)習過程
     前面分析過,在學(xué)習過程中并不清楚原MAC轉發表中是否存在原表項,如(rú)果先查一(yī)次是否存在,再查一(yī)次哪有(yǒu)空位用作存儲,則需要做(zuò)兩次全表遍曆。所以,針對MAC學(xué)習的(de)處理(lǐ)方式就是不管有(yǒu)沒有(yǒu),都當做(zuò)是新增的(de)方式處理(lǐ)。若查表不存在則存儲在一(yī)個空白表項位置,若查表存在,則刷新端口信息。

void learn_smac(u8 inport,u8 *smac)
{
int i = 0,j = -1;
u64 zero_mac = 0;/*定義一(yī)個全零MAC地(dì)址*/
xprintf("learn_smac->\n");
for(;i<>
{
if(!ether_addr_equal(smac,obx_mac_tbl->row[i].mac))
{
/*MAC轉發表當前i行(xíng)的(de)MAC地(dì)址與輸入參數smac相等*/
if(obx_mac_tbl->row[i].port != inport)
{
/*這個MAC地(dì)址發生了端口遷移*/
}
obx_mac_tbl->row[i].port = inport;
return;/*學(xué)習過程完成,立即返回*/
}
else if(j == -1 && !ether_addr_equal((u8 *)&zero_mac,obx_mac_tbl->row[i].mac))
{
j = i;/*記錄第一(yī)個找到為(wèi)空白表項位置*/
}
}
/*j==-1說明既沒有(yǒu)匹配上MAC,也找不到空閑位置存儲*/
if(j == -1)
{
xprintf("learn_smac->Table overflow!\n");
return;
}
/*将該MAC存儲到j的(de)位置*/
memcpy(obx_mac_tbl->row[j].mac,smac,MAC_LEN);
obx_mac_tbl->row[j].port = inport;
xprintf("learn_smac->add new MAC,port:%d,index:%d\n",inport,j);
}

     1)目的(de)MAC提取
     目的(de)MAC提取與源MAC類似,在參數傳遞過程中均用指針方式,故其表示方式為(wèi):

/*分組目的(de)MAC指針獲取*/
pkt->data/*數組名即為(wèi)指針*/

     2)查表過程
     查表過程就是一(yī)個簡單的(de)全表搜索,找到的(de)匹配的(de)MAC地(dì)址,則返回其學(xué)習到的(de)端口号。若是沒有(yǒu)找到匹配的(de)MAC,則需要用個特别的(de)數字(-1)來區分正常的(de)端口号。

int find_dmac(u8 inport,u8 *dmac)
{
int i = 0,ret = -1;/*匹配不到相同MAC,則返回-1*/
for(;i<>
{
if(obx_mac_tbl->row[i].port != inport
&& !ether_addr_equal(dmac,obx_mac_tbl->row[i].mac))
{
ret = obx_mac_tbl->row[i].port;
break;
}
}
xprintf("find_dmac->ret = %d\n",ret);
return ret;
}

     1)表的(de)查找
     表的(de)查找與表的(de)設計相關,如(rú)上我們設計的(de)是一(yī)種簡單的(de)數組結構,故也隻能進行(xíng)順序查找的(de)方式進行(xíng)遍曆。這種查表方式在實際應用場景下一(yī)般不會使用,但在設計原型系統時卻很方便。順序查表根據表的(de)大小和(hé)使用條數增加會導緻查表速度越來越慢,上述在源MAC學(xué)習過程中,會順帶把空閑位置也找出來,減少一(yī)次表的(de)遍曆。那麽查目的(de)MAC時也需要遍曆一(yī)次表,我們是不是也可(kě)以都放在這一(yī)次表的(de)遍曆中完成呢(ne)?當然是可(kě)以的(de),隻是這樣實現對業務的(de)邏輯理(lǐ)解沒有(yǒu)那麽好,但對表的(de)遍曆隻需要一(yī)次即可(kě),從執行(xíng)速度上來說确實會提升。
     另外,在對表的(de)高(gāo)效性處理(lǐ)方面,一(yī)般不會采用全表項匹配或多字段匹配的(de)方法,在表設計時會使用一(yī)個有(yǒu)效位字段,通過有(yǒu)效位的(de)簡單比較就可(kě)确定表項是否為(wèi)空或存在有(yǒu)效數據。這種方法普遍存在于硬件邏輯設計中,硬件的(de)查表方式也多種多樣,通常使用基于內(nèi)容可(kě)尋址存儲器(CAM)方式查表,既簡單又高(gāo)效。
     2)分組輸出
     二層交換的(de)分組輸出主要根據查目的(de)MAC的(de)結果來處理(lǐ),當查詢到相應的(de)輸出端口後,即可(kě)從指定的(de)端口輸出;當查不到該MAC的(de)端口信息時,則隻能通過泛洪的(de)方式轉發,這是在交換機(jī)層面确保數據不丢包的(de)一(yī)種措施,甯可(kě)多發包,也不丢包。當然,廣播地(dì)址也是需要泛洪的(de),多播地(dì)址則需要根據其組信息進行(xíng)端口組發送。下一(yī)篇文章(zhāng)我們來說一(yī)下分組輸出的(de)單播和(hé)多播。
      歡迎您和(hé)學(xué)生們加入FAST開源項目群溝通與探讨,一(yī)起體驗不一(yī)樣的(de)系統設計過程。請先加微信号15116127200後邀請入群。

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