10G UDP协议栈 (8)ICMP功能

发布于:2024-05-19 ⋅ 阅读:(141) ⋅ 点赞:(0)

一、ICMP的功能以及报文格式

ICMP报文的功能

CMP是 Internet Control Message Protocol 的缩写,即互联网控制消息协议。它是互联网协议族的核心协议之一。它用于 TCP/IP 网络中发送控制消息,提供可能发生在通信环境中的各种问题反馈,通过这些信息,使网络管理者可以对所发生的问题作出诊断,然后采取适当的措施解决问题。

虽然 ICMP 是网络层协议,但是它不像 IP 协议和 ARP 协议一样直接传递给数据链路层,而是先封装成 IP 数据包然后再传递给数据链路层。所以在 IP 数据包中如果协议类型字段的值是 1 的话,就表示 IP 数据是 ICMP 报文。

ICMP字段含义说明

各字段说明

  • 类型:占一字节,标识ICMP报文的类型,目前已定义了14种,从类型值来看ICMP报文可以分为两大类。第一类是取值为1~127的差错报文,第2类是取值128以上的信息报文。如前所述
  • 代码:占一字节,标识对应ICMP报文的代码。它与类型字段一起共同标识了ICMP报文的详细类型。如前所述
  • 校验和:这是对包括ICMP报文数据部分在内的整个ICMP数据报的校验和,以检验报文在传输过程中是否出现了差错。其计算方法与在我们介绍IP报头中的校验和计算方法是一样的。
  • 标识:占两字节,用于标识本ICMP进程,但仅适用于回显请求和应答ICMP报文,对于目标不可达ICMP报文和超时ICMP报文等,该字段的值为0。

二、代码实现

参考FPGA奇哥网课

架构

ICMP_RX模块

ICMP_RX功能:判断由IP层上传过来的数据包是否为ICMP数据包,如果是,则解析出标识符和序列号,并给到ICMP_TX一个触发信号。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/05/18 16:06:11
// Design Name: 
// Module Name: ICMP_RX
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module ICMP_RX(
    input           i_clk               ,
    input           i_rst               ,

    input  [63:0]   s_axis_ip_data      ,
    input  [54:0]   s_axis_ip_user      ,//1'bMF,16'dlen,1'bsplit,8'dtype,13'doffset,16'dID
    input  [7 :0]   s_axis_ip_keep      ,
    input           s_axis_ip_last      ,
    input           s_axis_ip_valid     ,

    output [15:0]   o_Identifier        ,
    output [15:0]   o_Sequence          ,
    output          o_trigger           
);

reg  [63:0]         rs_axis_ip_data     ;
reg  [54:0]         rs_axis_ip_user     ;
reg  [7 :0]         rs_axis_ip_keep     ;
reg                 rs_axis_ip_last     ;
reg                 rs_axis_ip_valid    ;
reg  [15:0]         r_cnt               ;
reg                 r_request           ;
reg  [15:0]         ro_Identifier       ; 
reg  [15:0]         ro_Sequence         ; 
reg                 ro_trigger          ;
reg                 r_icmp_flag         ;

assign o_Identifier = ro_Identifier     ;
assign o_Sequence   = ro_Sequence       ;
assign o_trigger    = ro_trigger        ;

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        rs_axis_ip_data  <= 'd0;
        rs_axis_ip_user  <= 'd0;
        rs_axis_ip_keep  <= 'd0;
        rs_axis_ip_last  <= 'd0;
        rs_axis_ip_valid <= 'd0;
    end else begin
        rs_axis_ip_data  <= s_axis_ip_data ;
        rs_axis_ip_user  <= s_axis_ip_user ;
        rs_axis_ip_keep  <= s_axis_ip_keep ;
        rs_axis_ip_last  <= s_axis_ip_last ;
        rs_axis_ip_valid <= s_axis_ip_valid;
    end    
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_cnt <= 'd0;
    else if(rs_axis_ip_valid)
        r_cnt <= r_cnt + 1;
    else        
        r_cnt <= 'd0;
end
//判断是否为ICMP请求回显的数据包
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_request <= 'd0;
    else if(rs_axis_ip_valid && r_cnt == 0 && rs_axis_ip_data[63:48] == 16'h0800)
        r_request <= 'd1;
    else if(rs_axis_ip_valid && r_cnt == 0 && rs_axis_ip_data[63:48] != 16'h0800)
        r_request <= 'd0;
    else 
        r_request <= r_request;
end
//解析出标识符
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_Identifier <= 'd0;
    else if(rs_axis_ip_valid && r_cnt == 0)
        ro_Identifier <= rs_axis_ip_data[31:16];
    else 
        ro_Identifier <= ro_Identifier;
end
//解析出序列值
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_Sequence <= 'd0;
    else if(rs_axis_ip_valid && r_cnt == 0)
        ro_Sequence <= rs_axis_ip_data[15:0];
    else 
        ro_Sequence <= ro_Sequence;
end
//当收到ICMP请求,并且此帧已经接收完毕,那么就拉高触发信号,通知ICMP_TX模块应答
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_trigger <= 'd0;
    else if(r_request && !s_axis_ip_valid && rs_axis_ip_valid && r_icmp_flag)
        ro_trigger <= 'd1;
    else 
        ro_trigger <= 'd0;
end
//检测是否为ICMP报文
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_icmp_flag <= 'd0;
    else if(s_axis_ip_valid && !rs_axis_ip_valid && s_axis_ip_user[36:29] != 1)
        r_icmp_flag <= 'd0;
    else if(s_axis_ip_valid && !rs_axis_ip_valid && s_axis_ip_user[36:29] == 1)
        r_icmp_flag <= 'd1;
    else 
        r_icmp_flag <= r_icmp_flag;
end

endmodule

 ICMP_TX模块

功能:接收到ICMP_RX模块传递过来的触发信号后,组成与ICMP请求报文相同标识符和序列号的响应报文。在其中的校验和的计算方式上,采用与IP首部校验和相同的方式。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/05/18 16:06:11
// Design Name: 
// Module Name: ICMP_TX
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module ICMP_TX(
    input           i_clk               ,
    input           i_rst               ,

    output [63:0]   m_axis_ip_data      ,
    output [70:0]   m_axis_ip_user      ,//16'dByteLen,1'bMF,16'dlen,1'bsplit,8'dtype,13'doffset,16'dID
    output [7 :0]   m_axis_ip_keep      ,
    output          m_axis_ip_last      ,
    output          m_axis_ip_valid     ,
    input           m_axis_ip_ready     ,

    input  [15:0]   i_Identifier        ,
    input  [15:0]   i_Sequence          ,
    input           i_trigger           
);

reg  [63:0]         rm_axis_ip_data     ;
reg  [70:0]         rm_axis_ip_user     ;
reg  [7 :0]         rm_axis_ip_keep     ;
reg                 rm_axis_ip_last     ;
reg                 rm_axis_ip_valid    ;
reg  [15:0]         r_cnt               ;
reg  [15:0]         ri_Identifier       ;
reg  [15:0]         ri_Sequence         ;
reg                 ri_trigger          ;
reg                 ri_trigger_1d       ;
reg  [31:0]         r_header_check      ;

assign m_axis_ip_data  = rm_axis_ip_data    ;
assign m_axis_ip_user  = rm_axis_ip_user    ;
assign m_axis_ip_keep  = rm_axis_ip_keep    ;
assign m_axis_ip_last  = rm_axis_ip_last    ;
assign m_axis_ip_valid = rm_axis_ip_valid   ;
//接收ICMP_RX模块传递过来的触发信号、标识符、序列值
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_trigger    <= 'd0; 
    end else begin
        ri_trigger    <= i_trigger      ;
        ri_trigger_1d <= ri_trigger     ;
    end
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_Identifier <= 'd0;
    else if(i_trigger)   
        ri_Identifier <= i_Identifier   ;
    else 
        ri_Identifier <= ri_Identifier   ;
end
        
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_Sequence <= 'd0;
    else if(i_trigger)
        ri_Sequence   <= i_Sequence     ;
    else 
        ri_Sequence   <= ri_Sequence     ;
end

//进行首部CRC校验,与IP报文一致,都是以2字节为单位,累加求和(把进位加在低位),然后取反。
//此处先进行累加求和
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_header_check <= 'd0;
    else if(i_trigger)
        r_header_check <= i_Identifier + i_Sequence + 16'h6162 + 16'h6364 + 16'h6566 +16'h6768 + 16'h696a
            + 16'h6b6c + 16'h6d6e + 16'h6f70 + 16'h7172 + 16'h7374 + 16'h7576 + 16'h7761 + 16'h6263 + 16'h6465
            + 16'h6667 + 16'h6869;
    else if(ri_trigger)
        r_header_check <= r_header_check[31:16] + r_header_check[15:0];
    else 
        r_header_check <= r_header_check;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_cnt <= 'd0;
    else if(r_cnt == 4)
        r_cnt <= 'd0;
    else if(ri_trigger_1d || r_cnt)
        r_cnt <= r_cnt + 'd1;
    else 
        r_cnt <= r_cnt;
end
//发送ICMP报文
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_ip_data <= 'd0;
    else case(r_cnt)
        0           :rm_axis_ip_data <= {16'h0000,~r_header_check[15:0],ri_Identifier,ri_Sequence};//16‘h0000代表是响应报文,~r_header_check[15:0]对累加和取反,ri_Identifier,ri_Sequence:要与请求报文的标识符和序列值相同
        1           :rm_axis_ip_data <= {64'h6162636465666768};//之后全部为填充数据
        2           :rm_axis_ip_data <= {64'h696a6b6c6d6e6f70};
        3           :rm_axis_ip_data <= {64'h7172737475767761};
        4           :rm_axis_ip_data <= {64'h6263646566676869};
        default     :rm_axis_ip_data <= {64'h0000000000000000};
    endcase
end

//16'dByteLen,1'bMF,16'dlen,1'bsplit,8'dtype,13'doffset,16'dID

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_ip_user <= 'd0;
    else 
        rm_axis_ip_user <= {16'd40,1'b0,16'd5,1'b0,8'd1,13'd0,16'd1};
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_ip_keep <= 8'b1111_1111;
    else 
        rm_axis_ip_keep <= 8'b1111_1111;
end     

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_ip_last <= 'd0;
    else if(r_cnt == 4)
        rm_axis_ip_last <= 'd1;
    else 
        rm_axis_ip_last <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        rm_axis_ip_valid <= 'd0;
    else if(rm_axis_ip_last)
        rm_axis_ip_valid <= 'd0;
    else if(ri_trigger_1d)
        rm_axis_ip_valid <= 'd1;
    else 
        rm_axis_ip_valid <= rm_axis_ip_valid;
end


endmodule

三、仿真

向ICMP模块发送一个ICMP请求包,查看ICMP_RX和ICMP_TX的执行情况

ICMP_RX模块

ICMP_TX模块


网站公告

今日签到

点亮在社区的每一天
去签到