Get a full tcp handshake, send data, and close cleanly

This commit is contained in:
Byron Lathi
2024-10-01 21:38:17 -07:00
parent 766fe72daf
commit 7ebbef487b
6 changed files with 149 additions and 41 deletions

View File

@@ -1,4 +1,5 @@
from http import server from http import server
from turtle import xcor
from scapy.layers.inet import Ether, IP, TCP from scapy.layers.inet import Ether, IP, TCP
from scapy.layers.l2 import ARP from scapy.layers.l2 import ARP
from scapy.data import IP_PROTOS from scapy.data import IP_PROTOS
@@ -107,7 +108,7 @@ async def test_irl(dut):
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((tb_ip, 5678)) serversocket.bind((tb_ip, 5678))
serversocket.listen(5) serversocket.listen(1)
t = TunTapInterface('tun0') t = TunTapInterface('tun0')
@@ -176,7 +177,10 @@ async def test_irl(dut):
t.send(ip_packet) t.send(ip_packet)
pkt = t.recv() while True:
pkt = t.recv()
if (pkt.proto == IP_PROTOS.tcp):
break
print(pkt) print(pkt)
tcp_synack = Ether(dst=dut_mac, src=tb_mac) / pkt tcp_synack = Ether(dst=dut_mac, src=tb_mac) / pkt
@@ -206,6 +210,28 @@ async def test_irl(dut):
con, addr = serversocket.accept() con, addr = serversocket.accept()
# Construct a descriptor in memry
tb.axil_ram.write_dword(0x00000000, 0x00001000)
tb.axil_ram.write_dword(0x00000004, 64)
tb.axil_ram.write_dword(0x00000008, 0)
tb.axil_ram.write_dword(0x0000000c, 0)
test_data = bytearray([x % 256 for x in range(256)])
tb.axil_ram.write(0x1000, test_data)
await tb.axil_master.write_dword(0x22c, 0)
await tb.axil_master.write_dword(0x220, 0x00000000)
await tb.axil_master.write_dword(0x224, 0x00000000)
resp = await tb.mii_phy.tx.recv() # type: GmiiFrame
packet = Ether(resp.get_payload())
t.send(packet.payload)
con.recv(64)
tb.log.info("Received 64 packets")
con.close() con.close()
serversocket.close() serversocket.close()
@@ -215,6 +241,18 @@ async def test_irl(dut):
break break
print(pkt) print(pkt)
tcp_ack = Ether(dst=dut_mac, src=tb_mac) / pkt
await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_ack.build()))
tb.log.info("Expecting to send an F here")
while True:
pkt = t.recv()
if (pkt.proto == IP_PROTOS.tcp):
break
print(pkt)
tcp_fin = Ether(dst=dut_mac, src=tb_mac) / pkt tcp_fin = Ether(dst=dut_mac, src=tb_mac) / pkt
await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_fin.build())) await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_fin.build()))
@@ -240,31 +278,16 @@ async def test_irl(dut):
t.send(ip_packet) t.send(ip_packet)
return tb.log.info("Expecting to send last ACK here")
while True:
pkt = t.recv()
if (pkt.proto == IP_PROTOS.tcp):
break
print(pkt)
tcp_fin = Ether(dst=dut_mac, src=tb_mac) / pkt
# Construct a descriptor in memry await tb.mii_phy.rx.send(GmiiFrame.from_payload(tcp_fin.build()))
tb.axil_ram.write_dword(0x00000000, 0x00001000)
tb.axil_ram.write_dword(0x00000004, 64)
tb.axil_ram.write_dword(0x00000008, 0)
tb.axil_ram.write_dword(0x0000000c, 0)
test_data = bytearray([x % 256 for x in range(256)]) await Timer(Decimal(CLK_PERIOD_NS * 1000), units='ns')
tb.axil_ram.write(0x1000, test_data)
await tb.axil_master.write_dword(0x22c, 0)
await tb.axil_master.write_dword(0x220, 0x00000000)
await tb.axil_master.write_dword(0x224, 0x00000000)
resp = await tb.mii_phy.tx.recv() # type: GmiiFrame
packet = Ether(resp.get_payload())
t.send(packet.payload)
# con.recv(64)
serversocket.close()

View File

@@ -4,6 +4,8 @@ module tcp_packet_generator (
axis_intf.SLAVE s_axis_data, axis_intf.SLAVE s_axis_data,
input wire i_no_data,
input wire [15:0] i_ip_len, input wire [15:0] i_ip_len,
input wire [31:0] i_seq_number, input wire [31:0] i_seq_number,
input wire [31:0] i_ack_number, input wire [31:0] i_ack_number,
@@ -21,8 +23,33 @@ module tcp_packet_generator (
ip_intf.MASTER m_ip ip_intf.MASTER m_ip
); );
axis_intf #(.DATA_WIDTH(8)) pre_checksum_data();
axis_intf #(.DATA_WIDTH(8)) post_checksum_data();
logic saf_ready;
assign pre_checksum_data.tdata = s_axis_data.tdata;
assign pre_checksum_data.tkeep = s_axis_data.tkeep;
assign pre_checksum_data.tvalid = s_axis_data.tvalid & saf_ready;
assign s_axis_data.tready = pre_checksum_data.tready & saf_ready;
assign pre_checksum_data.tlast = s_axis_data.tlast;
assign pre_checksum_data.tuser = s_axis_data.tuser;
axis_saf_fifo #(
.DATA_DEPTH_L2(11),
.CTRL_DEPTH_L2(1)
) u_checksum_fifo (
.sclk(i_clk),
.srst(i_rst),
.s_axis(pre_checksum_data),
.mclk(i_clk),
.mrst(i_rst),
.m_axis(post_checksum_data)
);
logic [31:0] counter, counter_next; logic [31:0] counter, counter_next;
enum logic [1:0] {IDLE, HEADER, DATA} state, state_next; enum logic [1:0] {IDLE, DATA_CHECKSUM, HEADER, DATA} state, state_next;
logic [31:0] checksum_counter, checksum_counter_next; logic [31:0] checksum_counter, checksum_counter_next;
@@ -34,7 +61,13 @@ logic checksum_clear;
logic [31:0] checksum_data; logic [31:0] checksum_data;
logic [15:0] checksum_final; logic [15:0] checksum_final;
checksum_calc u_checksum_calc( logic [31:0] data_expand, data_expand_next;
logic data_checksum_enable;
logic data_checksum_clear;
logic [31:0] data_checksum_data;
logic [15:0] data_checksum_final;
checksum_calc u_header_checksum_calc(
.i_rst (i_rst), .i_rst (i_rst),
.i_clk (i_clk), .i_clk (i_clk),
.i_clear (checksum_clear), .i_clear (checksum_clear),
@@ -49,10 +82,12 @@ always_ff @(posedge i_clk) begin
counter <= '0; counter <= '0;
checksum_counter <= '0; checksum_counter <= '0;
state <= IDLE; state <= IDLE;
data_expand <= '0;
end else begin end else begin
counter <= counter_next; counter <= counter_next;
checksum_counter <= checksum_counter_next; checksum_counter <= checksum_counter_next;
state <= state_next; state <= state_next;
data_expand <= data_expand_next;
end end
end end
@@ -64,6 +99,10 @@ always_comb begin
checksum_clear = '0; checksum_clear = '0;
checksum_enable = '0; checksum_enable = '0;
saf_ready = '0;
data_expand_next = data_expand;
case (state) case (state)
IDLE: begin IDLE: begin
@@ -82,7 +121,32 @@ always_comb begin
m_ip.ip_dest_ip = i_dst_ip; m_ip.ip_dest_ip = i_dst_ip;
if (m_ip.ip_hdr_ready) begin if (m_ip.ip_hdr_ready) begin
if (i_no_data) begin
state_next = HEADER;
end else begin
state_next = DATA_CHECKSUM;
end
end
end
end
DATA_CHECKSUM: begin
saf_ready = '1;
data_expand_next = {data_expand[23:0], pre_checksum_data.tdata};
// data_expand_next = {pre_checksum_data.tdata, data_expand[31:8]};
if (checksum_counter[1:0] == '1) begin
checksum_enable = '1;
checksum_data = data_expand_next;
end
if (s_axis_data.tready & s_axis_data.tvalid) begin
checksum_counter_next = checksum_counter + 1;
if (s_axis_data.tlast) begin
state_next = HEADER; state_next = HEADER;
checksum_counter_next = '0;
end end
end end
end end
@@ -97,7 +161,7 @@ always_comb begin
case (checksum_counter) case (checksum_counter)
0: checksum_data = m_ip.ip_source_ip; 0: checksum_data = m_ip.ip_source_ip;
1: checksum_data = m_ip.ip_dest_ip; 1: checksum_data = m_ip.ip_dest_ip;
2: checksum_data = {8'b0, m_ip.ip_protocol, 16'd20}; // tcp length, not IP length 2: checksum_data = {8'b0, m_ip.ip_protocol, (i_ip_len - 16'd20)}; // tcp length, not IP length
3: checksum_data = {i_source_port, i_dest_port}; 3: checksum_data = {i_source_port, i_dest_port};
4: checksum_data = i_seq_number; 4: checksum_data = i_seq_number;
5: checksum_data = i_ack_number; 5: checksum_data = i_ack_number;
@@ -127,7 +191,7 @@ always_comb begin
18: m_ip.ip_payload_axis_tdata = '0; 18: m_ip.ip_payload_axis_tdata = '0;
19: begin 19: begin
m_ip.ip_payload_axis_tdata = '0; m_ip.ip_payload_axis_tdata = '0;
m_ip.ip_payload_axis_tlast = ~s_axis_data.tvalid; // kinda hacky m_ip.ip_payload_axis_tlast = i_no_data; // kinda hacky
end end
endcase endcase
@@ -147,12 +211,12 @@ always_comb begin
DATA: begin DATA: begin
state_next = DATA; state_next = DATA;
s_axis_data.tready = m_ip.ip_payload_axis_tready; post_checksum_data.tready = m_ip.ip_payload_axis_tready;
m_ip.ip_payload_axis_tvalid = s_axis_data.tvalid; m_ip.ip_payload_axis_tvalid = post_checksum_data.tvalid;
m_ip.ip_payload_axis_tdata = s_axis_data.tdata; m_ip.ip_payload_axis_tdata = post_checksum_data.tdata;
m_ip.ip_payload_axis_tlast = s_axis_data.tlast; m_ip.ip_payload_axis_tlast = post_checksum_data.tlast;
if (s_axis_data.tlast && s_axis_data.tvalid && s_axis_data.tready) begin if (post_checksum_data.tlast && post_checksum_data.tvalid && post_checksum_data.tready) begin
state_next = IDLE; state_next = IDLE;
o_packet_done = '1; o_packet_done = '1;
end end

View File

@@ -43,7 +43,13 @@ always_comb begin
o_rx_msg = RX_MSG_RECV_FIN; o_rx_msg = RX_MSG_RECV_FIN;
o_rx_msg_valid = '1; o_rx_msg_valid = '1;
end end
if (i_flags == 8'h10) begin
o_rx_msg = RX_MSG_RECV_ACK;
o_rx_msg_valid = '1;
end
end end
end end
endmodule endmodule

View File

@@ -50,6 +50,7 @@ always_comb begin
tcp_state_next = tcp_state; tcp_state_next = tcp_state;
o_tx_ctrl_valid = '0; o_tx_ctrl_valid = '0;
o_open_clr = '0;
o_tx_ctrl = TX_CTRL_NOP; o_tx_ctrl = TX_CTRL_NOP;
o_tx_ctrl_valid = '0; o_tx_ctrl_valid = '0;
@@ -80,6 +81,7 @@ always_comb begin
if (i_tx_ctrl_ack) begin if (i_tx_ctrl_ack) begin
tcp_state_next = ESTABLISHED; tcp_state_next = ESTABLISHED;
o_open_clr = '1;
end end
end end
@@ -92,9 +94,11 @@ always_comb begin
end end
LAST_ACK: begin LAST_ACK: begin
if (i_rx_msg_valid && i_rx_msg == RX_MSG_RECV_ACK) begin
tcp_state_next = IDLE;
end
end end
endcase endcase
end end
endmodule endmodule

View File

@@ -49,6 +49,8 @@ tcp_pkg::rx_msg_t rx_msg;
logic rx_msg_valid; logic rx_msg_valid;
logic rx_msg_ack; logic rx_msg_ack;
logic w_no_data;
logic [15:0] w_saf_pkt_len; logic [15:0] w_saf_pkt_len;
logic [15:0] w_tx_ip_len; logic [15:0] w_tx_ip_len;
logic [31:0] w_tx_seq_number; logic [31:0] w_tx_seq_number;
@@ -166,6 +168,7 @@ tcp_tx_ctrl u_tcp_tx_ctrl (
.i_tx_ctrl_valid (tx_ctrl_valid), .i_tx_ctrl_valid (tx_ctrl_valid),
.o_tx_ctrl_ack (tx_ctrl_ack), .o_tx_ctrl_ack (tx_ctrl_ack),
.o_no_data (w_no_data),
.o_ip_len (w_tx_ip_len), .o_ip_len (w_tx_ip_len),
.o_seq_number (w_tx_seq_number), .o_seq_number (w_tx_seq_number),
// .o_ack_number (w_tx_ack_number), // .o_ack_number (w_tx_ack_number),
@@ -187,6 +190,7 @@ tcp_packet_generator u_tcp_packet_generator (
.s_axis_data (m_tx_ctrl_axis_data), .s_axis_data (m_tx_ctrl_axis_data),
.i_no_data (w_no_data),
.i_ip_len (w_tx_ip_len), .i_ip_len (w_tx_ip_len),
.i_seq_number (w_tx_seq_number), .i_seq_number (w_tx_seq_number),
.i_ack_number (w_tx_ack_number), .i_ack_number (w_tx_ack_number),
@@ -238,4 +242,4 @@ tcp_rx_ctrl u_tcp_rx_ctrl (
// rx buffer // rx buffer
endmodule endmodule

View File

@@ -8,6 +8,8 @@ module tcp_tx_ctrl(
input logic i_tx_ctrl_valid, input logic i_tx_ctrl_valid,
output logic o_tx_ctrl_ack, output logic o_tx_ctrl_ack,
output logic o_no_data,
output logic [15:0] o_ip_len, output logic [15:0] o_ip_len,
output logic [31:0] o_seq_number, output logic [31:0] o_seq_number,
output logic [31:0] o_ack_number, output logic [31:0] o_ack_number,
@@ -57,10 +59,11 @@ end
always_comb begin always_comb begin
state_next = state; state_next = state;
o_no_data = '0;
o_ack_number = '0; o_ack_number = '0;
o_flags = '0; o_flags = '0;
o_window_size = 16'b1; o_window_size = 16'h100;
o_hdr_valid = '0; o_hdr_valid = '0;
seq_num_next = seq_num; seq_num_next = seq_num;
@@ -86,6 +89,7 @@ always_comb begin
SEND_SYN: begin SEND_SYN: begin
o_flags = FLAG_SYN; o_flags = FLAG_SYN;
o_no_data = '1;
o_hdr_valid = '1; o_hdr_valid = '1;
if (i_packet_done) begin if (i_packet_done) begin
@@ -96,6 +100,7 @@ always_comb begin
SEND_ACK: begin SEND_ACK: begin
o_flags = FLAG_ACK; o_flags = FLAG_ACK;
o_no_data = '1;
o_hdr_valid = '1; o_hdr_valid = '1;
if (i_packet_done) begin if (i_packet_done) begin
@@ -106,6 +111,7 @@ always_comb begin
SEND_DATA: begin SEND_DATA: begin
o_flags = FLAG_ACK | FLAG_PSH; o_flags = FLAG_ACK | FLAG_PSH;
o_no_data = '0;
o_ip_len = 16'd40 + s_axis_len; // default length of IP packet o_ip_len = 16'd40 + s_axis_len; // default length of IP packet
o_hdr_valid = '1; o_hdr_valid = '1;
@@ -117,7 +123,8 @@ always_comb begin
SEND_FIN: begin SEND_FIN: begin
o_flags = FLAG_ACK | FLAG_FIN; o_flags = FLAG_ACK | FLAG_FIN;
o_ip_len = 16'd40 + s_axis_len; // default length of IP packet o_no_data = '1;
o_ip_len = 16'd40; // default length of IP packet
o_hdr_valid = '1; o_hdr_valid = '1;
if (i_packet_done) begin if (i_packet_done) begin