【以太网通信】FPGA 实现 IP 协议的校验

使用 FPGA 实现以太网通信时,需要计算 IP 首部的校验和。本文给出了一种计算 IP 数据报校验和的 HDL 实现方法。

目录

1 IP 协议

2 校验过程

3 HDL 描述


1 IP 协议

        TCP/IP 协议是 TCP、UDP 和 IP 等协议构成的协议簇,作为网络信息传输的规范。在 OSI 网络模型中,TCP 和 UDP 协议由传输层处理,IP 协议由网络层处理。

        在网络层中,数据以 IP 数据报为单位进行传输。每一个 IP 数据报都由 IP 首部和报文数据两部分组成,其中 IP 首部至少包括 20 个字节,这 20 个字节的含义如下:

2 校验过程

        IP 数据报只对首部进行校验,发送数据时,按照以下步骤计算 IP 校验和:

(1)把 IP 首部的校验和字段置为 0x0000;

(2)将首部按照 16bit 为字长进行二进制反码求和;

(3)将校验和填充到 IP 首部中。

        接收数据时,校验数据的步骤为:

(1)将首部(包括校验和)按照 16bit 为字长进行二进制反码求和;

(2)判断计算结果是否等于零;

(3)如果校验和为零,则校验通过;否则,校验失败,丢弃该报文。

3 HDL 描述

VHDL 版本

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity validate_ip is
   port(
      -- System level
      sys_rst        : in std_logic;
      sys_clk        : in std_logic;
		
      -- IP information
      ip_packet_len  : in std_logic_vector(2*8-1 downto 0);
      identify_code  : in std_logic_vector(2*8-1 downto 0);
      local_ip_addr  : in std_logic_vector(4*8-1 downto 0);
      remote_ip_addr : in std_logic_vector(4*8-1 downto 0);
		
      -- IP checksum output
      ip_checksum_o  : out std_logic_vector(2*8-1 downto 0)
   );
end entity;
architecture behav of validate_ip is
   -- internal signal declarations
   subtype word is std_logic_vector(15 downto 0);
   type check_info_t is array(0 to 9) of word;
   signal ip_check_info: check_info_t;
   signal ip_checksum: std_logic_vector(2*8-1 downto 0);
begin
   -- todo
   process(sys_rst,sys_clk)
   begin
      if sys_rst = '1' then
         ip_check_info <= (others => (others => '0'));
      elsif rising_edge(sys_clk) then
         ip_check_info(0) <= X"4500";  -- IPv4, IP head 20 Bytes
         ip_check_info(1) <= ip_packet_len;
         ip_check_info(2) <= identify_code;
         ip_check_info(3) <= X"4000";  -- Don't Fragment, shift 0
         ip_check_info(4) <= X"4011";  -- TTL, 64ms, UDP protocol
         ip_check_info(5) <= X"0000";  -- IP checksum bytes padding
         ip_check_info(6) <= local_ip_addr(4*8-1 downto 2*8);
         ip_check_info(7) <= local_ip_addr(2*8-1 downto 0*8);
         ip_check_info(8) <= remote_ip_addr(4*8-1 downto 2*8);
         ip_check_info(9) <= remote_ip_addr(2*8-1 downto 0*8);
      end if;
   end process;

   process(ip_check_info)
      variable tmp: std_logic_vector(31 downto 0);
   begin
      tmp := (others => '0');
      for i in 0 to 9 loop
         tmp := tmp + ip_check_info(i);
      end loop;
      ip_checksum <= not (tmp(15 downto 0) + tmp(31 downto 16));
   end process;

   process(sys_rst,sys_clk)
   begin
      if sys_rst = '1' then
         ip_checksum_o <= (others => '0');
      elsif rising_edge(sys_clk) then
         ip_checksum_o <= ip_checksum;
      end if;
  end process;
end architecture;

Verilog 版本

`timescale 1ns / 1ps

module validate_ip(
   // System level
   sys_rst,
   sys_clk,
	
   // IP packet info
   ip_packet_len,
   identify_code,
   local_ip_addr,
   remote_ip_addr,
	
   // IP checksum output
   ip_checksum_o
);

   // I/O port declarations
   input            sys_rst;
   input            sys_clk;
   input  [2*8-1:0] ip_packet_len;
   input  [2*8-1:0] identify_code;
   input  [4*8-1:0] local_ip_addr;
   input  [4*8-1:0] remote_ip_addr;
   output [2*8-1:0] ip_checksum_o;
   reg    [2*8-1:0] ip_checksum_o;

   // internal signal declarations
   reg [2*8-1:0] ip_check_info[9:0];
   reg [2*8-1:0] ip_checksum;
   reg [4*8-1:0] tmp;
  
   integer i;
  
   always@(posedge sys_rst or posedge sys_clk) begin
      if(sys_rst)
         for(i = 0; i < 10; i=i+1) begin
            ip_check_info[i] <= 16'h0000;
		 end
      else begin
         ip_check_info[0] <= 16'h4500;  // Ipv4, IP head 20 Bytes
         ip_check_info[1] <= ip_packet_len;
         ip_check_info[2] <= identify_code;
         ip_check_info[3] <= 16'h4000;  // Don't Fragment, shift 0
         ip_check_info[4] <= 16'h4011;  // TTL 64ms, UDP protocol
         ip_check_info[5] <= 16'h0000;  // IP checksum bytes padding
         ip_check_info[6] <= local_ip_addr[4*8-1:2*8];
         ip_check_info[7] <= local_ip_addr[2*8-1:0*8];
         ip_check_info[8] <= remote_ip_addr[4*8-1:2*8];
         ip_check_info[9] <= remote_ip_addr[2*8-1:0*8];
      end
   end
  
   always@(*) begin
      tmp = 32'd0;
      for(i = 0; i < 10; i=i+1) begin
	     tmp = tmp + ip_check_info[i];
	  end
	  ip_checksum = ~(tmp[31:16] + tmp[16:0]);
   end
  
   always@(posedge sys_rst or posedge sys_clk) begin
      if(sys_rst)
	     ip_checksum_o <= 16'd0;
	  else
	     ip_checksum_o <= ip_checksum;
   end
endmodule

        综合得到的 RTL 电路图如下:

        上述综合结果加法器的路径比较长,如果对时序的要求比较严格,可以考虑采用树形结构电路优化,但是会消耗更多的寄存器资源。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洋洋Young

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值