当前位置:   article > 正文

协议crc计算_UDP/IP硬件协议栈设计(五):ARP表

udp asic ip

2c3f000367b76893ce15963a74c73195.png

前面完成了(四)ARP的处理,但是似乎少了点东西,既然说了ARP处理,不顺手再实现一个ARP表不就白来了吗。

ae96a91eab3fe5835e531bdbf2b83a65.png
新建Excel表

为什么要ARP表

如果主机AFPGA发送IP协议的数据,就需要先发送ARP得到FPGA端的MAC地址,而FPGA对其解析后再做相应处理,比如需要再发送IP协议到主机A端,那么是不是得一直保存主机A的MAC地址或者FPGA发送ARP请求帧去请求主机A的MAC地址?

那可不可以主机A先发送的ARP请求帧时,就将其MAC/IP地址的映射存入到RAM当中,当FPGA要发送IP协议的数据时(比如ICMP或者UDP),就直接在RAM中查询主机A的MAC地址,然后再封帧进行发送,这样就省得再发ARP问询了。好,到这个时候,ARP表的功能就出了。

怎么实现?

作为一个MAC/IP地址的映射表,首先就需要确定存入什么样的数据,然后是怎么样将数据存入,最后是怎样取出数据,本文设计采用以下方式:

  1. 待存入MAC/IP地址的选择。只选择缓存ARP的请求帧或者应答帧中发送端(sender)的MAC/IP地址,共10字节;
  2. 存入的方式。为便于查询起见,对待存入的IP地址做HASH计算,得到的结果作为存入RAM的地址,那问题来了,HASH冲突怎么办,问就是没有做!做了这个头又要秃了,有兴趣的可以试试。
  3. 查询接口。对待查询的IP地址同样做HASH计算,计算值作为ARP表的地址,得到相应的MAC/IP地址,待查询的与RAM缓存的IP地址进行比较,若相同则输出MAC地址,不同则输出0。

具体实现过程

  • 获取待更新MAC/IP地址信息

获取ARP报文的各字段信息前文已经说过,本文不再说明。

当Opcode字段为16'h0001或者16'h0002时,则开始更新ARP表:

assign update_arptable_en   =   ((arp_opcode == 16'h0001) || (arp_opcode == 16'h0002))
  • HASH计算

对于采用何种算法完成HASH计算确实是个问题,但是前面在检验一文中提到使用CRC算法,还提了一个在线生成源码的工具,所以本文就直接使用该工具,生成32bit数据位宽的CRC计算模块来实现HASH计算,如下所示,其中nextCRC8_D32即在线生成的function。

  1. wire [7:0] new_crc;
  2. assign new_crc = nextCRC8_D32(calc_data_i,8'hff);
  3. always@(posedge clk or negedge rst_n)begin
  4. if(!rst_n)begin
  5. crc32_o <= 8'h0;
  6. end
  7. else if(calc_en_i) begin
  8. crc32_o <= new_crc;
  9. end
  10. end
  11. always@(posedge clk or negedge rst_n)begin
  12. if(!rst_n)begin
  13. crc32_valid_o <= 1'h0;
  14. end
  15. else begin
  16. crc32_valid_o <= calc_en_i;
  17. end
  18. end
  19. // polynomial: x^8 + x^2 + x^1 + 1
  20. // data width: 32
  21. // convention: the first serial bit is D[31]
  22. function [7:0] nextCRC8_D32;
  23. input [31:0] Data;
  24. input [7:0] crc;
  25. reg [31:0] d;
  26. reg [7:0] c;
  27. reg [7:0] newcrc;
  28. begin
  29. d = Data;
  30. c = crc;
  31. newcrc[0] = d[31] ^ d[30] ^ d[28] ^ d[23] ^ d[21] ^ d[19] ^ d[18] ^ d[16] ^ d[14] ^ d[12] ^ d[8] ^ d[7] ^ d[6] ^ d[0] ^ c[4] ^ c[6] ^ c[7];
  32. newcrc[1] = d[30] ^ d[29] ^ d[28] ^ d[24] ^ d[23] ^ d[22] ^ d[21] ^ d[20] ^ d[18] ^ d[17] ^ d[16] ^ d[15] ^ d[14] ^ d[13] ^ d[12] ^ d[9] ^ d[6] ^ d[1] ^ d[0] ^ c[0] ^ c[4] ^ c[5] ^ c[6];
  33. newcrc[2] = d[29] ^ d[28] ^ d[25] ^ d[24] ^ d[22] ^ d[17] ^ d[15] ^ d[13] ^ d[12] ^ d[10] ^ d[8] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[4] ^ c[5];
  34. newcrc[3] = d[30] ^ d[29] ^ d[26] ^ d[25] ^ d[23] ^ d[18] ^ d[16] ^ d[14] ^ d[13] ^ d[11] ^ d[9] ^ d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[5] ^ c[6];
  35. newcrc[4] = d[31] ^ d[30] ^ d[27] ^ d[26] ^ d[24] ^ d[19] ^ d[17] ^ d[15] ^ d[14] ^ d[12] ^ d[10] ^ d[8] ^ d[4] ^ d[3] ^ d[2] ^ c[0] ^ c[2] ^ c[3] ^ c[6] ^ c[7];
  36. newcrc[5] = d[31] ^ d[28] ^ d[27] ^ d[25] ^ d[20] ^ d[18] ^ d[16] ^ d[15] ^ d[13] ^ d[11] ^ d[9] ^ d[5] ^ d[4] ^ d[3] ^ c[1] ^ c[3] ^ c[4] ^ c[7];
  37. newcrc[6] = d[29] ^ d[28] ^ d[26] ^ d[21] ^ d[19] ^ d[17] ^ d[16] ^ d[14] ^ d[12] ^ d[10] ^ d[6] ^ d[5] ^ d[4] ^ c[2] ^ c[4] ^ c[5];
  38. newcrc[7] = d[30] ^ d[29] ^ d[27] ^ d[22] ^ d[20] ^ d[18] ^ d[17] ^ d[15] ^ d[13] ^ d[11] ^ d[7] ^ d[6] ^ d[5] ^ c[3] ^ c[5] ^ c[6];
  39. nextCRC8_D32 = newcrc;
  40. end
  41. endfunction
  • MAC/IP地址信息存入RAM

对待更新的MAC/IP地址中的IP地址进行HASH计算,得到的8bit的计算结果取低位作为ARP表(RAM)的地址,并将MAC/IP地址信息存入到RAM中,如下所示,使用了一个数据位宽为80bit,深度为2^4=16的双端口RAM作为了ARP表,其中RAM的a端作为更新端,b端作为查询端。

  1. assign arp_table_mem_wea = crc_calc_result_valid;
  2. assign arp_table_mem_addra = crc_calc_result[ARP_TB_W-1:0];
  3. assign arp_table_mem_dina = {arp_sender_ip,arp_sender_mac};
  4. dual_ram#(
  5. .RAM_DW (80), //ram data width
  6. .RAM_DP (ARP_TB_W) //ARP_TB_W取4, ram depth 2^4 = 16
  7. ) U_arp_table_mem(
  8. .rst_n (rst_n),
  9. .clka (clk),
  10. .wea (arp_table_mem_wea),
  11. .addra (arp_table_mem_addra),
  12. .dina (arp_table_mem_dina),
  13. .douta (arp_table_mem_douta),
  14. .clkb (clk),
  15. .web (arp_table_mem_web),
  16. .addrb (arp_table_mem_addrb),
  17. .dinb (arp_table_mem_dinb),
  18. .doutb (arp_table_mem_doutb)
  19. );
  • MAC地址查询

当外部逻辑需要通过IP地址查询MAC地址时,即同样对待查询的IP地址进行HASH计算,将其计算结果的低位作为ARP表(RAM)的b端读取地址,得到的MAC/IP信息后,再与待查询的IP地址进行比较输出,如下所示。

  1. //request IP&MAC mapping
  2. CRC8_D32 U1_CRC8_D32(
  3. .clk (clk),
  4. .rst_n (rst_n),
  5. .calc_data_i (req_ip_i),
  6. .calc_en_i (mac_ip_req_i),
  7. .crc32_o (req_crc_result),
  8. .crc32_valid_o (req_crc_result_valid)
  9. );
  10. assign arp_table_mem_web = 1'b0;
  11. assign arp_table_mem_addrb = req_crc_result[ARP_TB_W-1:0];
  12. assign arp_table_mem_dinb = 80'h0;
  13. dual_ram#(
  14. .RAM_DW (80), //ram data width
  15. .RAM_DP (ARP_TB_W) //ARP_TB_W取4, ram depth 2^4 = 16
  16. ) U_arp_table_mem(
  17. .rst_n (rst_n),
  18. .clka (clk),
  19. .wea (arp_table_mem_wea),
  20. .addra (arp_table_mem_addra),
  21. .dina (arp_table_mem_dina),
  22. .douta (arp_table_mem_douta),
  23. .clkb (clk),
  24. .web (arp_table_mem_web),
  25. .addrb (arp_table_mem_addrb),
  26. .dinb (arp_table_mem_dinb),
  27. .doutb (arp_table_mem_doutb)
  28. );
  29. //output result
  30. always @ (posedge clk or negedge rst_n) begin
  31. if(!rst_n) begin
  32. req_crc_result_valid_r <= 1'b0;
  33. mac_ip_ack_o <= 1'b0;
  34. ack_mac_o <= 48'h0;
  35. end
  36. else begin
  37. req_crc_result_valid_r <= req_crc_result_valid;
  38. mac_ip_ack_o <= req_crc_result_valid_r;
  39. ack_mac_o <= (arp_table_mem_doutb[79:48] == req_ip_i)?arp_table_mem_doutb[47:0]:48'h0;
  40. end
  41. end

以及即完成了ARP表的设计,不过设计中存在的HASH冲突问题并未解决,同时采用CRC8进行HASH计算资源消耗较大,换成简单一点的HASH算法可能更优,有兴趣的可以加以改进。

如有错误之处还望批评指正!


十二点过九分:UDP/IP硬件协议栈设计(六):ICMP​zhuanlan.zhihu.com
7842a632308cc52d798ce3e3e94d61f7.png

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/187168
推荐阅读
相关标签
  

闽ICP备14008679号