摘 要: 本文介绍了采用XILINX的VIRTEX300E FPGA如何实现Ethernet Frame 到SDH映射的GFP协议,详细阐述了GFP帧映射模式的原理及其实现的方法。
关 键 词:GFP协议;SDH;FPGA;MAC
引言
当前通信领域主导技术有二种:用于内部商业通信的局域网(LAN)和Telco/PTT广域网(WAN)中的SONET/SDH。当企业之间需要互相通信或需要将其总部与分部连接在同一个LAN时,互连的问题便应运而生了,因为在SONET/SDH上并不直接支持以太网的传输。
以太网的数据具有突发和不定长的特性, 这与要求严格同步的SDH帧有很大的区别,因此需要引入合适的数据链路层适配协议来完成以太数据封装,实现到SDH的帧映射。目前,有三种链路层适配协议可以完成以太网业务的数据封装:
PPP(Point-to-Point Protocol)点到点协议和ML-PPP扩展协议;
LAPS(Link Access Procedure--SDH)协议;
GFP(Generic Framing Procedure)通用成帧规程协议;
这三种协议均为面向无连接的数据链路层,并有相应的国际标准:
PPP: RFC1661;
LAPS:ITU-T X.86;
GFP: ITU-T G.7041;
目前,业界普遍看好最新的GFP协议,它代表着未来封装协议的发展方向。从三种数据封装映射方式来看,相对于PPP、LAPS,GFP协议的标准化程度更高,适用程度更广,是数据业务封装映射到SDH/OTN的标准方式之一,具有良好的市场前景。
GFP协议
GFP(Generic Framing Procedure, 通用成帧规程)是一种通用映射技术,它可将变长或定长的数据分组,进行统一的适配处理,实现数据业务在多种高速物理传输通道中的传输。一方面,GFP采用灵活的帧封装以支持固定或可变长度的数据,GFP能对可变长度的用户PDU(Protocol
Data Unit,协议数据单元)进行全封装,免去对数据的拆分、重组及对帧的填充,简化了系统的操作,提高了系统的处理速度和稳定度;另一方面,GFP不像LAPS以特定字符7E填充帧头来确定帧边界,GFP使用类似于ATM中基于差错控制的帧定界方式,以HEC(Head
Error Check,帧头错误检验)为基础,通过两字节当前帧的净荷长度和两字节的帧头错误检验来确定帧的边界,这种显示帧长度指示的方式可减少边界搜索处理时间,对于有较高同步需求的数据链路来说相当重要,同时它克服了靠帧标志定位带来的种种缺点,进一步加快了处理速度,适应下一代SDH高速的要求。
GFP 标准定义了两种模式:透传模式和帧映射模式。
GFP-T(透明映射的GFP)是一种面向块状码的数据流模式,实现对时延敏感的SAN网(Storage Area Network,存储区域网)的线路码的高效和透明地传输,它面对的是Fiber
Channel(光纤通道)、FICON和ESCON接口的数据流。
GFP-F(帧映射的GFP)是一种面向PDU的数据流模式,用作传输IP协议、多协议标记交换(MPLS)和以太网的数据流。
在这里我们主要介绍适用于传输以太网数据的GFP-F模式。
(1)GFP帧结构
GFP协议定义了两种类型的GFP帧:GFP客户帧和GFP管理帧。
GFP的帧结构如图1所示,按字节排列,它包括GFP帧头(Core Header)和GFP净荷区(GFP Payload Area)两部分。
图1 GFP的帧结构(略)
GFP帧头包括帧长度标识(PLI ,Payload Length Indicator)和帧头错误检验(Core HEC)。PLI为2个字节,表明帧的净荷长度,当PLI大于或等于4时,表明该帧是GFP客户帧,否则为GFP管理帧(目前只定义了PLI等于0时的空闲帧)。帧头错误检验也为2个字节,它采用CRC-16的检错方法给帧头提供保护。这是GFP一大特点,它通过计算接收到数据的帧头错误检验值与数据本身比较来实现帧的定位,通过PLI知道帧的长度,这样就可迅速、直接地把净荷从GFP帧中提取出来,从而避免了HDLC协议的需要大量时间的繁琐操作。在发送和接收GFP帧前,四字节的帧头要与十六进制数B6AB31E0进行异或以实现所谓的扰码功能。
GFP净荷区包括:净荷头(Payload Header)、净荷信息域(Payload Information)和净荷的帧检验序列(Payload
FCS)三部分,而净荷头包括:净荷类型(Payload Type)、净荷类型的HEC(Type HEC)和扩展头(Extension
Header)三部分。
净荷类型为2个字节,表明GFP净荷信息的内容和格式。它包括净荷类型标识(PTI)、净荷FCS标识(PFI)、扩展帧头标识(EXI)和用户净荷标识(UPI)。PTI为3bit,表明该GFP帧为客户数据帧还是客户管理帧;PFI为1bit,表明有没有净荷的FCS;EXI为4bit,表明采用哪种扩展帧头:空扩展帧头、线性扩展帧头还是环扩展帧头;UPI为8bit,表明GFP净荷中的数据类型等。从UPI字节可以看出GFP是支持多种数据类型的,如Ethernet、IP、Fiber
Channel、FICON、ESCON等,这也是GFP的一大特点。净荷类型的HEC为2个字节,采用CRC-16给净荷类型提供保护。
GFP的扩展头为0~60字节,有三种类型:空扩展头、线性扩展头和环扩展头,由EXI来设定。空扩展头,此时扩展头为0字节,GFP帧的净荷为单一类型;线性扩展头,用以支持多客户通过点到点结构来共享GFP帧的净荷;环扩展头,用以支持多客户通过环结构来共享GFP帧的净荷,与IEEE
802.17 RPR(Resilient Packet Ring,弹性分组数据环)的MAC类似。由此可见,GFP提供一个灵活的扩展帧头以适应多样的传输机制,这就为SDH提供灵活广泛的应用,而这是HDLC所无法比拟的。
净荷的帧检验序列为4个字节,采用CRC-32来保护净荷的完整。它为可选的,当PFI为1时,则存在,否则不存在。
同样,在发送和接收GFP帧时,净荷区的所有字节要进行X^43+1并行扰码。
(2)ETHERNET MAC 帧的GFP封装格式
MAC 帧与GFP帧的映射关系如图2所示。
图2 MAC帧和GFP帧的关系(略)
MAC帧的格式在IEEE 802.3中进行了定义。MAC帧与GFP帧是一一对应的关系,在进行GFP包封之前,要对MAC帧进行一帧的缓存,以获取MAC帧的长度,该长度加上净荷头的长度形成2字节的PLI标识,并对PLI进行CRC16计算得到2字节的HEC值,PLI与HEC值形成4字节的GFP帧头。净荷类型中的PTI等于000,表明该GFP帧为客户数据帧,PFI等于0,表明该GFP帧没有净荷的FCS,EXI等于0000,表明该GFP帧没有扩展头,UPI等于00000001,表明该GFP帧为以太网MAC帧的映射。对净荷类型进行CRC16计算,得到净荷类型的HEC值,由于没有扩展头,此时净荷头由净荷类型和净荷类型的HEC
4字节组成。净荷信息域包含了从目的地址到FCS的所有MAC帧字节(去除了MAC帧的前导码)。这样MAC帧进行GFP包封后的格式如表1所示。在没有有效的MAC帧发送时,可以直接发送GFP的空闲帧,空闲帧扰码后的格式如表2所示。
表1:数据帧结构(略)
表2:扰码后的空闲帧格式(略)
(3)GFP帧的同步
GFP帧要实现两项非常重要的功能:捕获GFP帧头以及保持帧同步。帧同步情况分为同步状态、预同步状态和搜索状态。由预同步状态到同步状态所需的有效帧头数目N可以由使用者配置。搜索状态为链路链接初始化或GFP接收器接收失败时的基本状态。接收器使用当前的4字节数据来搜索下一帧,如果计算出的Core
HEC值与数据域中的Core HEC值相同,则接收器暂时进入预同步状态,否则,它移到下一字节继续进行搜索。预同步状态时,根据PLI能够确定帧的边界,当连续N个GFP帧被正确检测到,则进入同步状态。同步状态为一个规则的操作状态,它检查PLI值,确定Core
HEC值,提取帧的PDU,然后到下一帧,如此循环,各状态之间的转移如图3所示。
图3 帧同步状态转移图(略)
FPGA的实现
在本设计中采用了XILINX公司的XCV200E芯片,它是一片拥有30万系统门,高速、可灵活编程的FPGA。
(1)MAC帧到GFP帧包封的实现
包封在FPGA中实现的框图如图4所示。
图4 MAC帧到GFP帧包封框图(略)
FPGA通过GMII或MII MAC接口以字节的方式接收一个完整的MAC帧,去除帧前导码后进行MAC帧的缓存,同时对帧长进行计数,并保存在FIFO中,当有一帧缓存结束时,取出该帧的长度值加上净荷头的长度后得到PLI,算出其CRC值形成GFP的Core
Header,再加上固定的4字节净荷头(只有Type Header,无Extension Header),此时从缓存区取出MAC帧的内容加在净荷头之后,完成GFP的包封。当没有有效的MAC帧发送时,必须插入完整的4字节空闲帧,两者进行复用后,分别进行Core
Header扰码(与十六进制数B6AB31E0异或)和Payload扰码(X^43+1)。扰码完成后直接发送给SDH的虚容器中。
(2)GFP帧到MAC帧解包封的实现
解包封在FPGA中实现的框图如图5所示。
从SDH虚容器中接收到数据后,分别送入GFP帧同步的Delineation模块和Payload解扰码模块中,Delineation模块实现GFP帧的同步捕捉和保持,从由预同步状态到同步状态所需的有效帧头数目N取为1,为避免有效的数据丢失,进入预同步状态后,该帧的payload也是有效的,Delineation模块输出一个payload_valid信号给Payload解扰码模块,指示其对有效的数据进行X^43+1解扰码。对解扰后的GFP帧进行解包封,在解包封时要注意一些错误的处理,如要对Type
Header HEC值进行检查,若正确还要对Type Header中的各项值(PTI,PFI,EXI,UPI)进行检查,看接收到的数据是否为所需的MAC帧类型,若有错误则把该帧丢弃,并要进行统计,当PFI为1时,还必须对Payload域进行CRC32的计算,并检查FCS是否正确。解包封完的数据加上前导码后通过GMII或MII
MAC接口送出。由于帧的同步是GFP中比较有特点的地方,所以我把帧同步模块Delineation的Verilog语言程序附在了后面作为参考。
图5 GFP帧到MAC帧解包封框(略)
结束语
由于以太网在企业中非常流行,所以不同区域同一企业间的以太网互联互通将会成为一个问题,GFP作为ITU的国际标准,将会成为今后的主流协议。
附程序:
module delineation ( reset_in, clk, sdh_valid,sdh_data,payload_valid);
input reset_in;
input clk;
input sdh_valid;
input [7:0] sdh_data;
output payload_valid;
reg [1:0] syn_cnt;reg [2:0] state;
reg [23:0] core_shift;
reg [15:0] payload_length;
wire [31:0] descram_core;
wire [15:0] crc_result;
parameter HUNT =3'b001;
parameter PRE_SYN = 3'b010;
parameter SYN = 3'b100;
parameter core_poly = 32'hb6ab31e0;
assign descram_core = {core_shift,sdh_data} ^ core_poly;
assign payload valid = ((state == SYN) | (state ==PRE_ SYN))&
( | payload_length);
assign crc_result = CRC16_D16(descram_core[31:16],16'h0000);
always @(posedge clk or negedge reset_in)
if (~reset_in)
core_shift <=0;
else
if ( ~| payload_length)
begin
if (sdh_valid)
core_shift <= {core_shift[15:0],sdh_data};
end
else
core_shift <= 0;
always @(posedge clk or negedge reset_in)
if (~reset_in)
syn_cnt <= 0;
else
if (sdh_valid)
if ( ~| payload_length)
begin
if (syn_cnt != 2'b11)
syn_cnt <= syn_cnt+1;
else
if (descram_core[15:0] == crc_result)
syn_cnt <= 2'b00;
else
if ((state==PRE_SYN) | (state==SYN))
syn_cnt <= 2'b00;
else
syn_cnt <= 2'b11;
end
else
syn_cnt <= 2'b00;
always @(posedge clk or negedge reset_in)
if (~reset_in)
state <= HUNT;
else
case (state)
HUNT: if ((~| payload_length) & (syn_cnt==2'b11) & sdh_valid)
if (descram_core[15:0] == crc_result)
state <= PRE_SYN;
PRE_SYN:if ((~| payload_length) & (syn_cnt==2'b11) & sdh_valid)
if (descram_core[15:0] == crc_result)
state <= SYN;
else
state <= HUNT;
SYN: if ((~| payload_length) & (syn_cnt==2'b11) & sdh_valid)
if (descram_core[15:0] == crc_result)
state <= SYN;
else
state <= HUNT;
default:state <= HUNT;
endcase
always @(posedge clk or negedge reset_in)
if (~reset_in)
payload_length <= 0;
else
if (sdh_valid)
if (~| payload_length)
begin
if (syn_cnt==2'b11)
if (descram_core[15:0] == crc_result)
payload_length <= descram_core[31:16];
else
payload_length <= 0;
end
else
payload_length <= payload_length-1;
function [15:0] CRC16_D16;
input [15:0] Data;
input [15:0] CRC;
reg [15:0] D;
reg [15:0] C;
reg [15:0] NewCRC;
begin
/* 略 */
end
endfunction
endmodule
|