mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:48:10 +00:00
Kernel: Avoid allocations when sending IP packets
Previously we'd allocate buffers when sending packets. This patch avoids these allocations by using the NetworkAdapter's packet queue. At the same time this also avoids copying partially constructed packets in order to prepend Ethernet and/or IPv4 headers. It also properly truncates UDP and raw IP packets.
This commit is contained in:
parent
f8310b7796
commit
b436dd138b
7 changed files with 94 additions and 117 deletions
|
@ -10,7 +10,6 @@
|
|||
#include <Kernel/Heap/kmalloc.h>
|
||||
#include <Kernel/Lock.h>
|
||||
#include <Kernel/Net/EtherType.h>
|
||||
#include <Kernel/Net/EthernetFrameHeader.h>
|
||||
#include <Kernel/Net/LoopbackAdapter.h>
|
||||
#include <Kernel/Net/NetworkAdapter.h>
|
||||
#include <Kernel/Process.h>
|
||||
|
@ -76,15 +75,15 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet
|
|||
send_raw({ (const u8*)eth, size_in_bytes });
|
||||
}
|
||||
|
||||
KResult NetworkAdapter::send_ipv4(const IPv4Address& source_ipv4, const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl)
|
||||
void NetworkAdapter::fill_in_ipv4_header(PacketWithTimestamp& packet, IPv4Address const& source_ipv4, MACAddress const& destination_mac, IPv4Address const& destination_ipv4, IPv4Protocol protocol, size_t payload_size, u8 ttl)
|
||||
{
|
||||
size_t ipv4_packet_size = sizeof(IPv4Packet) + payload_size;
|
||||
if (ipv4_packet_size > mtu())
|
||||
return send_ipv4_fragmented(source_ipv4, destination_mac, destination_ipv4, protocol, payload, payload_size, ttl);
|
||||
VERIFY(ipv4_packet_size <= mtu());
|
||||
|
||||
size_t ethernet_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload_size;
|
||||
auto buffer = NetworkByteBuffer::create_zeroed(ethernet_frame_size);
|
||||
auto& eth = *(EthernetFrameHeader*)buffer.data();
|
||||
size_t ethernet_frame_size = ipv4_payload_offset() + payload_size;
|
||||
VERIFY(packet.buffer.size() == ethernet_frame_size);
|
||||
memset(packet.buffer.data(), 0, ipv4_payload_offset());
|
||||
auto& eth = *(EthernetFrameHeader*)packet.buffer.data();
|
||||
eth.set_source(mac_address());
|
||||
eth.set_destination(destination_mac);
|
||||
eth.set_ether_type(EtherType::IPv4);
|
||||
|
@ -98,53 +97,6 @@ KResult NetworkAdapter::send_ipv4(const IPv4Address& source_ipv4, const MACAddre
|
|||
ipv4.set_ident(1);
|
||||
ipv4.set_ttl(ttl);
|
||||
ipv4.set_checksum(ipv4.compute_checksum());
|
||||
m_packets_out++;
|
||||
m_bytes_out += ethernet_frame_size;
|
||||
|
||||
if (!payload.read(ipv4.payload(), payload_size))
|
||||
return EFAULT;
|
||||
send_raw({ (const u8*)ð, ethernet_frame_size });
|
||||
return KSuccess;
|
||||
}
|
||||
|
||||
KResult NetworkAdapter::send_ipv4_fragmented(const IPv4Address& source_ipv4, const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const UserOrKernelBuffer& payload, size_t payload_size, u8 ttl)
|
||||
{
|
||||
// packets must be split on the 64-bit boundary
|
||||
auto packet_boundary_size = (mtu() - sizeof(IPv4Packet) - sizeof(EthernetFrameHeader)) & 0xfffffff8;
|
||||
auto fragment_block_count = (payload_size + packet_boundary_size) / packet_boundary_size;
|
||||
auto last_block_size = payload_size - packet_boundary_size * (fragment_block_count - 1);
|
||||
auto number_of_blocks_in_fragment = packet_boundary_size / 8;
|
||||
|
||||
auto identification = get_good_random<u16>();
|
||||
|
||||
size_t ethernet_frame_size = mtu();
|
||||
for (size_t packet_index = 0; packet_index < fragment_block_count; ++packet_index) {
|
||||
auto is_last_block = packet_index + 1 == fragment_block_count;
|
||||
auto packet_payload_size = is_last_block ? last_block_size : packet_boundary_size;
|
||||
auto buffer = NetworkByteBuffer::create_zeroed(ethernet_frame_size);
|
||||
auto& eth = *(EthernetFrameHeader*)buffer.data();
|
||||
eth.set_source(mac_address());
|
||||
eth.set_destination(destination_mac);
|
||||
eth.set_ether_type(EtherType::IPv4);
|
||||
auto& ipv4 = *(IPv4Packet*)eth.payload();
|
||||
ipv4.set_version(4);
|
||||
ipv4.set_internet_header_length(5);
|
||||
ipv4.set_source(source_ipv4);
|
||||
ipv4.set_destination(destination_ipv4);
|
||||
ipv4.set_protocol((u8)protocol);
|
||||
ipv4.set_length(sizeof(IPv4Packet) + packet_payload_size);
|
||||
ipv4.set_has_more_fragments(!is_last_block);
|
||||
ipv4.set_ident(identification);
|
||||
ipv4.set_ttl(ttl);
|
||||
ipv4.set_fragment_offset(packet_index * number_of_blocks_in_fragment);
|
||||
ipv4.set_checksum(ipv4.compute_checksum());
|
||||
m_packets_out++;
|
||||
m_bytes_out += ethernet_frame_size;
|
||||
if (!payload.read(ipv4.payload(), packet_index * packet_boundary_size, packet_payload_size))
|
||||
return EFAULT;
|
||||
send_raw({ (const u8*)ð, ethernet_frame_size });
|
||||
}
|
||||
return KSuccess;
|
||||
}
|
||||
|
||||
void NetworkAdapter::did_receive(ReadonlyBytes payload)
|
||||
|
@ -195,6 +147,8 @@ RefPtr<PacketWithTimestamp> NetworkAdapter::acquire_packet_buffer(size_t size)
|
|||
if (m_unused_packets.is_empty()) {
|
||||
auto buffer = KBuffer::create_with_size(size, Region::Access::Read | Region::Access::Write, "Packet Buffer", AllocationStrategy::AllocateNow);
|
||||
auto packet = adopt_ref_if_nonnull(new PacketWithTimestamp { move(buffer), kgettimeofday() });
|
||||
if (!packet)
|
||||
return nullptr;
|
||||
packet->buffer.set_size(size);
|
||||
return packet;
|
||||
}
|
||||
|
@ -208,6 +162,8 @@ RefPtr<PacketWithTimestamp> NetworkAdapter::acquire_packet_buffer(size_t size)
|
|||
|
||||
auto buffer = KBuffer::create_with_size(size, Region::Access::Read | Region::Access::Write, "Packet Buffer", AllocationStrategy::AllocateNow);
|
||||
packet = adopt_ref_if_nonnull(new PacketWithTimestamp { move(buffer), kgettimeofday() });
|
||||
if (!packet)
|
||||
return nullptr;
|
||||
packet->buffer.set_size(size);
|
||||
return packet;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue