IPv4: Use KBuffer instead of ByteBuffer for socket receive queues

This drastically reduces the pressure on the kernel heap when receiving
data from IPv4 sockets.
This commit is contained in:
Andreas Kling 2019-08-04 21:07:50 +02:00
parent 609495882f
commit 72798519cb
7 changed files with 18 additions and 19 deletions

View file

@ -228,7 +228,7 @@ ssize_t IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t
#endif
}
ASSERT(!packet.data.is_null());
auto& ipv4_packet = *(const IPv4Packet*)(packet.data.pointer());
auto& ipv4_packet = *(const IPv4Packet*)(packet.data->data());
if (addr) {
dbgprintf("Incoming packet is from: %s:%u\n", packet.peer_address.to_string().characters(), packet.peer_port);
@ -246,13 +246,13 @@ ssize_t IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t
return ipv4_packet.payload_size();
}
return protocol_receive(packet.data, buffer, buffer_length, flags);
return protocol_receive(*packet.data, buffer, buffer_length, flags);
}
void IPv4Socket::did_receive(const IPv4Address& source_address, u16 source_port, ByteBuffer&& packet)
void IPv4Socket::did_receive(const IPv4Address& source_address, u16 source_port, NonnullRefPtr<KBuffer>&& packet)
{
LOCKER(lock());
auto packet_size = packet.size();
auto packet_size = packet->size();
m_receive_queue.append({ source_address, source_port, move(packet) });
m_can_read = true;
m_bytes_received += packet_size;

View file

@ -2,6 +2,7 @@
#include <AK/HashMap.h>
#include <AK/SinglyLinkedList.h>
#include <Kernel/KBuffer.h>
#include <Kernel/DoubleBuffer.h>
#include <Kernel/Lock.h>
#include <Kernel/Net/IPv4.h>
@ -33,7 +34,7 @@ public:
virtual ssize_t sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override;
virtual ssize_t recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override;
void did_receive(const IPv4Address& peer_address, u16 peer_port, ByteBuffer&&);
void did_receive(const IPv4Address& peer_address, u16 peer_port, NonnullRefPtr<KBuffer>&&);
const IPv4Address& local_address() const;
u16 local_port() const { return m_local_port; }
@ -50,7 +51,7 @@ protected:
int allocate_local_port_if_needed();
virtual KResult protocol_bind() { return KSuccess; }
virtual int protocol_receive(const ByteBuffer&, void*, size_t, int) { return -ENOTIMPL; }
virtual int protocol_receive(const KBuffer&, void*, size_t, int) { return -ENOTIMPL; }
virtual int protocol_send(const void*, int) { return -ENOTIMPL; }
virtual KResult protocol_connect(FileDescription&, ShouldBlock) { return KSuccess; }
virtual int protocol_allocate_local_port() { return 0; }
@ -65,7 +66,7 @@ private:
struct ReceivedPacket {
IPv4Address peer_address;
u16 peer_port;
ByteBuffer data;
RefPtr<KBuffer> data;
};
SinglyLinkedList<ReceivedPacket> m_receive_queue;

View file

@ -203,7 +203,7 @@ void handle_icmp(const EthernetFrameHeader& eth, int frame_size)
LOCKER(socket->lock());
if (socket->protocol() != (unsigned)IPv4Protocol::ICMP)
continue;
socket->did_receive(ipv4_packet.source(), 0, ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
socket->did_receive(ipv4_packet.source(), 0, KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
}
}
@ -260,7 +260,7 @@ void handle_udp(const EthernetFrameHeader& eth, int frame_size)
ASSERT(socket->type() == SOCK_DGRAM);
ASSERT(socket->local_port() == udp_packet.destination_port());
socket->did_receive(ipv4_packet.source(), udp_packet.source_port(), ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
socket->did_receive(ipv4_packet.source(), udp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
}
void handle_tcp(const EthernetFrameHeader& eth, int frame_size)
@ -319,7 +319,7 @@ void handle_tcp(const EthernetFrameHeader& eth, int frame_size)
kprintf("handle_tcp: Got FIN, payload_size=%u\n", payload_size);
if (payload_size != 0)
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
socket->send_tcp_packet(TCPFlags::FIN | TCPFlags::ACK);
@ -340,5 +340,5 @@ void handle_tcp(const EthernetFrameHeader& eth, int frame_size)
socket->send_tcp_packet(TCPFlags::ACK);
if (payload_size != 0)
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), ByteBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
}

View file

@ -46,11 +46,10 @@ NonnullRefPtr<TCPSocket> TCPSocket::create(int protocol)
return adopt(*new TCPSocket(protocol));
}
int TCPSocket::protocol_receive(const ByteBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
int TCPSocket::protocol_receive(const KBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
{
(void)flags;
ASSERT(!packet_buffer.is_null());
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer());
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
auto& tcp_packet = *static_cast<const TCPPacket*>(ipv4_packet.payload());
size_t payload_size = packet_buffer.size() - sizeof(IPv4Packet) - tcp_packet.header_size();
#ifdef TCP_SOCKET_DEBUG

View file

@ -33,7 +33,7 @@ private:
static NetworkOrdered<u16> compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket&, u16 payload_size);
virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags) override;
virtual int protocol_receive(const KBuffer&, void* buffer, size_t buffer_size, int flags) override;
virtual int protocol_send(const void*, int) override;
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override;
virtual int protocol_allocate_local_port() override;

View file

@ -43,11 +43,10 @@ NonnullRefPtr<UDPSocket> UDPSocket::create(int protocol)
return adopt(*new UDPSocket(protocol));
}
int UDPSocket::protocol_receive(const ByteBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
int UDPSocket::protocol_receive(const KBuffer& packet_buffer, void* buffer, size_t buffer_size, int flags)
{
(void)flags;
ASSERT(!packet_buffer.is_null());
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer());
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.data());
auto& udp_packet = *static_cast<const UDPPacket*>(ipv4_packet.payload());
ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
ASSERT(buffer_size >= (udp_packet.length() - sizeof(UDPPacket)));

View file

@ -16,7 +16,7 @@ private:
virtual const char* class_name() const override { return "UDPSocket"; }
static Lockable<HashMap<u16, UDPSocket*>>& sockets_by_port();
virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags) override;
virtual int protocol_receive(const KBuffer&, void* buffer, size_t buffer_size, int flags) override;
virtual int protocol_send(const void*, int) override;
virtual KResult protocol_connect(FileDescription&, ShouldBlock) override { return KSuccess; }
virtual int protocol_allocate_local_port() override;