本帖最后由 UT发布 于 2025-4-3 15:34 编辑
软件版本:TD_5.6.4_Release_97693 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 1 巨型帧介绍以太网数据帧的长度为6字节目的MAC地址+6字节源MAC地址+2字节类型+有效载荷+4字节FCS。IEEE802.3协议规定,以太网帧长最小为64字节,最大为1518字节。MTU(Maximum Transmission Unit,最大传输单元)指以太网的有效载荷部分的长度的最大值,为1500字节。 巨型帧(Jumbo Frame)是指MTU超过1500字节的以太网帧,通过分片进行数据传输。只有当传输第一个分片时,需要添加UDP头部,其他分片不添加,这样减少了非数据片段的开销,提高了带宽利用率。但巨型帧也会带来更大的延时,当巨型帧占用网络时,其它协议需要排队等待访问MAC的时间更长,当巨型帧出现错误时,数据重传也需要更长的时间。 在实际使用中,需要相互通讯的两个端口同时支持巨型帧,否则巨型帧会被滤除。 2 巨型帧程序设计
2.1 巨型帧帧格式巨型帧由IP包头部的第7和第8这两个字节控制,其中高3bit为标志字段,低13bit为分片偏移字段。标志字段的功能如下: bit1:保留位,不使用。 bit2:Don`t Fragment,不分片标志,置1时表示不分片,置0时表示分片。 bit3:More Fragment,更多分片标志,置1时表示下一个数据包是巨型帧的一个分片,一般在巨型帧除了最后一个分片的数据包都置1。 分片偏移表示该分片在巨型帧中的位置,由于该字段只有13个bit,而IP和UDP总长度字段有16个bit,所以该字段每加1表示8个字节的数据,比如当一个分片的UDP字段长度为1480时,第1个分片的分片偏移为0,第2个分片的分片偏移为185(1480/8)。 假设一次传输5000字节的数据,巨型帧发送的示意图如下图所示。
巨型帧的处理需要在UDP层和IP层进行。 2.2 发送端设计当开启巨型帧时,如果数据长度小于(IP包有效载荷长度-UDP首部长度),则作为普通帧发送,否则开启巨帧分片。 UDP层例化两个FIFO,1个用于缓存用户端数据,1个用于缓存长度队列,当用户数据写入数据FIFO完成后,再把长度信息写入长度FIFO,用长度FIFO的空信号来判断是否有数据等待发送。 程序中通过状态机控制数据的发送,由于UDP层需要向IP层握手才能发送数据,状态机的控制会有些复杂。状态机的转换图如下图所示。
WAIT_PKG:初始状态,等待需要发送的数据包,当有数据包需要发送时,向IP层发送请求信号,状态机跳转至WAIT_ACK。 WAIT_ACK:等待IP层握手响应,当发送第一包数据时,状态机跳转至PREPARE状态;当发送的不是第一包数据时,判断剩余的数据数量,如果剩余数据量小于最大有效载荷长度,则跳转至LAST_SPLIT状态,否则跳转至MID_SPLIT状态。 PREPARE:通过数据长度判断是否需要分片,需要分片则进入FIRST_SPLIT状态,否则进入SINGLE_PKG状态。 FIRST_SPLIT:发送第一个分片并且封装UDP头部,发送完成后进入WAIT_PAUSE状态。 SINGLE_SPLIT:发送一个完整的普通包,发送完成后进入WAIT_PAUSE状态。 MID_SPLIT:发送不包括第一个和末尾的分片,发送完成后进入WAIT_PAUSE状态。 LAST_SPLIT:发送最后一个分片,发送完成后进入WAIT_PAUSE状态。 WAIT_PAUSE:判断数据是否发送完成,发送完成则进入WAIT_PKG状态,否则继续向IP层发送请求信号,进入WAIT_ACK状态。 UDP层还需将DF标志、MF标志和分片偏移发送到IP层,在封装IP头部和计算IP首部校验时需要用到这些数据。设置了两个顶层参数用来控制巨型帧,JUMBO_ENABLE为巨型帧使能,置1时打开巨型帧,置0时关闭;JUMBO_PACKET为巨帧一个分片的长度。
- `timescale 1ns/1ps
- module uiudp_tx#(
- parameter JUMBO_ENABLE = 1'b1,
- parameter JUMBO_PACKET = 16'd4048
- )
- (
- input wire [15:0] I_udp_local_port, //UDP本地端口
- input wire [15:0] I_udp_dest_port, //UDP目的端口
-
- input wire I_reset,
- input wire I_W_udp_clk, //UDP写数据时钟
- input wire I_W_udp_req, //UDP写请求
- input wire I_W_udp_valid, //UDP写有效
- input wire [7:0] I_W_udp_data, //UDP写数据
- input wire [15:0] I_W_udp_len, //UDP写长度
- output reg O_W_udp_busy, //UDP写忙
-
- input wire I_udp_ip_tbusy, //ip层发送忙
- output reg O_udp_ip_treq, //udp请求发送数据到IP层
- output reg O_udp_ip_tvalid, //udp发送udp包到ip层有效
- output reg [7:0] O_udp_ip_tdata, //udp发送udp包到ip
- output reg [15:0] O_udp_ip_tpkg_len, //udp发送udp包长度
- output wire [15:0] O_udp_ip_flag //3bit flag + 13bit offset
- );
- localparam MAX_FRAME_LEN = JUMBO_PACKET - 8;
- localparam OFFSET = JUMBO_PACKET>>3;
- localparam CHECKSUM = 16'h0000;//假如UDP包不使用校验和功能,校验和部分需全部置0,UDP发送不对校验和计算
- reg [1:0] SWFIFO;
- reg [2:0] SRFIFO;
-
- localparam WAIT_PKG = 2'd0;
- localparam PRE = 2'd1;
- localparam WRITE_FIFO = 2'd2;
-
- localparam WAIT_FIFO = 'd0;
- localparam WAIT_PAUSE = 'd1;
- localparam PREPARE = 'd2;
- localparam FIRST_SPLIT = 'd3;
- localparam MID_SPLIT = 'd4;
- localparam LAST_SPLIT = 'd5;
- localparam SINGLE_PKG = 'd6;
- localparam WAIT_ACK = 'd7;
-
- reg fifo_data_wren ;
- reg [8:0] fifo_data_din ;
- reg fifo_data_rden ;
- wire [8:0] fifo_data_dout ;
- wire fifo_data_full ;
- wire fifo_data_empty ;
- wire [16:0] fifo_data_count ;
-
- reg fifo_info_wren ;
- reg [15:0] fifo_info_din ;
- reg fifo_info_rden ;
- wire [15:0] fifo_info_dout ;
- wire fifo_info_full ;
- wire fifo_info_empty ;
- wire [4:0] fifo_info_count ;
-
- wire udp_send_ready ;
- reg udp_in_valid ;
- reg [7:0] udp_in_data ;
- reg [15:0] udp_in_len ;
- wire udp_in_last ;
-
- reg [15:0] st_cnt ;
- reg [15:0] udp_length ;
- reg split_flag ;
- reg more_fragments ;
- reg [12:0] udp_offset ;
- reg udp_out_last ;
-
- assign udp_send_ready = (fifo_data_count > 'd20000 || fifo_info_count > 'd12) ? 0 : 1;
- assign udp_in_last = udp_in_valid && ~I_W_udp_valid;
- assign O_udp_ip_flag = {1'b0, ~split_flag, more_fragments, udp_offset};
- always @(posedge I_W_udp_clk) begin
- udp_in_valid <= I_W_udp_valid;
- udp_in_data <= I_W_udp_data;
- udp_in_len <= I_W_udp_len;
- end
- always @(posedge I_W_udp_clk) begin
- if(I_reset) begin
- fifo_data_wren <= 1'b0;
- fifo_data_din <= 65'd0;
- fifo_info_wren <= 1'b0;
- fifo_info_din <= 65'd0;
- O_W_udp_busy <= 0;
- SWFIFO <= WAIT_PKG;
- end
- else begin
- case(SWFIFO)
- WAIT_PKG:begin
- if(I_W_udp_req && !O_W_udp_busy && udp_send_ready) begin
- O_W_udp_busy <= 1;
- SWFIFO <= PRE;
- end
- else begin
- fifo_data_wren <= 1'b0;
- fifo_data_din <= 65'd0;
- fifo_info_wren <= 1'b0;
- fifo_info_din <= 65'd0;
- O_W_udp_busy <= 0;
- SWFIFO <= WAIT_PKG;
- end
- end
- PRE:begin
- if(udp_in_valid) begin
- fifo_info_wren <= 1;
- fifo_info_din <= I_W_udp_len;
- fifo_data_wren <= 1;
- fifo_data_din <= {udp_in_last, udp_in_data};
- SWFIFO <= WRITE_FIFO;
- end
- end
- WRITE_FIFO:begin
- fifo_info_wren <= 0;
- fifo_info_din <= 0;
- fifo_data_wren <= 1;
- fifo_data_din <= {udp_in_last, udp_in_data};
- if(udp_in_valid && ~I_W_udp_valid) begin
- O_W_udp_busy <= 0;
- SWFIFO <= WAIT_PKG;
- end
- end
- default:begin
- fifo_data_wren <= 1'b0;
- fifo_data_din <= 65'd0;
- fifo_info_wren <= 1'b0;
- fifo_info_din <= 65'd0;
- O_W_udp_busy <= 0;
- SWFIFO <= WAIT_PKG;
- end
- endcase
- end
- end
- udp_data_fifo udp_data_fifo
- (
- .clk (I_W_udp_clk),
- .srst (I_reset),
- .din (fifo_data_din),
- .wr_en (fifo_data_wren),
- .rd_en (fifo_data_rden),
- .dout (fifo_data_dout),
- .full (fifo_data_full),
- .empty (fifo_data_empty),
- .data_count (fifo_data_count)
- );
- udp_info_fifo udp_info_fifo
- (
- .clk (I_W_udp_clk),
- .srst (I_reset),
- .din (fifo_info_din),
- .wr_en (fifo_info_wren),
- .rd_en (fifo_info_rden),
- .dout (fifo_info_dout),
- .full (fifo_info_full),
- .empty (fifo_info_empty),
- .data_count (fifo_info_count)
- );
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- st_cnt <= 0;
- else if(SRFIFO == WAIT_PKG)
- st_cnt <= 0;
- else if(SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG || SRFIFO == MID_SPLIT || SRFIFO == LAST_SPLIT)
- st_cnt <= st_cnt + 1;
- else
- st_cnt <= 0;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- SRFIFO <= WAIT_PKG;
- else begin
- case(SRFIFO)
- WAIT_PKG:begin
- if(!fifo_info_empty && !I_udp_ip_tbusy)
- SRFIFO <= WAIT_ACK;
- else
- SRFIFO <= WAIT_PKG;
- end
- WAIT_PAUSE:begin
- if(!split_flag)
- SRFIFO <= WAIT_PKG;
- else if(!I_udp_ip_tbusy && split_flag)
- SRFIFO <= WAIT_ACK;
- else
- SRFIFO <= WAIT_PAUSE;
- end
- WAIT_ACK:begin
- if(I_udp_ip_tbusy)
- if(!split_flag)
- SRFIFO <= PREPARE;
- else if((udp_offset + OFFSET) > (udp_length >> 3))
- SRFIFO <= LAST_SPLIT;
- else
- SRFIFO <= MID_SPLIT;
- else
- SRFIFO <= WAIT_ACK;
- end
- PREPARE:begin
- if(fifo_info_dout > MAX_FRAME_LEN && JUMBO_ENABLE)
- SRFIFO <= FIRST_SPLIT;
- else
- SRFIFO <= SINGLE_PKG;
- end
- FIRST_SPLIT, MID_SPLIT, LAST_SPLIT, SINGLE_PKG:begin
- if(udp_out_last)
- SRFIFO <= WAIT_PAUSE;
- else
- SRFIFO <= SRFIFO;
- end
- default:begin
- SRFIFO <= WAIT_PKG;
- end
- endcase
- end
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- O_udp_ip_treq <= 0;
- else if(I_udp_ip_tbusy)
- O_udp_ip_treq <= 0;
- else if(SRFIFO == WAIT_PAUSE && !I_udp_ip_tbusy && split_flag)
- O_udp_ip_treq <= 1;
- else if(SRFIFO == WAIT_PKG && !fifo_info_empty && !I_udp_ip_tbusy)
- O_udp_ip_treq <= 1;
- else
- O_udp_ip_treq <= O_udp_ip_treq;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- fifo_info_rden <= 0;
- else if(SRFIFO == WAIT_PKG && !fifo_info_empty && !I_udp_ip_tbusy)
- fifo_info_rden <= 1;
- else
- fifo_info_rden <= 0;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- fifo_data_rden <= 0;
- else if(fifo_data_dout[8] && fifo_data_rden)
- fifo_data_rden <= 0;
- else if(st_cnt == JUMBO_PACKET && JUMBO_ENABLE)
- fifo_data_rden <= 0;
- else if((SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG) && st_cnt == 'd8)
- fifo_data_rden <= 1;
- else if((SRFIFO == MID_SPLIT || SRFIFO == LAST_SPLIT) && st_cnt == 'd0)
- fifo_data_rden <= 1;
- else
- fifo_data_rden <= fifo_data_rden;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- udp_length <= 0;
- else if(SRFIFO == PREPARE)
- udp_length <= fifo_info_dout + 16'd8;
- else
- udp_length <= udp_length;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- split_flag <= 0;
- else if(SRFIFO == LAST_SPLIT && udp_out_last)
- split_flag <= 0;
- else if(SRFIFO == PREPARE && fifo_info_dout > MAX_FRAME_LEN && JUMBO_ENABLE)
- split_flag <= 1;
- else
- split_flag <= split_flag;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- more_fragments <= 0;
- else if(SRFIFO == FIRST_SPLIT || SRFIFO == MID_SPLIT)
- more_fragments <= 1;
- else
- more_fragments <= 0;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- udp_out_last <= 0;
- else if(fifo_data_dout[8] && fifo_data_rden)
- udp_out_last <= 1;
- else if(st_cnt == JUMBO_PACKET && JUMBO_ENABLE)
- udp_out_last <= 1;
- else
- udp_out_last <= 0;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- O_udp_ip_tdata <= 0;
- else if(SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG)
- case(st_cnt)
- 1 :O_udp_ip_tdata <= I_udp_local_port[15:8];
- 2 :O_udp_ip_tdata <= I_udp_local_port[7:0];
- 3 :O_udp_ip_tdata <= I_udp_dest_port[15:8];
- 4 :O_udp_ip_tdata <= I_udp_dest_port[7:0];
- 5 :O_udp_ip_tdata <= udp_length[15:8];
- 6 :O_udp_ip_tdata <= udp_length[7:0];
- 7 :O_udp_ip_tdata <= CHECKSUM[15:8];
- 8 :O_udp_ip_tdata <= CHECKSUM[7:0];
- default :O_udp_ip_tdata <= fifo_data_dout[7:0];
- endcase
- else
- O_udp_ip_tdata <= fifo_data_dout[7:0];
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- O_udp_ip_tvalid <= 0;
- else if(udp_out_last)
- O_udp_ip_tvalid <= 0;
- else if(SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG || SRFIFO == MID_SPLIT || SRFIFO == LAST_SPLIT)
- O_udp_ip_tvalid <= st_cnt > 0;
- else
- O_udp_ip_tvalid <= O_udp_ip_tvalid;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- O_udp_ip_tpkg_len <= 0;
- else if(fifo_info_rden)
- O_udp_ip_tpkg_len <= JUMBO_ENABLE ? fifo_info_dout > MAX_FRAME_LEN ? JUMBO_PACKET : fifo_info_dout + 8 : fifo_info_dout + 8;
- else if(SRFIFO == WAIT_PAUSE && (udp_offset + OFFSET) > (udp_length >> 3))
- O_udp_ip_tpkg_len <= udp_length - (udp_offset << 3);
- else if(SRFIFO == WAIT_PAUSE )
- O_udp_ip_tpkg_len <= JUMBO_PACKET;
- else
- O_udp_ip_tpkg_len <= O_udp_ip_tpkg_len;
- end
- always@(posedge I_W_udp_clk) begin
- if(I_reset)
- udp_offset <= 0;
- else if(SRFIFO == WAIT_PKG)
- udp_offset <= 0;
- else if(SRFIFO != LAST_SPLIT && udp_out_last && O_udp_ip_tvalid)
- udp_offset <= udp_offset + OFFSET;
- else
- udp_offset <= udp_offset;
- end
-
- endmodule
复制代码
2.3 接收端设计首先在IP层把IP包头的MF标志解析出来,发送到UDP层用于判断数据包是否为分片,如果是分片,则继续将下一个数据包写入FIFO,等待全部数据包写入FIFO完成后,再将完整的有效数据段读出。 - module uiudp_rx
- (
- input wire I_reset,
- input wire I_R_udp_clk, //udp接收时钟,和ip_layer接收的数据时钟相同
- output reg O_R_udp_valid, //输出到用户层udp读数据有效
- output reg [7:0] O_R_udp_data, //输出到用户层udp数据
- output reg [15:0] O_R_udp_len, //输出到用户层读udp数据长度
- output reg [15:0] O_R_udp_src_port, //输出到用户层接收到的UDP数据包的端口号
-
- input wire I_udp_ip_rvalid, //udp接收来自ip层的数据有效信号
- input wire [7:0] I_udp_ip_rdata, //udp接收来自ip层数据
- input wire I_udp_ip_rmf
- );
- reg fifo_data_rden;
- wire [8:0] fifo_data_dout;
- wire fifo_data_full;
- wire fifo_data_empty;
- wire [16:0] fifo_data_count;
-
- reg fifo_info_rden;
- wire [15:0] fifo_info_dout;
- wire fifo_info_full;
- wire fifo_info_empty;
- wire [4:0] fifo_info_count;
-
- reg rec_data_valid;
- reg [7:0] rec_data;
- reg rec_data_mf;//打拍信号
-
- reg [15:0] rx_length;
- reg info_lock;
- reg [15:0] rx_cnt;
- reg [15:0] fifo_cnt;
- reg [15:0] udp_pkg_len;
- reg [15:0] udp_length;
- always@(posedge I_R_udp_clk) begin
- rec_data_valid <= I_udp_ip_rvalid;
- rec_data <= I_udp_ip_rdata;
- rec_data_mf <= I_udp_ip_rmf;
- end
- udp_data_fifo udp_data_fifo
- (
- .clk (I_R_udp_clk),
- .srst (I_reset),
- .din ({1'b0, I_udp_ip_rdata}),
- .wr_en (I_udp_ip_rvalid),
- .rd_en (fifo_data_rden),
- .dout (fifo_data_dout),
- .full (fifo_data_full),
- .empty (fifo_data_empty),
- .data_count (fifo_data_count)
- );
- udp_info_fifo udp_info_fifo
- (
- .clk (I_R_udp_clk),
- .srst (I_reset),
- .din (rx_length),
- .wr_en (rec_data_valid && ~I_udp_ip_rvalid && ~rec_data_mf),
- .rd_en (fifo_info_rden),
- .dout (fifo_info_dout),
- .full (fifo_info_full),
- .empty (fifo_info_empty),
- .data_count (fifo_info_count)
- );
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- fifo_cnt <= 0;
- else if(I_udp_ip_rvalid)
- fifo_cnt <= fifo_cnt + 1;
- else
- fifo_cnt <= 0;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- info_lock <= 0;
- else if(fifo_cnt == 6)
- info_lock <= I_udp_ip_rmf ? 1 : 0;
- else
- info_lock <= info_lock;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- rx_length <= 0;
- else if((fifo_cnt == 4 || fifo_cnt == 5) && !info_lock)
- rx_length <= {rx_length[7:0], I_udp_ip_rdata[7:0]};
- else
- rx_length <= rx_length;
- end
-
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- udp_length <= 0;
- else if(fifo_info_rden)
- udp_length <= fifo_info_dout < 26 ? 26 : fifo_info_dout;
- else
- udp_length <= udp_length;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- udp_pkg_len <= 0;
- else if(fifo_info_rden)
- udp_pkg_len <= fifo_info_dout;
- else
- udp_pkg_len <= udp_pkg_len;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- fifo_info_rden <= 0;
- else if(fifo_info_rden || fifo_data_rden)
- fifo_info_rden <= 0;
- else if(!fifo_info_empty)
- fifo_info_rden <= 1;
- else
- fifo_info_rden <= 0;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- fifo_data_rden <= 0;
- else if(rx_cnt == udp_length - 1)
- fifo_data_rden <= 0;
- else if(fifo_info_rden)
- fifo_data_rden <= 1;
- else
- fifo_data_rden <= fifo_data_rden;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- rx_cnt <= 0;
- else if(fifo_data_rden)
- rx_cnt <= rx_cnt + 1;
- else
- rx_cnt <= 0;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- O_R_udp_valid <= 0;
- else if(rx_cnt > 7 && rx_cnt < udp_pkg_len)
- O_R_udp_valid <= 1;
- else
- O_R_udp_valid <= 0;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- O_R_udp_data <= 0;
- else if(rx_cnt > 7 && rx_cnt < udp_pkg_len)
- O_R_udp_data <= fifo_data_dout[7:0];
- else
- O_R_udp_data <= 0;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- O_R_udp_len <= 0;
- else if(fifo_info_rden)
- O_R_udp_len <= fifo_info_dout - 8;
- else
- O_R_udp_len <= O_R_udp_len;
- end
- always@(posedge I_R_udp_clk or posedge I_reset) begin
- if(I_reset)
- O_R_udp_src_port <= 0;
- else if(fifo_data_rden && (rx_cnt == 0 || rx_cnt == 1))
- O_R_udp_src_port <= {O_R_udp_src_port[7:0], fifo_data_dout[7:0]};
- else
- O_R_udp_src_port <= O_R_udp_src_port;
- end
- endmodule
复制代码
3 巨型帧验证3.1 仿真验证
首先对设计完成的uiudp_tx模块进行仿真验证,设置JUMBO_ENABLE为1,JUMBO_PACKET为1480,用户端持续发送一段长度为5000字节的测试数据,仿真波形图如下图所示。
该数据被分成了4个分片依次发送出去,前3个分片的UDP长度为1480,最后1个分片的UDP长度为568,则数据发送的长度正确(1480*3+568-8=5000)。标志位分别为3’b001、3’b001、3’b001、3’b000,标志位都正确。偏移量的计算为(片偏移字段*8),则偏移量分别为0、1480、2960、4440,偏移量都正确。 将发送端发送的巨型帧通过MAC回环进接收端,uiudp_rx模块的仿真波形图如下图所示。 IP层解析出MF信号用于UDP层判断数据是独立的还是巨帧分片,当4个巨帧分片都写入FIFO后,将FIFO中的数据读出重组成为完整的5000字节的数据流。 3.2上板验证首先在电脑“设备管理器”中展开“网络适配器”选项,找到自己的网卡,双击进入设置。
在高级选项卡中,找到巨型帧选项开启,不同厂家设置的传输单元大小可能有所不同,本次验证选择4088Bytes。
首先使用网络调试助手发送一个巨型帧,通过wireshark软件抓取。
可以抓到每一帧的长度为4082,则JUMBO_FRAME的参数设置为4048(4082-20(IP首部)-14(MAC首部))。将程序下载进开发板中,首先通过ping包测试网络是否通畅。
接着通过网络调试助手进行回环测试。
可以看到收发数据量一致,并且环回的数据正确。通过wireshark抓取的数据包如下图所示,红框为电脑向开发板发送的巨帧分片,在最后一个分片时重组成为巨型帧。
在网络调试助手发送64000字节长度的数据,验证巨型帧最大帧长。网络调试助手接收到的数据如下图所示。
wireshark抓取的数据如下图所示。
|