0731-84728105
15116127200
二層交換機原型設計與實現(七)
發布時(shí)間:2021-06-09
     上(shàng)一篇講述了(le/liǎo)bitmap的(de)端口表示方法,也(yě)講了(le/liǎo)單播隻用常規方法表示的(de)原因,故我們隻需要(yào / yāo)對多播的(de)轉發表進行相應的(de)定制和(hé / huò)處理即可。單播和(hé / huò)多播的(de)地(dì / de)址區分也(yě)已在(zài)上(shàng)篇文章中交待清楚,本篇重點講述如何處理多播數據。
     根據前篇分析,多播表的(de)定義隻是(shì)将其端口号字段的(de)表述進行了(le/liǎo)重定義。故多播表的(de)定義隻需要(yào / yāo)将單播表複制一份即可,隻是(shì)在(zài)處理多播數據時(shí),對端口字段的(de)使用有些不(bù)一樣。

struct table_port_mac *obx_mc_mac_tbl = NULL;/*定義多播MAC轉發表對象爲(wéi / wèi)空指針,将在(zài)main函數中初始地(dì / de)址*/
/*爲(wéi / wèi)多手播MAC轉發表分配内存,并初始數據爲(wéi / 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版本,故隻對該版本協議進行解析處理,對組播的(de)入組與退組處理隻需要(yào / yāo)處理IGMPv3 的(de)Report分組協議即可。
     解析IGMP協議我們需要(yào / yāo)關心的(de)分組字段如下:
     1)IGMP的(de)組播IP地(dì / de)址爲(wéi / wèi)224.0.0.22,多播MAC爲(wéi / wèi):01:00:5E:00:00:16
     2)以(yǐ)太網幀類型爲(wéi / wèi)IPv4(0x0800)
     3)IP協議号爲(wéi / wèi)IGMP(0x2)
     4)IGMP協議的(de)type字段爲(wéi / wèi)0x22(V3 report)
     相關的(de)協議數據結構定義在(zài)以(yǐ)下幾個(gè)系統頭文件中,将其添加到(dào)代碼頭部。

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

     1)多播解析
     多播首先判斷MAC地(dì / de)址的(de)第1字節的(de)最低位,分離出(chū)多播分組,然後再精确篩選出(chū)組播入組與退組的(de)通告消息。

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)多播學習
     精确篩選出(chū)IGMP的(de)Report分組後,便可根據協議字段區分是(shì)入組消息或是(shì)退組消息。該步最核心的(de)一步是(shì)要(yào / yāo)将IGMP中的(de)組播IP地(dì / de)址轉換爲(wéi / wèi)多播MAC,并将該MAC消息學習到(dào)多播MAC轉發表中。多播MAC的(de)轉換規則有明确的(de)定義要(yào / yāo)求,簡言之(zhī)就(jiù)是(shì)MAC地(dì / de)址由三部分組成:高24位固定爲(wéi / wèi)01:00:5E,第23位爲(wéi / wèi)0,低23位爲(wéi / wèi)組播IP的(de)低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);
}
}
}

     多播MAC的(de)學習過程封裝在(zài)join_leave_mc_mac函數中,其核心操作方法與單播MAC的(de)學習過程類似,隻是(shì)在(zài)對端口号的(de)處理不(bù)同。

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

     3)多播查表
     多播的(de)查表與單播完全一緻,隻是(shì)查表的(de)對象換成多播表,這(zhè)兩個(gè)查表過程可以(yǐ)代碼優化成一個(gè)功能函數。
     4)多播輸出(chū)
     多播的(de)輸出(chū)端口信息存儲在(zài)返回值的(de)每個(gè)bit位上(shàng),故需要(yào / yāo)根據輸出(chū)端口的(de)bit位是(shì)否爲(wéi / wèi)1來(lái)作爲(wéi / wèi)分組輸出(chū)判斷依據。單播和(hé / huò)多播的(de)統一輸出(chū)函數如下:

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);
}
}
}
}

     一定要(yào / yāo)記得,底層API的(de)輸出(chū)端口号是(shì)常規表示方法,在(zài)多播輸出(chū)時(shí)的(de)端口号應該是(shì)變量i的(de)值。
     1)确定協議支持
     硬件适合做簡單、确定的(de)事情,軟件适合做靈活多變的(de)事情。故若在(zài)硬件中支持組播的(de)加入和(hé / huò)退出(chū),簡單實現就(jiù)是(shì)支持确定性的(de)IGMPv3協議的(de)Report功能,硬件可以(yǐ)不(bù)像軟件一下逐層解析協議,可以(yǐ)直接将對應幾個(gè)位置的(de)數據都取出(chū)來(lái)之(zhī)後一次判斷,符合要(yào / yāo)求的(de)消息即可繼續完成後續功能。硬件不(bù)如軟件靈活,對每一種确定協議的(de)支持都需要(yào / yāo)确定的(de)邏輯支撐,所以(yǐ)對于(yú)比較複雜的(de)協議交互,一般在(zài)要(yào / yāo)設備中加入輕量級的(de)CPU進行處理。一般像确定的(de)組播協議可以(yǐ)放到(dào)FPGA實現,而(ér)生成樹協議不(bù)适合FPGA實現。
     2)MAC表的(de)老化
     老化簡單來(lái)說(shuō)就(jiù)是(shì)删除長時(shí)間不(bù)使用的(de)表項,把空間留出(chū)來(lái)給新的(de)MAC地(dì / de)址使用。老化是(shì)爲(wéi / wèi)了(le/liǎo)解決MAC地(dì / de)址數量大(dà)于(yú)轉發表空間容量的(de)問題。若有些MAC地(dì / de)址使用一段時(shí)間之(zhī)後,就(jiù)一直不(bù)再使用或關機,則交換機無需再保留其在(zài)MAC轉發表中。若不(bù)删除,則會導緻新的(de)MAC表找不(bù)到(dào)存儲空間,導緻大(dà)量的(de)數據轉化爲(wéi / wèi)泛洪發送,對整個(gè)網絡來(lái)說(shuō)是(shì)災難性的(de),不(bù)可容忍的(de)。當然,不(bù)計成本的(de)擴大(dà)存儲容量更是(shì)不(bù)可取的(de)。故MAC表的(de)老化是(shì)十分必要(yào / yāo)的(de),下篇主要(yào / yāo)内容講述MAC表老化。
      歡迎您和(hé / huò)學生們加入FAST開源項目群溝通與探讨,一起體驗不(bù)一樣的(de)系統設計過程。請先加微信号15116127200後邀請入群。

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