【IP层的校验和与UDP的校验和】+【FPGA实现】

MAC层的校验是CRC,而IP层也有其校验机制。

CRC保证数据包的传输正确;

 

IP头校验和

IP头校验和是一种错误检测机制,用于在互联网协议(IP)中保证IP头的数据完整性。

当一个IP数据包从源主机发送到目的主机时,它经过许多路由器和交换机,校验和可以帮助这些中间设备检查数据包在传输过程中是否出现错误。

IP头校验和的计算方式如下:

  1. 分割:将IP头部分为16位(2字节)的段。
  2. 求和:将所有16位的段相加(以二进制求和,也就是每个段直接按位相加)。
  3. 进位处理:如果求和的结果产生了溢出,则将溢出的部分(即进位)加到求和的结果的最低位上。这可能需要重复进行,直到不再有溢出发生。
  4. 取反:将求和结果取反(按位取反,1变0,0变1)得到校验和。

这个校验和随后被填充在IP头中专门为校验和预留的字段内。在接收端,同样的计算会被执行在收到的IP头上,包括校验和字段本身。如果数据包在传输过程中没有错误,所有段的总和加上接收到的校验和的结果应该是一个全1的二进制数(因为原始计算中结果取反了)。如果计算结果不是全1,那么就说明数据在传输过程中可能出现了错误。

重要的是,IP头校验和只检查头部的完整性,并不保护整个IP数据包的内容。传输层(如TCP或UDP)有自己的校验和,负责整个数据段(包括数据)的完整性检查。

在实际的网络设备中,这个计算通常是由硬件来执行,以提高数据包处理的效率。当数据包通过每个路由器传输时,因为TTL字段会改变,所以需要重新计算校验和。

FPGA实现:

module emcode_checksum_ip (
    input   wire            sys_clk            ,
    input   wire            sys_rst_n          ,
    input   wire            i_vaild            ,
    input   wire  [7:0]     i_data             ,
    output  wire            o_vaild            ,
    output  wire  [7:0]     o_data                   
);
            reg   [15:0]    r_i_vaild          ;
            reg   [07:0]    r1_i_data  [15:0]  ;

            reg   [07:0]    checksum_cnt       ;
            reg   [01:0]    concat_cnt         ;
            wire  [15:0]    concat_data        ;
            reg   [31:0]    r1_sum             ;
            wire  [31:0]    r1_checksum_value  ;
            wire  [15:0]    r2_checksum_value  ;
            reg   [15:0]    r3_checksum_value  ;
            reg   [07:0]    vaild_cnt          ;
            reg   [07:0]    r_o_data           ;

    always @(posedge sys_clk) begin
        r_i_vaild <= {r_i_vaild[14:0],i_vaild};
    end

    reg [7:0] reg_i1;
    reg [7:0] reg_i2;
    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            for (reg_i1 = 0; reg_i1 < 'd16;  reg_i1 = reg_i1 + 1) begin
                r1_i_data[reg_i1] <= 'd0;
            end
        end else begin
            for (reg_i2 = 0; reg_i2 < 'd15;  reg_i2 = reg_i2 + 1) begin
                r1_i_data[reg_i2+1] <= r1_i_data[reg_i2];
            end
            r1_i_data[0] <= i_data;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            checksum_cnt <= 8'h0;
        end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin
            checksum_cnt <= 8'h0;
        end else if(i_vaild == 1'b1)begin
            checksum_cnt <= checksum_cnt + 1'b1;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            vaild_cnt <= 8'h0;
        end else if(r_i_vaild[10] == 1'b0 && r_i_vaild[11] == 1'b1) begin
            vaild_cnt <= 8'h0;
        end else if(r_i_vaild[10] == 1'b1)begin
            vaild_cnt <= vaild_cnt + 1'b1;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            concat_cnt <= 2'd0;
        end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin
            concat_cnt <= 2'd0;
        end else if(i_vaild == 1'b1 && checksum_cnt >= 'd22 && checksum_cnt <= 41) begin
            if(concat_cnt == 1'b1) begin
                concat_cnt <= 2'd0;
            end else begin
                concat_cnt <= concat_cnt + 1'b1;
            end
        end else begin
            concat_cnt <= concat_cnt;
        end
    end

    assign  concat_data = {r1_i_data[0],i_data};

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r1_sum <= 32'd0;
        end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin
            r1_sum <= 32'd0;
        end else if(i_vaild == 1'b1 && checksum_cnt >= 'd22 && checksum_cnt <= 'd41 && concat_cnt == 1'b1) begin
            r1_sum <= r1_sum + concat_data;
        end else begin
            r1_sum <= r1_sum;
        end
    end    

    assign  r1_checksum_value =  r1_sum[15:0] + r1_sum[31:16];
    assign  r2_checksum_value = ~(r1_checksum_value[15:0]);

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r3_checksum_value <= 'd0;
        end else if(r_i_vaild[10] == 1'b0 && r_i_vaild[11] == 1'b1) begin
            r3_checksum_value <= 'd0;
        end else if(i_vaild == 1'b1 && checksum_cnt == 'd42) begin
            r3_checksum_value <= r2_checksum_value;
        end
    end

    assign  o_vaild = r_i_vaild[11];
    assign  o_data  = r_o_data     ;
    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r_o_data <= 8'd0;
        end else if(r_i_vaild[10] == 1'b1 && vaild_cnt == 'd32) begin
            r_o_data <= r3_checksum_value[15:08];
        end else if(r_i_vaild[10] == 1'b1 && vaild_cnt == 'd33) begin
            r_o_data <= r3_checksum_value[07:00];
        end else begin
            r_o_data <= r1_i_data[10];
        end
    end
endmodule

 

UDP校验和

UDP校验和是一种错误检测机制,与IP校验和类似,但它覆盖了更多的数据:UDP校验和不仅检查UDP头部,还检查数据部分。这为UDP数据包提供了一个简单的形式的数据完整性验证。

计算UDP校验和的步骤如下:

  1. 伪头部:首先,创建一个所谓的“伪头部”,它包括源IP地址、目的IP地址、一个8位全零字段、协议字段(对于UDP,这个值是17,8‘h11)和UDP长度字段。这个伪头部不是UDP数据包的一部分,而是仅用于校验和计算过程。

  2. 合并:将伪头部、UDP头部和数据部分合并起来。如果数据的总字节长度不是偶数,会在最后添加一个零字节来填充。

  3. 分割:将合并后的数据分割成16位的段。

  4. 求和:以二进制求和这些16位的段,包括溢出。

  5. 进位处理:与IP校验和相同,如果求和的结果产生溢出,将溢出的部分加回到求和结果的最低位。

  6. 取反:将最终的求和结果取反。

 

得到的校验和随后放入UDP头部中的校验和字段。在接收端,同样的计算会被执行在整个数据包上(包括伪头部)。如果数据包传输正确,所有的16位段相加(包括校验和字段)应该结果为全1的二进制数(0xFFFF)。如果不是,那么就说明数据包在传输过程中出现了错误。

值得注意的是,UDP校验和是可选的,在IPv4中可以设置为零表示不计算校验和,但在IPv6中,UDP校验和是必需的。这是因为IPv6不包括一个独立的校验和,因此依赖于UDP校验和提供错误检测。

 FPGA实现:

module checksum_ip_buffer #(
    parameter   UDP_CODE             =  8'h11                                           ,
    parameter   TX_TARGET_PORT       = 16'd808                                          ,
    parameter   TX_SOURCE_PORT       = 16'd8080                                         ,
    parameter   RX_Sync_Frame        = 32'hF05AA50F                                     ,
    parameter   TX_SOURCE_Addr       = {8'd192,8'd168,8'd0,8'd1}                        ,
    parameter   TX_TARGET_Addr       = {8'hFF,8'hFF,8'hFF,8'hFF}                        ,
    //Length
    parameter   TX_PREAMBLE          = {8'h55,8'h55,8'h55,8'h55,8'h55,8'h55,8'h55,8'hD5},
    parameter   TX_TARGET_MAC        = {8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF}            ,// broadcast packet
    parameter   TX_SOURECE_MAC       = {8'hA8,8'hB2,8'h3C,8'h7D,8'h97,8'hD7}            , 
    parameter   Length_HeartBeat     = 16'd92                                           ,
    parameter   Length_UDP           = 16'd72                                           ,
    parameter   Length_HeartBeat_all = 8'd114                                           ,
    parameter   Length_EnCODE_Packet = 8'd114 
)(
    input   wire            sys_clk            ,
    input   wire            sys_rst_n          ,
    input   wire            i_vaild            ,
    input   wire  [7:0]     i_data             ,
    output  wire            o_vaild            ,
    output  wire  [7:0]     o_data                   
);
            reg   [15:0]    i_vaild_cnt          ;
            reg   [15:0]    r_i_vaild            ;
            reg   [07:0]    r1_i_data            ;
            wire  [15:0]    concat_data          ;
        //IP check sum
            reg   [01:0]    ip_concat_cnt        ;
            reg   [01:0]    udp_concat_cnt       ;
            reg   [31:0]    r1_IPsum             ;
            wire  [31:0]    r1_IPchecksum_value  ;
            reg   [15:0]    r2_IPchecksum_value  ;

        //UDP check sum
            reg             udp_reg              ;
            reg   [31:0]    r1_UDPsum            ;
            wire  [31:0]    r1_UDPchecksum_value ;
            wire  [15:0]    r2_UDPchecksum_value ;
            reg   [15:0]    r3_UDPchecksum_value ;
            //rd
            reg             rd_cycle             ;
            reg   [15:0]    rd_cnt               ;
            reg   [15:0]    r_rd_cnt             ;
            reg             r1_o_vaild           ;
            reg             r2_o_vaild           ;
            reg   [07:0]    r1_o_data            ;
            wire  [07:0]    rd_data              ;
            wire  [31:00]   Faker_header         ;
            wire  [15:00]   length_check         ;
            wire            length_check_flag    ;

    assign  Faker_header    = TX_SOURCE_Addr[31:16] + TX_SOURCE_Addr[15:00]
                            + TX_TARGET_Addr[31:16] + TX_TARGET_Addr[15:00]
                            + {8'h00,UDP_CODE} + Length_UDP;

    assign  length_check = Length_UDP - 'd8;
    assign  length_check_flag = (length_check[0] == 0)?(1'b0):(1'b1);


    always @(posedge sys_clk) begin
        r_i_vaild <= {r_i_vaild[14:0],i_vaild};
        r1_o_vaild <= rd_cycle;
        r2_o_vaild <= r1_o_vaild;
        r1_i_data  <= i_data;
        r_rd_cnt   <= rd_cnt;
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            i_vaild_cnt <= 8'h0;
        end else if(i_vaild == 1'b1) begin
            if(i_vaild_cnt == Length_EnCODE_Packet - 1'b1) begin
                i_vaild_cnt <= 8'h0;
            end else begin
                i_vaild_cnt <= i_vaild_cnt + 1'b1;
            end
        end
    end

    assign  concat_data = {r1_i_data,i_data};

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            ip_concat_cnt <= 2'd0;
        end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin
            ip_concat_cnt <= 2'd0;
        end else if(i_vaild == 1'b1 && i_vaild_cnt >= 'd22 && i_vaild_cnt <= 41) begin
            if(ip_concat_cnt == 1'b1) begin
                ip_concat_cnt <= 2'd0;
            end else begin
                ip_concat_cnt <= ip_concat_cnt + 1'b1;
            end
        end else begin
            ip_concat_cnt <= ip_concat_cnt;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r1_IPsum <= 32'd0;
        end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin
            r1_IPsum <= 32'd0;
        end else if(i_vaild == 1'b1 && i_vaild_cnt >= 'd22 && i_vaild_cnt <= 'd41 && ip_concat_cnt == 1'b1) begin
            r1_IPsum <= r1_IPsum + concat_data;
        end else begin
            r1_IPsum <= r1_IPsum;
        end
    end 

    assign  r1_IPchecksum_value =  r1_IPsum[15:0] + r1_IPsum[31:16];

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r2_IPchecksum_value <= 'd0;
        end else if(rd_cycle == 1'b1 && rd_cnt == Length_EnCODE_Packet - 1'b1) begin
            r2_IPchecksum_value <= 'd0;
        end else if(i_vaild == 1'b1 && i_vaild_cnt == 'd42) begin
            r2_IPchecksum_value <= ~(r1_IPchecksum_value[15:0]);
        end
    end

// UDP
    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            udp_concat_cnt <= 2'd0;
        end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin
            udp_concat_cnt <= 2'd0;
        end else if(i_vaild == 1'b1 && ((i_vaild_cnt >= 42 && i_vaild_cnt <= 49) 
        || (i_vaild_cnt >= 'd50 && i_vaild_cnt <= Length_EnCODE_Packet - 1'b1))) begin
            if(udp_concat_cnt == 1'b1) begin
                udp_concat_cnt <= 2'd0;
            end else begin
                udp_concat_cnt <= udp_concat_cnt + 1'b1;
            end
        end else begin
            udp_concat_cnt <= udp_concat_cnt;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            udp_reg <= 1'b0;
        end else if(i_vaild == 1'b1 && i_vaild_cnt == Length_EnCODE_Packet - 1'b1) begin
            udp_reg <= 1'b1;
        end else begin
            udp_reg <= 1'b0;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r1_UDPsum <= 'd0;
        end else if(rd_cycle == 1'b1 && rd_cnt == Length_EnCODE_Packet - 1'b1) begin
            r1_UDPsum <= 'd0;
        end else if(i_vaild == 1'b1 && r_i_vaild == 1'b0) begin
            r1_UDPsum <= Faker_header;
        end else if(i_vaild == 1'b1 && udp_concat_cnt == 1'b1 
        && ((i_vaild_cnt >= 'd42 && i_vaild_cnt <= 'd49) 
        ||  (i_vaild_cnt >= 'd50 && i_vaild_cnt <= Length_EnCODE_Packet - 1'b1))) begin
            r1_UDPsum <= r1_UDPsum + concat_data;
        end else begin
            r1_UDPsum <= r1_UDPsum;
        end
    end 

    assign  r1_UDPchecksum_value =  r1_UDPsum[15:0] + r1_UDPsum[31:16];
    assign  r2_UDPchecksum_value = ~(r1_UDPchecksum_value[15:0]);

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r3_UDPchecksum_value <= 'd0;
        end else if(rd_cycle == 1'b1 && rd_cnt == Length_EnCODE_Packet - 1'b1) begin
            r3_UDPchecksum_value <= 'd0;
        end else if(udp_reg == 1'b1) begin
            r3_UDPchecksum_value <= r2_UDPchecksum_value;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            rd_cycle <= 1'b0;
        end else if(rd_cycle == 1'b1 && rd_cnt == Length_EnCODE_Packet - 1'b1) begin
            rd_cycle <= 1'b0;
        end else if(rd_cycle == 1'b0 && i_vaild == 1'b1 && i_vaild_cnt == Length_EnCODE_Packet - 1'b1) begin
            rd_cycle <= 1'b1;
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            rd_cnt <= 8'h0;
        end else if(rd_cycle == 1'b1) begin
            if(rd_cnt == Length_EnCODE_Packet - 1'b1) begin
                rd_cnt <= 8'h0;
            end else begin
                rd_cnt <= rd_cnt + 1'b1;
            end
        end
    end

    always @(posedge sys_clk) begin
        if(sys_rst_n == 1'b0) begin
            r1_o_data <= 8'h0;
        end else if(r1_o_vaild == 1'b1 && r_rd_cnt == 'd32) begin
            r1_o_data <= r2_IPchecksum_value[15:08];
        end else if(r1_o_vaild == 1'b1 && r_rd_cnt == 'd33) begin
            r1_o_data <= r2_IPchecksum_value[07:00];
        end else if(r1_o_vaild == 1'b1 && r_rd_cnt == 'd48) begin
            r1_o_data <= r3_UDPchecksum_value[15:08];
        end else if(r1_o_vaild == 1'b1 && r_rd_cnt == 'd49) begin
            r1_o_data <= r3_UDPchecksum_value[07:00];
        end else if(r1_o_vaild == 1'b1) begin
            r1_o_data <= rd_data;
        end else begin
            r1_o_data <= 8'hff;
        end
    end

    assign  o_vaild  = r2_o_vaild;
    assign  o_data   = r1_o_data;


buffer_encode buffer_encode_inst0 (
  .clka ( sys_clk     ), // input wire clka
  .wea  ( i_vaild     ), // input wire [0 : 0] wea
  .addra( i_vaild_cnt ), // input wire [6 : 0] addra
  .dina ( i_data      ), // input wire [7 : 0] dina
  .clkb ( sys_clk     ), // input wire clkb
  .addrb( rd_cnt      ), // input wire [6 : 0] addrb
  .doutb( rd_data     )  // output wire [7 : 0] doutb
);

endmodule

 

 
 
 
posted @ 2024-04-09 11:27  NoNounknow  阅读(17)  评论(0编辑  收藏  举报