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

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

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

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

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)多播學習
     精确篩選出IGMP的Report分組後,便可根據協議(yì)字段區(qū)分是入組消息或是退組消息。該步最核心的一步是要将IGMP中的組播IP地址轉換爲多播MAC,并将該MAC消息學習到(dào)多播MAC轉發表中。多播MAC的轉換規則有明(míng)确的定義要求,簡言之就是MAC地址由三部分組成:高(gāo)24位固定爲01:00:5E,第23位爲0,低(dī)23位爲組播IP的低(dī)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的學習過程封裝在join_leave_mc_mac函數中,其核心操作(zuò)方法與單播MAC的學習過程類似,隻是在對(duì)端口号的處理(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ì)象換成多播表,這(zhè)兩個查表過程可以代碼優化成一個功能(néng)函數。
     4)多播輸出
     多播的輸出端口信息存儲在返回值的每個bit位上(shàng),故需要根據輸出端口的bit位是否爲1來(lái)作(zuò)爲分組輸出判斷依據。單播和(hé)多播的統一輸出函數如下(xià):

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

關注FAST開(kāi)源社區(qū)
FAST一一開(kāi)源、開(kāi)放(fàng)、高(gāo)速、高(gāo)效、可編程、可定義!軟硬件協同并行處理(lǐ)。