diff options
author | Anton Kling <anton@kling.gg> | 2024-10-06 11:12:16 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-10-06 11:12:16 +0200 |
commit | f18beba3cb3d85ed6e0f44fdff9256c50adcc5e1 (patch) | |
tree | 42e15026c9a0154269e5c7de71cd829866d6d564 | |
parent | 6dc2637972f93dea8cc831d7ee225daefb74b8ab (diff) |
Kernel/Networking: Modify outgoing packet in place
This avoids creation of new buffers and unnecessary memcpys. The old
interface still exists for UDP but will be removed when I am less lazy.
From testing it does not appear to have any performance improvement but
this is most likely due to other bottlenecks as extra copies should
always be worse.
-rw-r--r-- | kernel/drivers/rtl8139.c | 18 | ||||
-rw-r--r-- | kernel/drivers/rtl8139.h | 2 | ||||
-rw-r--r-- | kernel/network/ethernet.c | 27 | ||||
-rw-r--r-- | kernel/network/ethernet.h | 10 | ||||
-rw-r--r-- | kernel/network/ipv4.c | 32 | ||||
-rw-r--r-- | kernel/network/ipv4.h | 1 | ||||
-rw-r--r-- | kernel/network/tcp.c | 90 |
7 files changed, 126 insertions, 54 deletions
diff --git a/kernel/drivers/rtl8139.c b/kernel/drivers/rtl8139.c index 669cb6c..946c405 100644 --- a/kernel/drivers/rtl8139.c +++ b/kernel/drivers/rtl8139.c @@ -111,6 +111,24 @@ void rtl8139_handler(void *regs) { EOI(0xB); } +u8 *nic_get_buffer(void) { + if (send_buffers_loop > 3) { + send_buffers_loop = 0; + } + return send_buffers[send_buffers_loop]; +} + +void nic_send_buffer(u16 data_size) { + const struct PCI_DEVICE *device = &rtl8139; + outl(device->gen.base_mem_io + 0x20 + send_buffers_loop * 4, + (u32)virtual_to_physical(send_buffers[send_buffers_loop], NULL)); + outl(device->gen.base_mem_io + 0x10 + send_buffers_loop * 4, data_size); + send_buffers_loop += 1; + if (send_buffers_loop > 3) { + send_buffers_loop = 0; + } +} + void rtl8139_send_data(u8 *data, u16 data_size) { if (data_size > 0x1000) { rtl8139_send_data(data, 0x1000); diff --git a/kernel/drivers/rtl8139.h b/kernel/drivers/rtl8139.h index c61e6de..ebefd77 100644 --- a/kernel/drivers/rtl8139.h +++ b/kernel/drivers/rtl8139.h @@ -2,3 +2,5 @@ void get_mac_address(u8 mac[6]); void rtl8139_init(void); void rtl8139_send_data(u8 *data, u16 data_size); +u8 *nic_get_buffer(void); +void nic_send_buffer(u16 data_size); diff --git a/kernel/network/ethernet.c b/kernel/network/ethernet.c index dbd1b6d..fd385b3 100644 --- a/kernel/network/ethernet.c +++ b/kernel/network/ethernet.c @@ -9,12 +9,6 @@ #include <stdio.h> #include <string.h> -struct EthernetHeader { - u8 mac_dst[6]; - u8 mac_src[6]; - u16 type; -}; - u32 crc32(const char *buf, size_t len) { static u32 table[256]; static int have_table = 0; @@ -68,6 +62,27 @@ void handle_ethernet(const u8 *packet, u64 packet_length) { } } +void send_ethernet_packet2(u8 mac_dst[6], u16 type, u64 payload_length) { + u64 buffer_size = + sizeof(struct EthernetHeader) + payload_length + sizeof(u32); + assert(buffer_size < 0x1000); + + u8 *buffer = nic_get_buffer(); + struct EthernetHeader *eth_header = (struct EthernetHeader *)buffer; + memset(eth_header, 0, sizeof(struct EthernetHeader)); + buffer += sizeof(struct EthernetHeader); + buffer += payload_length; + + memcpy(eth_header->mac_dst, mac_dst, sizeof(u8[6])); + get_mac_address(eth_header->mac_src); + eth_header->type = htons(type); + *(u32 *)(buffer) = + htonl(crc32((const char *)nic_get_buffer(), buffer_size - 4)); + + nic_send_buffer(buffer_size); + // rtl8139_send_data(ethernet_buffer, buffer_size); +} + u8 ethernet_buffer[0x1000]; void send_ethernet_packet(u8 mac_dst[6], u16 type, u8 *payload, u64 payload_length) { diff --git a/kernel/network/ethernet.h b/kernel/network/ethernet.h index ffb7893..6534a64 100644 --- a/kernel/network/ethernet.h +++ b/kernel/network/ethernet.h @@ -1,5 +1,15 @@ +#ifndef ETHERNET_H +#define ETHERNET_H #include <typedefs.h> +struct EthernetHeader { + u8 mac_dst[6]; + u8 mac_src[6]; + u16 type; +}; + void handle_ethernet(const u8 *packet, u64 packet_length); +void send_ethernet_packet2(u8 mac_dst[6], u16 type, u64 payload_length); void send_ethernet_packet(u8 mac_dst[6], u16 type, u8 *payload, u64 payload_length); +#endif // ETHERNET_H diff --git a/kernel/network/ipv4.c b/kernel/network/ipv4.c index 6074141..de6984a 100644 --- a/kernel/network/ipv4.c +++ b/kernel/network/ipv4.c @@ -1,5 +1,6 @@ #include <assert.h> #include <drivers/pit.h> +#include <drivers/rtl8139.h> #include <kmalloc.h> #include <network/arp.h> #include <network/bytes.h> @@ -26,6 +27,37 @@ static u16 ip_checksum(const u16 *data, u16 length) { return htons(~acc); } +void send_ipv4_packet2(ipv4_t ip, u8 protocol, u16 length) { + u16 header[10]; + header[0] = (4 /*version*/ << 4) | (5 /*IHL*/); + + header[1] = htons(length + 20); + + header[2] = 0; + + header[3] = 0; + header[4] = (protocol << 8) | 0xF8; + + header[5] = 0; + header[6] = (ip_address.d >> 0) & 0xFFFF; + header[7] = (ip_address.d >> 16) & 0xFFFF; + + header[8] = (ip.d >> 0) & 0xFFFF; + header[9] = (ip.d >> 16) & 0xFFFF; + + header[5] = ip_checksum(header, 20); + u16 packet_length = length + 20; + // TODO + // assert(packet_length < sizeof(ipv4_buffer)); + u8 *packet = nic_get_buffer() + sizeof(struct EthernetHeader); + memcpy(packet, header, 20); + + u8 mac[6]; + for (; !get_mac_from_ip(ip, mac);) + ; + send_ethernet_packet2(mac, 0x0800, packet_length); +} + u8 ipv4_buffer[0x1000]; void send_ipv4_packet(ipv4_t ip, u8 protocol, const u8 *payload, u16 length) { u16 header[10]; diff --git a/kernel/network/ipv4.h b/kernel/network/ipv4.h index 7b44eb1..4d19ae9 100644 --- a/kernel/network/ipv4.h +++ b/kernel/network/ipv4.h @@ -2,3 +2,4 @@ void handle_ipv4(const u8 *payload, u32 packet_length); void send_ipv4_packet(ipv4_t ip, u8 protocol, const u8 *payload, u16 length); +void send_ipv4_packet2(ipv4_t ip, u8 protocol, u16 length); diff --git a/kernel/network/tcp.c b/kernel/network/tcp.c index 8717250..e608f6c 100644 --- a/kernel/network/tcp.c +++ b/kernel/network/tcp.c @@ -1,11 +1,13 @@ #include <assert.h> #include <cpu/arch_inst.h> #include <drivers/pit.h> +#include <drivers/rtl8139.h> #include <fs/vfs.h> #include <interrupts.h> #include <math.h> #include <network/arp.h> #include <network/bytes.h> +#include <network/ethernet.h> #include <network/ipv4.h> #include <network/tcp.h> #include <network/udp.h> @@ -82,43 +84,37 @@ u16 tcp_calculate_checksum(ipv4_t src_ip, u32 dst_ip, const u8 *payload, return htons(tcp_checksum_final(tmp, payload, payload_length)); } -static void tcp_send(struct TcpConnection *con, u8 *buffer, u16 length, - u32 seq_num, u32 payload_length) { - send_ipv4_packet((ipv4_t){.d = con->outgoing_ip}, 6, buffer, length); +static u8 *tcp_get_buffer(void) { + u8 *nb = nic_get_buffer(); + return nb + sizeof(struct EthernetHeader) + sizeof(u16[10]); } -u8 tcp_buffer[0x1000]; void tcp_send_empty_payload(struct TcpConnection *con, u8 flags) { - struct TcpHeader header; - memset(&header, 0, sizeof(header)); - header.src_port = htons(con->incoming_port); - header.dst_port = htons(con->outgoing_port); - header.seq_num = htonl(con->snd_nxt); + struct TcpHeader *header = (struct TcpHeader *)tcp_get_buffer(); + memset(header, 0, sizeof(struct TcpHeader)); + header->src_port = htons(con->incoming_port); + header->dst_port = htons(con->outgoing_port); + header->seq_num = htonl(con->snd_nxt); if (flags & ACK) { con->should_send_ack = 0; - header.ack_num = htonl(con->rcv_nxt); + header->ack_num = htonl(con->rcv_nxt); } else { - header.ack_num = 0; + header->ack_num = 0; } - header.data_offset = 5; - header.reserved = 0; - header.flags = flags; - header.window_size = htons(con->rcv_wnd); - header.urgent_pointer = 0; + header->data_offset = 5; + header->reserved = 0; + header->flags = flags; + header->window_size = htons(con->rcv_wnd); + header->urgent_pointer = 0; u8 payload[] = {0}; u16 payload_length = 0; - header.checksum = tcp_calculate_checksum( - ip_address, con->outgoing_ip, (const u8 *)payload, payload_length, - &header, sizeof(struct TcpHeader) + payload_length); - u32 send_len = sizeof(header) + payload_length; + header->checksum = tcp_calculate_checksum( + ip_address, con->outgoing_ip, (const u8 *)payload, payload_length, header, + sizeof(struct TcpHeader) + payload_length); + u32 send_len = sizeof(struct TcpHeader) + payload_length; - assert(send_len < sizeof(tcp_buffer)); - u8 *send_buffer = tcp_buffer; - memcpy(send_buffer, &header, sizeof(header)); - memcpy(send_buffer + sizeof(header), payload, payload_length); - - tcp_send(con, send_buffer, send_len, con->snd_nxt, 0); + send_ipv4_packet2((ipv4_t){.d = con->outgoing_ip}, 6, send_len); con->snd_nxt += (flags & SYN) ? 1 : 0; con->snd_nxt += (flags & FIN) ? 1 : 0; @@ -144,7 +140,7 @@ void tcp_close_connection(struct TcpConnection *con) { // FIXME: // Book says it should be FIN but observed network traffic says it // should be FIN|ACK? - tcp_send_empty_payload(con, FIN); + tcp_send_empty_payload(con, FIN | ACK); con->state = TCP_STATE_FIN_WAIT1; return; } @@ -181,30 +177,28 @@ int send_tcp_packet(struct TcpConnection *con, const u8 *payload, payload += len; return send_tcp_packet(con, payload, payload_length); } - struct TcpHeader header = {0}; - header.src_port = htons(con->incoming_port); - header.dst_port = htons(con->outgoing_port); - header.seq_num = htonl(con->snd_nxt); - header.ack_num = htonl(con->rcv_nxt); - header.data_offset = 5; - header.reserved = 0; - header.flags = PSH | ACK; - header.window_size = htons(con->rcv_wnd); - header.urgent_pointer = 0; - header.checksum = tcp_calculate_checksum( - ip_address, con->outgoing_ip, (const u8 *)payload, payload_length, - &header, sizeof(struct TcpHeader) + payload_length); - u32 send_len = sizeof(header) + payload_length; - assert(send_len < sizeof(tcp_buffer)); - u8 *send_buffer = tcp_buffer; - memcpy(send_buffer, &header, sizeof(header)); - memcpy(send_buffer + sizeof(header), payload, payload_length); - - if (header.flags & ACK) { + struct TcpHeader *header = (struct TcpHeader *)tcp_get_buffer(); + header->src_port = htons(con->incoming_port); + header->dst_port = htons(con->outgoing_port); + header->seq_num = htonl(con->snd_nxt); + header->ack_num = htonl(con->rcv_nxt); + header->data_offset = 5; + header->reserved = 0; + header->flags = PSH | ACK; + header->window_size = htons(con->rcv_wnd); + header->urgent_pointer = 0; + header->checksum = tcp_calculate_checksum( + ip_address, con->outgoing_ip, (const u8 *)payload, payload_length, header, + sizeof(struct TcpHeader) + payload_length); + u32 send_len = sizeof(struct TcpHeader) + payload_length; + u8 *send_buffer = tcp_get_buffer(); + memcpy(send_buffer + sizeof(struct TcpHeader), payload, payload_length); + + if (header->flags & ACK) { con->should_send_ack = 0; } - tcp_send(con, send_buffer, send_len, con->snd_nxt, payload_length); + send_ipv4_packet2((ipv4_t){.d = con->outgoing_ip}, 6, send_len); con->snd_nxt += payload_length; con->snd_max = max(con->snd_nxt, con->snd_max); |