0731-84728105
15116127200
二层交换机原型设计与实现(七)
发布时间:2021-06-09
     上一篇讲述了bitmap的端口表示方法,也讲了单播只用(yòng)常规方法表示的原因,故我们只需要对多(duō)播的转发表进行相应的定制和处理(lǐ)即可(kě)。单播和多(duō)播的地址區(qū)分(fēn)也已在上篇文(wén)章中交待清楚,本篇重点讲述如何处理(lǐ)多(duō)播数据。
     根据前篇分(fēn)析,多(duō)播表的定义只是将其端口号字段的表述进行了重定义。故多(duō)播表的定义只需要将单播表复制一份即可(kě),只是在处理(lǐ)多(duō)播数据时,对端口字段的使用(yòng)有(yǒu)些不一样。

struct table_port_mac *obx_mc_mac_tbl = NULL;/*定义多(duō)播MAC转发表对象為(wèi)空指针,将在main函数中初始地址*/
/*為(wèi)多(duō)手播MAC转发表分(fēn)配内存,并初始数据為(wèi)0*/
obx_mc_mac_tbl = (struct table_port_mac *)malloc(sizeof(struct table_port_mac));
memset(obx_mc_mac_tbl,0,sizeof(struct table_port_mac));

     本交换机原型中,我们仅支持IGMP v3版本,故只对该版本协议进行解析处理(lǐ),对组播的入组与退组处理(lǐ)只需要处理(lǐ)IGMPv3 的Report分(fēn)组协议即可(kě)。
     解析IGMP协议我们需要关心的分(fēn)组字段如下:
     1)IGMP的组播IP地址為(wèi)224.0.0.22,多(duō)播MAC為(wèi):01:00:5E:00:00:16
     2)以太网帧类型為(wèi)IPv4(0x0800)
     3)IP协议号為(wèi)IGMP(0x2)
     4)IGMP协议的type字段為(wèi)0x22(V3 report)
     相关的协议数据结构定义在以下几个系统头文(wén)件中,将其添加到代码头部。

#include /*ethhdr*/
#include /*iphdr*/
#include /*igmvp_report*/

     1)多(duō)播解析
     多(duō)播首先判断MAC地址的第1字节的最低位,分(fēn)离出多(duō)播分(fēn)组,然后再精确筛选出组播入组与退组的通告消息。

if(pkt->data[0]&0x1)//MC MAC
{
u64 igmpv3_dmac = 0x1600005E0001;
if(!ether_addr_equal(pkt->data,(u8 *)&igmpv3_dmac)) //IGMP
{
struct ethhdr *eth = (struct ethhdr *)pkt->data;
struct iphdr *ip = (struct iphdr *)(eth+1);
int oft = 0;
if(eth->h_proto = htons(0x0800) && ip->protocol == IPPROTO_IGMP)
{
oft = sizeof(*eth) + ip->ihl * sizeof(int);
igmpv3_report(pkt->um.inport,pkt->data+oft);
}
}
}

     2)多(duō)播學(xué)习
     精确筛选出IGMP的Report分(fēn)组后,便可(kě)根据协议字段區(qū)分(fēn)是入组消息或是退组消息。该步最核心的一步是要将IGMP中的组播IP地址转换為(wèi)多(duō)播MAC,并将该MAC消息學(xué)习到多(duō)播MAC转发表中。多(duō)播MAC的转换规则有(yǒu)明确的定义要求,简言之就是MAC地址由三部分(fēn)组成:高24位固定為(wèi)01:00:5E,第23位為(wèi)0,低23位為(wèi)组播IP的低23位。

void igmpv3_report(u8 inport,u8 *igmp)
{
struct igmpv3_report *g3r = (struct igmpv3_report *)igmp;
if(g3r->type == IGMPV3_HOST_MEMBERSHIP_REPORT)/*IGMPv3_REPORT*/
{
u8 mc_mac[MAC_LEN] = {0x01,00,0x5E};
u8 *mcip = NULL;
int k = 0;
for(;kngrec);k++)
{
mcip = (u8 *)&g3r->grec[k].grec_mca;
memcpy(&mc_mac[3],&mcip[1],3);/*仅复制后3字节数据*/
mc_mac[3] &= 0x7F;/*将第23bit置0*/
join_leave_mc_mac(inport,mc_mac,g3r->grec[k].grec_type);
}
}
}

     多(duō)播MAC的學(xué)习过程封装在join_leave_mc_mac函数中,其核心操作方法与单播MAC的學(xué)习过程类似,只是在对端口号的处理(lǐ)不同。

if(type == IGMPV3_CHANGE_TO_EXCLUDE)/*入组*/
{
obx_mc_mac_tbl->row[i].port |= 1<<>
}
else/*退组*/
{
obx_mc_mac_tbl->row[i].port &= ~ (1<<>
}

     3)多(duō)播查表
     多(duō)播的查表与单播完全一致,只是查表的对象换成多(duō)播表,这两个查表过程可(kě)以代码优化成一个功能(néng)函数。
     4)多(duō)播输出
     多(duō)播的输出端口信息存储在返回值的每个bit位上,故需要根据输出端口的bit位是否為(wèi)1来作為(wèi)分(fēn)组输出判断依据。单播和多(duō)播的统一输出函数如下:

void output(u8 outtype,int outport,struct fast_packet *pkt)
{
if(outtype == UC)
{
pkt->um.outport = outport;
pkt_send_normal(pkt,pkt->um.len);
}
else
{
int i = 0;
for(;i<>
{
if(pkt->um.inport != i && (outport & (1< 0)
{
pkt->um.outport = i;
pkt_send_normal(pkt,pkt->um.len);
}
}
}
}

     一定要记得,底层API的输出端口号是常规表示方法,在多(duō)播输出时的端口号应该是变量i的值。
     1)确定协议支持
     硬件适合做简单、确定的事情,软件适合做灵活多(duō)变的事情。故若在硬件中支持组播的加入和退出,简单实现就是支持确定性的IGMPv3协议的Report功能(néng),硬件可(kě)以不像软件一下逐层解析协议,可(kě)以直接将对应几个位置的数据都取出来之后一次判断,符合要求的消息即可(kě)继续完成后续功能(néng)。硬件不如软件灵活,对每一种确定协议的支持都需要确定的逻辑支撑,所以对于比较复杂的协议交互,一般在要设备中加入轻量级的CPU进行处理(lǐ)。一般像确定的组播协议可(kě)以放到FPGA实现,而生成树协议不适合FPGA实现。
     2)MAC表的老化
     老化简单来说就是删除長(cháng)时间不使用(yòng)的表项,把空间留出来给新(xīn)的MAC地址使用(yòng)。老化是為(wèi)了解决MAC地址数量大于转发表空间容量的问题。若有(yǒu)些MAC地址使用(yòng)一段时间之后,就一直不再使用(yòng)或关机,则交换机无需再保留其在MAC转发表中。若不删除,则会导致新(xīn)的MAC表找不到存储空间,导致大量的数据转化為(wèi)泛洪发送,对整个网络来说是灾难性的,不可(kě)容忍的。当然,不计成本的扩大存储容量更是不可(kě)取的。故MAC表的老化是十分(fēn)必要的,下篇主要内容讲述MAC表老化。
      欢迎您和學(xué)生们加入FAST开源项目群沟通与探讨,一起體(tǐ)验不一样的系统设计过程。请先加微信号15116127200后邀请入群。

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