summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-10-06 11:12:16 +0200
committerAnton Kling <anton@kling.gg>2024-10-06 11:12:16 +0200
commitf18beba3cb3d85ed6e0f44fdff9256c50adcc5e1 (patch)
tree42e15026c9a0154269e5c7de71cd829866d6d564
parent6dc2637972f93dea8cc831d7ee225daefb74b8ab (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.c18
-rw-r--r--kernel/drivers/rtl8139.h2
-rw-r--r--kernel/network/ethernet.c27
-rw-r--r--kernel/network/ethernet.h10
-rw-r--r--kernel/network/ipv4.c32
-rw-r--r--kernel/network/ipv4.h1
-rw-r--r--kernel/network/tcp.c90
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);