Use aligned_read for getter_be!#73
Conversation
20264cd to
39a0586
Compare
|
I found the following documentation about the
This would indicate that, at least for tc programs, we can always assume that all headers are properly aligned. |
|
I will take a deeper look at the test failures today why we end up doing unaligned reads for the ICMP header. |
I think it's because the Adding an |
|
@aureliar8 I think we need to force alignment in |
8dd43bb to
e236f3d
Compare
|
Sorry, I didn't have a lot of time to allocate to this PR and didn't have a good idea on how to tackle the problem I think the correct fix it to simply replace In an ebpf context the kernel will ensure that the L3 header is 4-bytes aligned (and thus that all headers after are too) In a pure rust setting, I added a macro to force the compiler to use 4-bytes alignment to all header types of layer 3 and higher.
EDIT: Actually rust already test for unaligned access (at least in test mode), so if test passes we know that we are safe in the pure rust context |
410c559 to
fe3483e
Compare
|
I'm not sure anymore that this is a good idea :( Even if we can rely on the kernel to 4-align the first IP header, which automatically ensure that the L4 header is aligned, we can't be certain that all headers are 4-aligned. The problematic scenario are encapsulated packets. For example Geneve encapsulated packets (but it can happen for any encapsulation protocol that encapsulate an Ethernet frame) The outer ip header is 4-aligned by the kernel, thus the outer UDP header is 4-aligned and the Geneve header is 4-aligned. I need to think more on how to tackle this kind of issue |
Try to fix #69 by using aligned reads (via
core::ptr:read) rather than unaligned reads (viacore::ptr::unaligned_read)In addition to that I added some verification in test that
getter_be!is only called to do aligned readsBellow is my understanding of the problem:
The issue is that the approach doesn't work for the moment:
I assumed the base pointer to all header types would be "properly aligned", and thus that as long as the field offset was a multiple of the field alignment, we would always do aligned reads.
However, with the current code, all header types have an alignment of 1 (easily checked by rust-analyser) . This is because the header types are only made of
u8and[u8; N]which have an alignment of 1.In a regular rust context, we could use the
align1 macro to raise the alignment of those type and ensure that the rust compiler aligns the base address of those types.But in an ebpf context, this can't work because the memory layout is controlled by the kernel.
While
ctx->datashould be at least 4-aligned (and maybe 8-aligned depending on the underlying arch), ensuring alignment for all the header seems difficult. It's probably true that all headers start at an address that is 2-aligned, because all sane protocols have header of a size that is a multiple of two, but we can't assume that all headers will be 4-aligned (For example the ethernet header is of size 14, which isn't a multiple of 4, so the IP header will not be 4-aligned and so theip_srcandip_destfields will not be either)If we want to still benefit a bit from fast aligned reads, I think the only thing we can do is to only do aligned read for u16 fields.
The safety property will be enforced differently depending on the context
#[align(2)]to all header structs to ensure the compiler aligns their base address(Note that in ebpf, the verifier checks that all pointer access are aligned, so we shouldn't have any undefined behavior. At worst a program will be rejected if it does unaligned loads 2)
WDYT ?
This change is