二層交換機(jī)原型設(shè)計(jì)與實(shí)現(xiàn)(五)
發(fā)布時(shí)間:2021-05-24
MAC地址的學(xué)習(xí)是指使用分組中的源MAC地址進(jìn)行查表,最后添加或更新到MAC轉(zhuǎn)發(fā)表中。目的MAC查找是指使用分組中的目的MAC進(jìn)行查表,獲得該MAC在學(xué)習(xí)中保存的端口號(hào)信息。兩個(gè)過(guò)程都需要對(duì)表進(jìn)行遍歷操作,根據(jù)邏輯功能的不同,其輸入輸出參數(shù)也不一樣。二層交換的核心邏輯就是這兩個(gè)功能函數(shù)。
1)源MAC提取
首先,源MAC地址獲取要根據(jù)MAC層協(xié)議來(lái)解析,從其對(duì)應(yīng)的位置提取相應(yīng)的數(shù)據(jù)。其次,源MAC的提取有多種方式,主要取決于對(duì)MAC地址的操作方式,如相等比較。由于MAC地址是不規(guī)整的數(shù)據(jù)類型,通常可以使用內(nèi)存塊的比較方式或拆分成幾部分的方式比較,拆分一般可分為2+2+2;兩種方式都要使用指針傳遞參數(shù)。
/*分組源MAC指針獲取*/
&pkt->data[MAC_LEN]/*MAC_LEN宏定義為6,表示MAC地址占6個(gè)字節(jié)*/
/*判斷兩個(gè)MAC地址是否相等*/
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é)習(xí)過(guò)程
前面分析過(guò),在學(xué)習(xí)過(guò)程中并不清楚原MAC轉(zhuǎn)發(fā)表中是否存在原表項(xiàng),如果先查一次是否存在,再查一次哪有空位用作存儲(chǔ),則需要做兩次全表遍歷。所以,針對(duì)MAC學(xué)習(xí)的處理方式就是不管有沒有,都當(dāng)做是新增的方式處理。若查表不存在則存儲(chǔ)在一個(gè)空白表項(xiàng)位置,若查表存在,則刷新端口信息。
void learn_smac(u8 inport,u8 *smac)
{
int i = 0,j = -1;
u64 zero_mac = 0;/*定義一個(gè)全零MAC地址*/
xprintf("learn_smac->\n");
for(;i
{
if(!ether_addr_equal(smac,obx_mac_tbl->row[i].mac))
{
/*MAC轉(zhuǎn)發(fā)表當(dāng)前i行的MAC地址與輸入?yún)?shù)smac相等*/
if(obx_mac_tbl->row[i].port != inport)
{
/*這個(gè)MAC地址發(fā)生了端口遷移*/
}
obx_mac_tbl->row[i].port = inport;
return;/*學(xué)習(xí)過(guò)程完成,立即返回*/
}
else if(j == -1 && !ether_addr_equal((u8 *)&zero_mac,obx_mac_tbl->row[i].mac))
{
j = i;/*記錄第一個(gè)找到為空白表項(xiàng)位置*/
}
}
/*j==-1說(shuō)明既沒有匹配上MAC,也找不到空閑位置存儲(chǔ)*/
if(j == -1)
{
xprintf("learn_smac->Table overflow!\n");
return;
}
/*將該MAC存儲(chǔ)到j(luò)的位置*/
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)目的MAC提取
目的MAC提取與源MAC類似,在參數(shù)傳遞過(guò)程中均用指針方式,故其表示方式為:
/*分組目的MAC指針獲取*/
pkt->data/*數(shù)組名即為指針*/
2)查表過(guò)程
查表過(guò)程就是一個(gè)簡(jiǎn)單的全表搜索,找到的匹配的MAC地址,則返回其學(xué)習(xí)到的端口號(hào)。若是沒有找到匹配的MAC,則需要用個(gè)特別的數(shù)字(-1)來(lái)區(qū)分正常的端口號(hào)。
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)表的查找
表的查找與表的設(shè)計(jì)相關(guān),如上我們?cè)O(shè)計(jì)的是一種簡(jiǎn)單的數(shù)組結(jié)構(gòu),故也只能進(jìn)行順序查找的方式進(jìn)行遍歷。這種查表方式在實(shí)際應(yīng)用場(chǎng)景下一般不會(huì)使用,但在設(shè)計(jì)原型系統(tǒng)時(shí)卻很方便。順序查表根據(jù)表的大小和使用條數(shù)增加會(huì)導(dǎo)致查表速度越來(lái)越慢,上述在源MAC學(xué)習(xí)過(guò)程中,會(huì)順帶把空閑位置也找出來(lái),減少一次表的遍歷。那么查目的MAC時(shí)也需要遍歷一次表,我們是不是也可以都放在這一次表的遍歷中完成呢?當(dāng)然是可以的,只是這樣實(shí)現(xiàn)對(duì)業(yè)務(wù)的邏輯理解沒有那么好,但對(duì)表的遍歷只需要一次即可,從執(zhí)行速度上來(lái)說(shuō)確實(shí)會(huì)提升。
另外,在對(duì)表的高效性處理方面,一般不會(huì)采用全表項(xiàng)匹配或多字段匹配的方法,在表設(shè)計(jì)時(shí)會(huì)使用一個(gè)有效位字段,通過(guò)有效位的簡(jiǎn)單比較就可確定表項(xiàng)是否為空或存在有效數(shù)據(jù)。這種方法普遍存在于硬件邏輯設(shè)計(jì)中,硬件的查表方式也多種多樣,通常使用基于內(nèi)容可尋址存儲(chǔ)器(CAM)方式查表,既簡(jiǎn)單又高效。
2)分組輸出
二層交換的分組輸出主要根據(jù)查目的MAC的結(jié)果來(lái)處理,當(dāng)查詢到相應(yīng)的輸出端口后,即可從指定的端口輸出;當(dāng)查不到該MAC的端口信息時(shí),則只能通過(guò)泛洪的方式轉(zhuǎn)發(fā),這是在交換機(jī)層面確保數(shù)據(jù)不丟包的一種措施,寧可多發(fā)包,也不丟包。當(dāng)然,廣播地址也是需要泛洪的,多播地址則需要根據(jù)其組信息進(jìn)行端口組發(fā)送。下一篇文章我們來(lái)說(shuō)一下分組輸出的單播和多播。
歡迎您和學(xué)生們加入FAST開源項(xiàng)目群溝通與探討,一起體驗(yàn)不一樣的系統(tǒng)設(shè)計(jì)過(guò)程。請(qǐng)先加微信號(hào)15116127200后邀請(qǐng)入群。

關(guān)注FAST開源社區(qū)
FAST一一開源、開放、高速、高效、可編程、可定義!軟硬件協(xié)同并行處理。