mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 22:23:16 +00:00
nic/packet_allocator: align allocations to 2 bytes
Override 'try_alloc/free' because ethernet frame headers are 14 bytes (src/dst mac (12) + ethertype (2)) causing the IP header to be 2 byte aligned, leading to problems on platforms that require load/store operations to be naturally aligned when reading, for example, 4 byte IP addresses. Therefore, we align the allocation to 2 bytes, so the IP header is aligned to 4. issue #4312
This commit is contained in:
parent
5611fd2355
commit
08c1e69d71
@ -17,16 +17,37 @@
|
|||||||
#define _INCLUDE__NIC__PACKET_ALLOCATOR__
|
#define _INCLUDE__NIC__PACKET_ALLOCATOR__
|
||||||
|
|
||||||
#include <os/packet_allocator.h>
|
#include <os/packet_allocator.h>
|
||||||
|
#include <base/log.h>
|
||||||
|
|
||||||
namespace Nic { struct Packet_allocator; }
|
namespace Nic { struct Packet_allocator; }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Packet allocator used for packet streaming in nic sessions.
|
* Packet allocator used for packet streaming in nic sessions.
|
||||||
|
*
|
||||||
|
* We override the allocator interface to align the IP packet to a 32-bit
|
||||||
|
* address. The ethernet frame header contains src/dst mac (12) + ethertype (2)
|
||||||
|
* causing the IP header to be at offset 14 in the packet. This leads to
|
||||||
|
* problems on platforms that require load/store operations to be naturally
|
||||||
|
* aligned when reading, for example, 4 byte IP addresses. Therefore, we
|
||||||
|
* allocate packet size plus OFFSET and offset the returned packet allocation
|
||||||
|
* at 2 bytes, which effectively aligns the IP header to 4 bytes.
|
||||||
|
*
|
||||||
|
* Note, this tweak reduces the usable bytes in the allocated packets to
|
||||||
|
* DEFAULT_PACKET_SIZE - OFFSET and assumes word-aligned allocations in the
|
||||||
|
* Genode::Packet_allocator. As DEFAULT_PACKET_SIZE is used for the
|
||||||
|
* transmission-buffer calculation we could not change it without breaking the
|
||||||
|
* API. OFFSET_PACKET_SIZE reflects the actual (usable) packet-buffer size.
|
||||||
*/
|
*/
|
||||||
struct Nic::Packet_allocator : Genode::Packet_allocator
|
struct Nic::Packet_allocator : Genode::Packet_allocator
|
||||||
{
|
{
|
||||||
enum { DEFAULT_PACKET_SIZE = 1600 };
|
enum {
|
||||||
|
DEFAULT_PACKET_SIZE = 1600,
|
||||||
|
OFFSET = 2,
|
||||||
|
OFFSET_PACKET_SIZE = DEFAULT_PACKET_SIZE - OFFSET,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Genode::size_t size_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -35,6 +56,44 @@ struct Nic::Packet_allocator : Genode::Packet_allocator
|
|||||||
*/
|
*/
|
||||||
Packet_allocator(Genode::Allocator *md_alloc)
|
Packet_allocator(Genode::Allocator *md_alloc)
|
||||||
: Genode::Packet_allocator(md_alloc, DEFAULT_PACKET_SIZE) {}
|
: Genode::Packet_allocator(md_alloc, DEFAULT_PACKET_SIZE) {}
|
||||||
|
|
||||||
|
Alloc_result try_alloc(size_t size) override
|
||||||
|
{
|
||||||
|
if (!size || size > OFFSET_PACKET_SIZE) {
|
||||||
|
Genode::error("unsupported NIC packet size ", size);
|
||||||
|
return Alloc_result { Alloc_error::DENIED };
|
||||||
|
}
|
||||||
|
|
||||||
|
Alloc_result result = Genode::Packet_allocator::try_alloc(size + OFFSET);
|
||||||
|
|
||||||
|
result.with_result(
|
||||||
|
[&] (void *content) {
|
||||||
|
/* assume word-aligned packet buffer and offset packet by 2 bytes */
|
||||||
|
if ((Genode::addr_t)content & 0b11) {
|
||||||
|
Genode::error("NIC packet allocation not word-aligned");
|
||||||
|
result = { Alloc_error::DENIED };
|
||||||
|
} else {
|
||||||
|
result = Alloc_result {
|
||||||
|
reinterpret_cast<void *>((Genode::uint8_t *)content + OFFSET) };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[] (Alloc_error) { }
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *addr, size_t size) override
|
||||||
|
{
|
||||||
|
if (!size || size > OFFSET_PACKET_SIZE) {
|
||||||
|
Genode::error("unsupported NIC packet size ", size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::Packet_allocator::free((Genode::uint8_t *)addr - OFFSET, size + OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__NIC__PACKET_ALLOCATOR__ */
|
#endif /* _INCLUDE__NIC__PACKET_ALLOCATOR__ */
|
||||||
|
@ -122,15 +122,15 @@ class Uplink_client : public Uplink_client_base
|
|||||||
|
|
||||||
progress = false;
|
progress = false;
|
||||||
size_t const max_pkt_size {
|
size_t const max_pkt_size {
|
||||||
Nic::Packet_allocator::DEFAULT_PACKET_SIZE };
|
Nic::Packet_allocator::OFFSET_PACKET_SIZE };
|
||||||
|
|
||||||
_drv_rx_handle_pkt(
|
_drv_rx_handle_pkt(
|
||||||
max_pkt_size,
|
max_pkt_size,
|
||||||
[&] (void *conn_tx_pkt_base,
|
[&] (void *conn_tx_pkt_base,
|
||||||
size_t &adjusted_conn_tx_pkt_size)
|
size_t &adjusted_conn_tx_pkt_size)
|
||||||
{
|
{
|
||||||
long int const read_result {
|
ssize_t const read_result {
|
||||||
read(_tap_fd, conn_tx_pkt_base, max_pkt_size) };
|
::read(_tap_fd, conn_tx_pkt_base, max_pkt_size) };
|
||||||
|
|
||||||
if (read_result <= 0) {
|
if (read_result <= 0) {
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ struct genode_uplink : private Noncopyable, private Interface
|
|||||||
typedef Uplink::Packet_descriptor Packet_descriptor;
|
typedef Uplink::Packet_descriptor Packet_descriptor;
|
||||||
|
|
||||||
Packet_descriptor packet { };
|
Packet_descriptor packet { };
|
||||||
size_t const max_bytes = Nic::Packet_allocator::DEFAULT_PACKET_SIZE;
|
size_t const max_bytes = Nic::Packet_allocator::OFFSET_PACKET_SIZE;
|
||||||
|
|
||||||
try { packet = tx_source.alloc_packet(max_bytes); }
|
try { packet = tx_source.alloc_packet(max_bytes); }
|
||||||
catch (Uplink::Session::Tx::Source::Packet_alloc_failed) {
|
catch (Uplink::Session::Tx::Source::Packet_alloc_failed) {
|
||||||
|
Loading…
Reference in New Issue
Block a user