0731-84728105
15116127200
二层交换机原型设计与实现(五)
发布时间:2021-05-24
     MAC地址的學(xué)习是指使用(yòng)分(fēn)组中的源MAC地址进行查表,最后添加或更新(xīn)到MAC转发表中。目的MAC查找是指使用(yòng)分(fēn)组中的目的MAC进行查表,获得该MAC在學(xué)习中保存的端口号信息。两个过程都需要对表进行遍历操作,根据逻辑功能(néng)的不同,其输入输出参数也不一样。二层交换的核心逻辑就是这两个功能(néng)函数。
     1)源MAC提取
     首先,源MAC地址获取要根据MAC层协议来解析,从其对应的位置提取相应的数据。其次,源MAC的提取有(yǒu)多(duō)种方式,主要取决于对MAC地址的操作方式,如相等比较。由于MAC地址是不规整的数据类型,通常可(kě)以使用(yòng)内存块的比较方式或拆分(fēn)成几部分(fēn)的方式比较,拆分(fēn)一般可(kě)分(fēn)為(wèi)2+2+2;两种方式都要使用(yòng)指针传递参数。

/*分(fēn)组源MAC指针获取*/
&pkt->data[MAC_LEN]/*MAC_LEN宏定义為(wèi)6,表示MAC地址占6个字节*/
/*判断两个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é)习过程
     前面分(fēn)析过,在學(xué)习过程中并不清楚原MAC转发表中是否存在原表项,如果先查一次是否存在,再查一次哪有(yǒu)空位用(yòng)作存储,则需要做两次全表遍历。所以,针对MAC學(xué)习的处理(lǐ)方式就是不管有(yǒu)没有(yǒu),都当做是新(xīn)增的方式处理(lǐ)。若查表不存在则存储在一个空白表项位置,若查表存在,则刷新(xīn)端口信息。

void learn_smac(u8 inport,u8 *smac)
{
int i = 0,j = -1;
u64 zero_mac = 0;/*定义一个全零MAC地址*/
xprintf("learn_smac->\n");
for(;i<>
{
if(!ether_addr_equal(smac,obx_mac_tbl->row[i].mac))
{
/*MAC转发表当前i行的MAC地址与输入参数smac相等*/
if(obx_mac_tbl->row[i].port != inport)
{
/*这个MAC地址发生了端口迁移*/
}
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;/*记录第一个找到為(wèi)空白表项位置*/
}
}
/*j==-1说明既没有(yǒu)匹配上MAC,也找不到空闲位置存储*/
if(j == -1)
{
xprintf("learn_smac->Table overflow!\n");
return;
}
/*将该MAC存储到j的位置*/
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类似,在参数传递过程中均用(yòng)指针方式,故其表示方式為(wèi):

/*分(fēn)组目的MAC指针获取*/
pkt->data/*数组名即為(wèi)指针*/

     2)查表过程
     查表过程就是一个简单的全表搜索,找到的匹配的MAC地址,则返回其學(xué)习到的端口号。若是没有(yǒu)找到匹配的MAC,则需要用(yòng)个特别的数字(-1)来區(qū)分(fēn)正常的端口号。

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)表的查找
     表的查找与表的设计相关,如上我们设计的是一种简单的数组结构,故也只能(néng)进行顺序查找的方式进行遍历。这种查表方式在实际应用(yòng)场景下一般不会使用(yòng),但在设计原型系统时却很(hěn)方便。顺序查表根据表的大小(xiǎo)和使用(yòng)条数增加会导致查表速度越来越慢,上述在源MAC學(xué)习过程中,会顺带把空闲位置也找出来,减少一次表的遍历。那么查目的MAC时也需要遍历一次表,我们是不是也可(kě)以都放在这一次表的遍历中完成呢(ne)?当然是可(kě)以的,只是这样实现对业務(wù)的逻辑理(lǐ)解没有(yǒu)那么好,但对表的遍历只需要一次即可(kě),从执行速度上来说确实会提升。
     另外,在对表的高效性处理(lǐ)方面,一般不会采用(yòng)全表项匹配或多(duō)字段匹配的方法,在表设计时会使用(yòng)一个有(yǒu)效位字段,通过有(yǒu)效位的简单比较就可(kě)确定表项是否為(wèi)空或存在有(yǒu)效数据。这种方法普遍存在于硬件逻辑设计中,硬件的查表方式也多(duō)种多(duō)样,通常使用(yòng)基于内容可(kě)寻址存储器(CAM)方式查表,既简单又(yòu)高效。
     2)分(fēn)组输出
     二层交换的分(fēn)组输出主要根据查目的MAC的结果来处理(lǐ),当查询到相应的输出端口后,即可(kě)从指定的端口输出;当查不到该MAC的端口信息时,则只能(néng)通过泛洪的方式转发,这是在交换机层面确保数据不丢包的一种措施,宁可(kě)多(duō)发包,也不丢包。当然,广播地址也是需要泛洪的,多(duō)播地址则需要根据其组信息进行端口组发送。下一篇文(wén)章我们来说一下分(fēn)组输出的单播和多(duō)播。
      欢迎您和學(xué)生们加入FAST开源项目群沟通与探讨,一起體(tǐ)验不一样的系统设计过程。请先加微信号15116127200后邀请入群。

关注FAST开源社區(qū)
FAST一一开源、开放、高速、高效、可(kě)编程、可(kě)定义!软硬件协同并行处理(lǐ)。
服務(wù)热線(xiàn)