10G UDP协议栈 IP层设计-(6)IP TX模块

一、模块功能

1、上层数据封装IP报文头部

2、计算首部校验和

二、首部校验和计算方法

在发送方,先把IP数据报首部划分为许多16位字的序列,并把检验和字段置零。用反码算术运算把所有16位字相加后,将得到的和的反码写入检验和字段。接收方收到数据报后,将首部的所有16位字再使用反码算术运算相加一次。将得到的和取反码,即得出接收方检验和的计算结果。若首部未发生任何变化,则此结果必为0,于是就保留这个数据报。否则即认为出差错。

原文链接:https://blog.csdn.net/weixin_44870077/article/details/118106364

例如一包数据的首部:64'h4500001400012000、64'h8017d0b9c0a86464、64'hc0a8646300000000

版本号到片偏移:64'h4500001400012000

生存时间:8'h80

协议号:8'h17

计算出来的首部校验和:16'hd0b9

源IP地址:c0a86464

目的IP地址:c0a86463

划分为长度为16bit的字段:4500 0014 0001 2000 8017 首部校验和初始计算值0000 c0a8 6464 c0a8 6463

相加:4500 + 0014 + 0001 + 2000 + 8017 + 0000 + c0a8 + 6464 + c0a8 + 6463 = 3 2F43

进位的高位再次加到低16位:2F43 + 0003 = 2F46

按位取法之后得到:d0b9

三、程序设计

参考:奇哥FPGA

//将数据缓存到FIFO
FIFO_UDP_DATA_64X16 u_FIFO_UDP_DATA_64X16 (
  .clk          (i_clk              ), 
  .srst         (i_rst              ), 
  .din          (rs_axis_out_data   ), 
  .wr_en        (rs_axis_out_valid  ), 
  .rd_en        (r_fifo_rden        ), 
  .dout         (w_fifo_data_out    ), 
  .full         (), 
  .empty        (w_fifo_empty       )  
);


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)begin
        rs_axis_out_data    <= 'd0; 
        rs_axis_out_user    <= 'd0;
        rs_axis_out_keep    <= 'd0;
        rs_axis_out_last    <= 'd0;
        rs_axis_out_valid   <= 'd0;
    end
    else begin
        rs_axis_out_data    <= s_axis_out_data  ;
        rs_axis_out_user    <= s_axis_out_user  ;
        rs_axis_out_keep    <= s_axis_out_keep  ;
        rs_axis_out_last    <= s_axis_out_last  ;
        rs_axis_out_valid   <= s_axis_out_valid ;
    end
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)begin
        r_fifo_rden_ff1 <= 'd0;
        r_fifo_rden_ff2 <= 'd0;
    end
    else begin
        r_fifo_rden_ff1 <= r_fifo_rden;
        r_fifo_rden_ff2 <= r_fifo_rden_ff1;
    end
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_fifo_data_out <= 'd0;
    else
        r_fifo_data_out <= w_fifo_data_out;
end


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_last_user <= 'd0;
    else
        if(s_axis_out_last)
            r_last_user <= s_axis_out_user;
        else
            r_last_user <= r_last_user;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_last_keep <= 'd0;
    else
        if(s_axis_out_last)
            r_last_keep <= s_axis_out_keep;
        else
            r_last_keep <= r_last_keep;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        ri_set_source_ip <= P_SOURCE_IP;
    else
        if(i_set_source_valid)
            ri_set_source_ip <= i_set_source_ip;
        else
            ri_set_source_ip <= ri_set_source_ip;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        ri_set_target_ip <= P_TARGET_IP;
    else
        if(i_set_target_valid)
            ri_set_target_ip <= i_set_target_ip;
        else
            ri_set_target_ip <= ri_set_target_ip;
end
//当FIFO有数据时就开始读FIFO
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_fifo_rden <= 'd0;
    else
        if(!w_fifo_empty && r_cnt == 0)
            r_fifo_rden <= 1'b1;
        else if(w_fifo_empty)
            r_fifo_rden <= 1'b0;
        else
            r_fifo_rden <= r_fifo_rden;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_cnt <= 'd0;
    else
        if(rm_axis_mac_last)
            r_cnt <= 'd0;
        else if((!w_fifo_empty && r_cnt == 0 && m_axis_mac_ready)|| r_cnt)
            r_cnt <= r_cnt + 1;
        else
            r_cnt <= r_cnt;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rs_axis_out_ready <= 'd1;
    else
        if(s_axis_out_last || !m_axis_mac_ready)
            rs_axis_out_ready <= 'd0;
        else if(rm_axis_mac_last || (!rm_axis_mac_valid && !m_axis_mac_ready))
            rs_axis_out_ready <= 'd1;
        else
            rs_axis_out_ready <= rs_axis_out_ready ;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_data <= 'd0;
    else
        if(!w_fifo_empty && r_cnt == 0)
            rm_axis_mac_data <= {4'b0100,4'b0101,8'd0,(rs_axis_out_user[70:55] + 16'd20),
                                 rs_axis_out_user[15:0],{1'b0,rs_axis_out_user[54],~rs_axis_out_user[37]},rs_axis_out_user[28:16]};
        else if(r_cnt == 1)
            rm_axis_mac_data <= {8'd128,rs_axis_out_user[36:29],~r_header_check[15:0],ri_set_source_ip[31:0]};
        else if(r_cnt == 2)
            rm_axis_mac_data <= {ri_set_target_ip[31:0],w_fifo_data_out[63:32]};
        else
            rm_axis_mac_data <= {r_fifo_data_out[31:0],w_fifo_data_out[63:32]};
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_hd_check_cnt <= 'd0;
    else
        if(s_axis_out_valid)
            r_hd_check_cnt <= r_hd_check_cnt + 1;
        else
            r_hd_check_cnt <= 'd0;
end

//做首部校验和
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_header_check <= 'd0;
    else
        if(r_hd_check_cnt == 1)
            r_header_check <= 16'h4500 + (rs_axis_out_user[70:55] + 16'd20) + rs_axis_out_user[15:0] + 
                              ({{1'b0,rs_axis_out_user[54],~rs_axis_out_user[37]},rs_axis_out_user[28:16]})
                              + {8'd128,rs_axis_out_user[36:29]} ++ ri_set_source_ip[31:16] + ri_set_source_ip[15:0] 
                              + ri_set_target_ip[31:16] + ri_set_target_ip[15:0];
        else if(r_hd_check_cnt == 1)
            r_header_check <= r_header_check[31:16] + r_header_check[15:0]; //可能会产生进位
        else if(r_hd_check_cnt == 2)
            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)
        rm_axis_mac_user <= 'd0;
    else
        rm_axis_mac_user <= {((rs_axis_out_user[70:55] + 16'd19) >> 3) + 1,48'hFFFFFFFF_FFFF,16'h0800};
end
//字节对齐
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_keep <= 'd0;
    else
        if(w_fifo_rden_neg && r_last_keep <= 8'b1111_0000)
            case(r_last_keep)
                // 8'b1111_1111: rm_axis_mac_keep <= 8'b1111_1111
                // 8'b1111_1110: rm_axis_mac_keep <= 
                // 8'b1111_1100: rm_axis_mac_keep <=
                // 8'b1111_1000: rm_axis_mac_keep <=
                8'b1111_0000: rm_axis_mac_keep <= 8'b1111_1111;
                8'b1110_0000: rm_axis_mac_keep <= 8'b1111_1110;
                8'b1100_0000: rm_axis_mac_keep <= 8'b1111_1100;
                8'b1000_0000: rm_axis_mac_keep <= 8'b1111_1000;
                default     : rm_axis_mac_keep <= 8'b1111_1111;
            endcase
        else if(w_fifo_rden_neg_ff1 && r_last_keep >= 8'b1111_1000)
            case(r_last_keep)
                8'b1111_1111: rm_axis_mac_keep <= 8'b1111_0000;
                8'b1111_1110: rm_axis_mac_keep <= 8'b1110_0000;
                8'b1111_1100: rm_axis_mac_keep <= 8'b1100_0000;
                8'b1111_1000: rm_axis_mac_keep <= 8'b1000_0000;
                // 8'b1111_0000: rm_axis_mac_keep <= 8'b1111_1111;
                // 8'b1110_0000: rm_axis_mac_keep <= 8'b1111_1110;
                // 8'b1100_0000: rm_axis_mac_keep <= 8'b1111_1100;
                // 8'b1000_0000: rm_axis_mac_keep <= 8'b1111_1000;
                default     : rm_axis_mac_keep <= 8'b0000_0000;
            endcase   
        else
               rm_axis_mac_keep <= 8'b1111_1111;      
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_last <= 'd0;
    else
        if(w_fifo_rden_neg && r_last_keep <= 8'b1111_0000)
            rm_axis_mac_last <= 1'b1;
        else if(w_fifo_rden_neg_ff1 && r_last_keep >= 8'b1111_1000)
            rm_axis_mac_last <= 1'b1;
        else
            rm_axis_mac_last <= 'd0;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_valid <= 'd0;
    else
        if(!w_fifo_empty && r_cnt == 0)
            rm_axis_mac_valid <= 1'b1;
        else if(rm_axis_mac_last)
            rm_axis_mac_valid <= 'd0;
        else
            rm_axis_mac_valid <= rm_axis_mac_valid ;

end

四、仿真

相关推荐
C++忠实粉丝9 分钟前
计算机网络socket编程(5)_TCP网络编程实现echo_server
网络·c++·网络协议·tcp/ip·计算机网络·算法
疯狂吧小飞牛2 小时前
openssl颁发包含主题替代名的证书–SAN
运维·服务器·网络
Wang's Blog3 小时前
RocketMQ: Broker 使用指南
服务器·网络·rocketmq
北'辰3 小时前
使用ENSP实现DHCP
运维·网络
丁总学Java4 小时前
netstat -tuln | grep 27017(显示所有监听状态的 TCP 和 UDP 端口,并且以数字形式显示地址和端口号)
网络协议·tcp/ip·udp
黑客K-ing4 小时前
开源网络安全检测工具——伏羲 Fuxi-Scanner
网络·数据库·web安全
网络安全-老纪5 小时前
AWS云安全
网络·云计算·aws
fanxiaohui121385 小时前
浪潮信息自动驾驶框架AutoDRRT 2.0,赋能高阶自动驾驶
运维·服务器·网络·人工智能·机器学习·金融·自动驾驶
老码沉思录5 小时前
Android开发实战班 -网络编程 - Retrofit 网络请求 + OkHttp 使用详解
android·网络·retrofit
Winston Wood5 小时前
一文学习开源框架OkHttp
网络·okhttp