1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-25 19:25:07 +00:00

Kernel: Plumb packet receive timestamp from NetworkAdapter to Socket::recvfrom

Since the receiving socket isn't yet known at packet receive time,
keep timestamps for all packets.

This is useful for keeping statistics about in-kernel queue latencies
in the future, and it can be used to implement SO_TIMESTAMP.
This commit is contained in:
Nico Weber 2020-09-16 12:25:06 -04:00 committed by Andreas Kling
parent b36a2d6686
commit 416d470d07
10 changed files with 52 additions and 37 deletions

View file

@ -52,10 +52,10 @@
namespace Kernel {
static void handle_arp(const EthernetFrameHeader&, size_t frame_size);
static void handle_ipv4(const EthernetFrameHeader&, size_t frame_size);
static void handle_icmp(const EthernetFrameHeader&, const IPv4Packet&);
static void handle_udp(const IPv4Packet&);
static void handle_tcp(const IPv4Packet&);
static void handle_ipv4(const EthernetFrameHeader&, size_t frame_size, const timeval& packet_timestamp);
static void handle_icmp(const EthernetFrameHeader&, const IPv4Packet&, const timeval& packet_timestamp);
static void handle_udp(const IPv4Packet&, const timeval& packet_timestamp);
static void handle_tcp(const IPv4Packet&, const timeval& packet_timestamp);
[[noreturn]] static void NetworkTask_main();
@ -89,14 +89,14 @@ void NetworkTask_main()
};
});
auto dequeue_packet = [&pending_packets](u8* buffer, size_t buffer_size) -> size_t {
auto dequeue_packet = [&pending_packets](u8* buffer, size_t buffer_size, timeval& packet_timestamp) -> size_t {
if (pending_packets == 0)
return 0;
size_t packet_size = 0;
NetworkAdapter::for_each([&](auto& adapter) {
if (packet_size || !adapter.has_queued_packets())
return;
packet_size = adapter.dequeue_packet(buffer, buffer_size);
packet_size = adapter.dequeue_packet(buffer, buffer_size, packet_timestamp);
pending_packets--;
#ifdef NETWORK_TASK_DEBUG
klog() << "NetworkTask: Dequeued packet from " << adapter.name().characters() << " (" << packet_size << " bytes)";
@ -108,10 +108,11 @@ void NetworkTask_main()
size_t buffer_size = 64 * KiB;
auto buffer_region = MM.allocate_kernel_region(buffer_size, "Kernel Packet Buffer", Region::Access::Read | Region::Access::Write, false, true);
auto buffer = (u8*)buffer_region->vaddr().get();
timeval packet_timestamp;
klog() << "NetworkTask: Enter main loop.";
for (;;) {
size_t packet_size = dequeue_packet(buffer, buffer_size);
size_t packet_size = dequeue_packet(buffer, buffer_size, packet_timestamp);
if (!packet_size) {
Thread::current()->wait_on(packet_wait_queue, "NetworkTask");
continue;
@ -150,7 +151,7 @@ void NetworkTask_main()
handle_arp(eth, packet_size);
break;
case EtherType::IPv4:
handle_ipv4(eth, packet_size);
handle_ipv4(eth, packet_size, packet_timestamp);
break;
case EtherType::IPv6:
// ignore
@ -213,7 +214,7 @@ void handle_arp(const EthernetFrameHeader& eth, size_t frame_size)
}
}
void handle_ipv4(const EthernetFrameHeader& eth, size_t frame_size)
void handle_ipv4(const EthernetFrameHeader& eth, size_t frame_size, const timeval& packet_timestamp)
{
constexpr size_t minimum_ipv4_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet);
if (frame_size < minimum_ipv4_frame_size) {
@ -239,18 +240,18 @@ void handle_ipv4(const EthernetFrameHeader& eth, size_t frame_size)
switch ((IPv4Protocol)packet.protocol()) {
case IPv4Protocol::ICMP:
return handle_icmp(eth, packet);
return handle_icmp(eth, packet, packet_timestamp);
case IPv4Protocol::UDP:
return handle_udp(packet);
return handle_udp(packet, packet_timestamp);
case IPv4Protocol::TCP:
return handle_tcp(packet);
return handle_tcp(packet, packet_timestamp);
default:
klog() << "handle_ipv4: Unhandled protocol " << packet.protocol();
break;
}
}
void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet)
void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet, const timeval& packet_timestamp)
{
auto& icmp_header = *static_cast<const ICMPHeader*>(ipv4_packet.payload());
#ifdef ICMP_DEBUG
@ -263,7 +264,7 @@ void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet)
LOCKER(socket->lock());
if (socket->protocol() != (unsigned)IPv4Protocol::ICMP)
continue;
socket->did_receive(ipv4_packet.source(), 0, KBuffer::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()), packet_timestamp);
}
}
@ -290,7 +291,7 @@ void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet)
}
}
void handle_udp(const IPv4Packet& ipv4_packet)
void handle_udp(const IPv4Packet& ipv4_packet, const timeval& packet_timestamp)
{
if (ipv4_packet.payload_size() < sizeof(UDPPacket)) {
klog() << "handle_udp: Packet too small (" << ipv4_packet.payload_size() << ", need " << sizeof(UDPPacket) << ")";
@ -316,10 +317,10 @@ void handle_udp(const IPv4Packet& ipv4_packet)
ASSERT(socket->type() == SOCK_DGRAM);
ASSERT(socket->local_port() == udp_packet.destination_port());
socket->did_receive(ipv4_packet.source(), udp_packet.source_port(), KBuffer::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()), packet_timestamp);
}
void handle_tcp(const IPv4Packet& ipv4_packet)
void handle_tcp(const IPv4Packet& ipv4_packet, const timeval& packet_timestamp)
{
if (ipv4_packet.payload_size() < sizeof(TCPPacket)) {
klog() << "handle_tcp: IPv4 payload is too small to be a TCP packet (" << ipv4_packet.payload_size() << ", need " << sizeof(TCPPacket) << ")";
@ -549,7 +550,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
case TCPSocket::State::Established:
if (tcp_packet.has_fin()) {
if (payload_size != 0)
socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::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()), packet_timestamp);
socket->set_ack_number(tcp_packet.sequence_number() + payload_size + 1);
(void)socket->send_tcp_packet(TCPFlags::ACK);
@ -565,7 +566,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet)
#endif
if (payload_size) {
if (socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size())))
if (socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()), packet_timestamp))
(void)socket->send_tcp_packet(TCPFlags::ACK);
}
}