0,IP层协议
版本:占 4 位,ipv4(0100),ipv6(0110);
首部长度:占 4 位;表示一共有多少个32bit(4字节),无可选字段时固定为5;
区分服务:占 8 位,用来获得更好的服务,在旧标准中叫做服务类型,但实际上一直未被使用过 1998 年这个字段改名为区分服务.只有在使用区分服务(DiffServ)时,这个字段才起作用.一般的情况下都不使用这个字段;设置为0;
总长度:占 16 位,指首部和数据之和的长度,单位为字节,因此数据报的最大长度为 65535字节总长度必须不超过最大传送单元 MTU(最大传输负载)。数据长度等于总长度-20(IP首部)
标识:占 16 位,它是一个计数器,用来产生数据报的标识;
标志(flag):占 3 位,第一位保留,第二位(1是不分片,0是分片),第三位是否有更多的分片;
片偏移:占 13 位,指较长的分组在分片后某片在原分组中的相对位置.片偏移以 8 个字节为偏移单位;
生存时间:占 8 位,记为 TTL (Time To Live) 数据报在网络中可通过的路由器数的最大值,TTL 字段是由发送端初始设置一个 8 bit 字段.推荐的初始值由分配数字 RFC 指定,当前值为 64.发送 ICMP 回显应答时经常把 TTL 设为最大值 255;
协议:占 8 位,指出此数据报携带的数据使用何种协议以便目的主机的 IP 层将数据部分上交给哪个处理过程, 1 表示为 ICMP 协议, 2 表示为 IGMP 协议, 6 表示为 TCP 协议, 17表示为 UDP 协议;
首部检验和:占 16 位,只检验数据报的首部不检验数据部分,采用二进制反码求和,即将16 位数据相加后,再将进位与低 16 位相加,直到进位为 0,最后将 16 位取反;
源地址:自身IP地址;
目的地址:接收方IP地址;
1,编写工程
ip层主要包含三个模块:ip_rx,ip_tx,ip_module
module _10g_ip_module
#(
parameter P_SOURCE_IP = 32'hc0_01_01_01,
parameter P_TARGET_IP = 32'hc0_01_01_01
)
(
input i_clk ,
input i_rst ,
//drp
input [ 31:0] i_dynamic_source_ip ,
input i_dynamic_source_valid ,
input [ 31:0] i_dynamic_target_ip ,
input i_dynamic_target_valid ,
/************** axi_mac *********************/
output [ 63:0] m_axis_mac_data ,
output [ 79:0] m_axis_mac_user ,//len(16)+source_mac(48)+type(16)
output [ 7:0] m_axis_mac_keep ,
output m_axis_mac_last ,
output m_axis_mac_valid ,
input [ 63:0] s_axis_mac_data ,
input [ 79:0] s_axis_mac_user ,//len(16)+source_mac(48)+type(16)
input [ 7:0] s_axis_mac_keep ,
input s_axis_mac_last ,
input s_axis_mac_valid ,
/************** axi_out *********************/
//与UDP或者ICMP层的交互
output [ 63:0] m_axis_out_data ,
output [ 55:0] m_axis_out_user ,//16len + 8type + 16ip + 3mflag + 13offset
output [ 7:0] m_axis_out_keep ,
output m_axis_out_last ,
output m_axis_out_valid ,
input [ 63:0] s_axis_out_data ,
input [ 55:0] s_axis_out_user ,//16len + 8type + 16ip + 3mflag + 13offset
input [ 7:0] s_axis_out_keep ,
input s_axis_out_last ,
input s_axis_out_valid
);
_10g_ip_tx
#(
.P_SOURCE_IP (P_SOURCE_IP ),
.P_TARGET_IP (P_TARGET_IP )
)
_10g_ip_tx_inst
(
.i_clk (i_clk ),
.i_rst (i_rst ),
//drp
.i_dynamic_source_ip (i_dynamic_source_ip ),
.i_dynamic_source_valid (i_dynamic_source_valid ),
.i_dynamic_target_ip (i_dynamic_target_ip ),
.i_dynamic_target_valid (i_dynamic_target_valid ),
.m_axis_mac_data (m_axis_mac_data ),
.m_axis_mac_user (m_axis_mac_user ),//len(16)+source_mac(48)+type(16)
.m_axis_mac_keep (m_axis_mac_keep ),
.m_axis_mac_last (m_axis_mac_last ),
.m_axis_mac_valid (m_axis_mac_valid ),
.m_axis_mac_ready ( ),
.s_axis_out_data (s_axis_out_data ),
.s_axis_out_user (s_axis_out_user ),//16len + 8type + 16ip + 3mflag + 13offset
.s_axis_out_keep (s_axis_out_keep ),
.s_axis_out_last (s_axis_out_last ),
.s_axis_out_valid (s_axis_out_valid )
);
_10g_ip_rx
#(
.P_SOURCE_IP (P_SOURCE_IP ),
.P_TARGET_IP (P_TARGET_IP )
)
_10g_ip_rx_inst
(
.i_clk (i_clk ),
.i_rst (i_rst ),
//drp
.i_dynamic_source_ip (i_dynamic_source_ip ),
.i_dynamic_source_valid (i_dynamic_source_valid ),
.i_dynamic_target_ip (i_dynamic_target_ip ),
.i_dynamic_target_valid (i_dynamic_target_valid ),
.s_axis_mac_data (s_axis_mac_data ),
.s_axis_mac_user (s_axis_mac_user ),//len(16)+source_mac(48)+type(16)
.s_axis_mac_keep (s_axis_mac_keep ),
.s_axis_mac_last (s_axis_mac_last ),
.s_axis_mac_valid (s_axis_mac_valid ),
.m_axis_out_data (m_axis_out_data ),
.m_axis_out_user (m_axis_out_user ),//16len + 8type + 16ip + 3mflag + 13offset
.m_axis_out_keep (m_axis_out_keep ),
.m_axis_out_last (m_axis_out_last ),
.m_axis_out_valid (m_axis_out_valid )
);
1.1,ip_rx
该模块主要负责接受MAC层输出的类型为0800的ip类型数据,进行数据报文的解析,主要功能如下:
module _10g_ip_rx
#(
parameter P_SOURCE_IP = 32'hc0_01_01_01,
parameter P_TARGET_IP = 32'hc0_01_01_01
)
(
input i_clk ,
input i_rst ,
//drp
input [ 31:0] i_dynamic_source_ip ,
input i_dynamic_source_valid ,
input [ 31:0] i_dynamic_target_ip ,
input i_dynamic_target_valid ,
input [ 63:0] s_axis_mac_data ,
input [ 79:0] s_axis_mac_user ,//len(16)+source_mac(48)+type(16)
input [ 7:0] s_axis_mac_keep ,
input s_axis_mac_last ,
input s_axis_mac_valid ,
output [ 63:0] m_axis_out_data ,
output [ 55:0] m_axis_out_user ,//16len + 8type + 16ip + 3mflag + 13offset
output [ 7:0] m_axis_out_keep ,
output m_axis_out_last ,
output m_axis_out_valid
);
1,解析出报文的长度(1byte形式),这里长度需要进行统一,有的是按照64bit(8byte形式),长度存放在user中,后续统一。
2,解析出协议protocal,为后续的ICMP,UDP仲裁使用。1 表示为 ICMP 协议, 2 表示为 IGMP 协议, 6 表示为 TCP 协议, 17表示为 UDP 协议;
3,解析出MFB,offset,为后续巨帧的开发做准备。
4,因为在MAC做了CRC校验,这里就不再对ip的首部检验和做检查,而是仅仅检查IP头部中的目的IP与IP层中的source_ip是否一致,用于控制输出的valid信号。
5,解析数据,传递给下一层,任然是老套的keep处理,尤其是尾端keep,但是因为经过MAC处理之后已经是字节对齐过了的,处理起来很方便。
else if( !r_s_axis_mac_valid && r_s_axis_mac_valid_1d && !(r_last_keep == 8'b1000_0000 || r_last_keep == 8'b1100_0000 || r_last_keep == 8'b1110_0000 || r_last_keep == 8'b1111_0000 ) ) begin
case (r_last_keep)
8'b1000_0000 : r_m_axis_out_keep <= 8'b1111_1000;//提前一个周期
8'b1100_0000 : r_m_axis_out_keep <= 8'b1111_1100;//提前一个周期
8'b1110_0000 : r_m_axis_out_keep <= 8'b1111_1110;//提前一个周期
8'b1111_0000 : r_m_axis_out_keep <= 8'b1111_1111;//提前一个周期
8'b1111_1000 : r_m_axis_out_keep <= 8'b1000_0000;
8'b1111_1100 : r_m_axis_out_keep <= 8'b1100_0000;
8'b1111_1110 : r_m_axis_out_keep <= 8'b1110_0000;
8'b1111_1111 : r_m_axis_out_keep <= 8'b1111_1111;
default : r_m_axis_out_keep <= 8'b1111_1111;
endcase
end
else if( !s_axis_mac_valid && r_s_axis_mac_valid && (r_last_keep == 8'b1000_0000 || r_last_keep == 8'b1100_0000 || r_last_keep == 8'b1110_0000 || r_last_keep == 8'b1111_0000 ) ) begin
case (r_last_keep)
8'b1000_0000 : r_m_axis_out_keep <= 8'b1111_1000;//提前一个周期
8'b1100_0000 : r_m_axis_out_keep <= 8'b1111_1100;//提前一个周期
8'b1110_0000 : r_m_axis_out_keep <= 8'b1111_1110;//提前一个周期
8'b1111_0000 : r_m_axis_out_keep <= 8'b1111_1111;//提前一个周期
8'b1111_1000 : r_m_axis_out_keep <= 8'b1000_0000;
8'b1111_1100 : r_m_axis_out_keep <= 8'b1100_0000;
8'b1111_1110 : r_m_axis_out_keep <= 8'b1110_0000;
8'b1111_1111 : r_m_axis_out_keep <= 8'b1111_1111;
default : r_m_axis_out_keep <= 8'b1111_1111;
endcase
end
仿真波形:
可以看到ip报文头部的20个byte已经全部移除,数据提取完毕且完成字节对齐。
1.2,ip_tx
将IMCP,UDP层发送的数据添加IP首部发送给MAC。
module _10g_ip_tx
#(
parameter P_SOURCE_IP = 32'hc0_01_01_01,
parameter P_TARGET_IP = 32'hc0_01_01_01
)
(
input i_clk ,
input i_rst ,
//drp
input [ 31:0] i_dynamic_source_ip ,
input i_dynamic_source_valid ,
input [ 31:0] i_dynamic_target_ip ,
input i_dynamic_target_valid ,
output [ 63:0] m_axis_mac_data ,
output [ 79:0] m_axis_mac_user ,//len(16)+source_mac(48)+type(16)
output [ 7:0] m_axis_mac_keep ,
output m_axis_mac_last ,
output m_axis_mac_valid ,
output m_axis_mac_ready ,
input [ 63:0] s_axis_out_data ,
input [ 55:0] s_axis_out_user ,//16len + 8type + 16ip + 3mflag + 13offset
input [ 7:0] s_axis_out_keep ,
input s_axis_out_last ,
input s_axis_out_valid
);
主要功能:
1,根据输入的user中的数据进行IP首部的组帧
input [ 55:0] s_axis_out_user ,//16len + 8type + 16ip + 3mflag + 13offset
2,首部校验和的计算,接受我们可以不校验,但是发送需要自己组成,
IP首部校验和计算方法:https://blog.youkuaiyun.com/weixin_44870077/article/details/118106364
总结一下就是:
- 将头部20个字节的IP首部分为10个16bit大小的数据,且首部检验和为0,进行相加。存放进一个[31:0]result(大位宽防止加法溢出);
- 使用result[31:16]+result[15:0],进行相加(如果担心任然有溢出,再次操作);
- 对最后的到的result[15:0]进行取反,即为首部校验和;
//首部校验和
always @(posedge i_clk) begin
if (i_rst) begin
r_header_sum_check <= 'd0;
end
else if(r_in_cnt == 1) begin
r_header_sum_check <= 16'h4500
+ (r_s_axis_out_user[55:40] + 16'd20) //len
+ r_s_axis_out_user[31:16] //id
+ r_s_axis_out_user[15:0] //mflag + offset
+ {P_LIVE_TIME , r_s_axis_out_user[36:29]} //live + protocol
+ 16'd0 //header_sum
+ r_i_dynamic_source_ip[31:16] + r_i_dynamic_source_ip[15:0]
+ r_i_dynamic_target_ip[31:16] + r_i_dynamic_target_ip[15:0];
end
else if(r_in_cnt == 2) begin
r_header_sum_check <= r_header_sum_check[31:16] + r_header_sum_check[15:0];
end
else if(r_in_cnt == 3) begin
r_header_sum_check <= r_header_sum_check[31:16] + r_header_sum_check[15:0];
end
else begin
r_header_sum_check <= r_header_sum_check;
end
end
3,进行数据输出的控制
主要还是keep,valid,last信号,发送给mac层 。
4,仿真波形:
2,上板
等待总体工程完毕。。。