summaryrefslogtreecommitdiff
path: root/kernel
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 /kernel
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.
Diffstat (limited to 'kernel')
-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);