-
Notifications
You must be signed in to change notification settings - Fork 206
IP-Version byte offset cleanup #946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ver is and never should be used for these frames. Defines ipUDP_PAYLOAD_IP_TYPE_OFFSET as an offset dependent on the IPv6 and UDP headers. Calculates ipIP_TYPE_OFFSET automatically based on the sizes it depends on instead of using a hardcoded number. Removes the definitions of ipIP_TYPE_OFFSET and ipUDP_PAYLOAD_IP_TYPE_OFFSET from FreeRTOS_IPv6_Private.h because they are already defined in FreeRTOS_IPv4_Private.h Adds an assert to ensure that storing of the IP-Type for IPv4 frames does not result in overwriting the ethernet header which would be the case if ipIP_TYPE_OFFSET somehow became negative or zero.
|
I tried running uncrustify, but it seems to modify a bunch of files that I did not touch. |
|
Uncrustify can be a bit of a fickle thing. I'll see if I can format your code change so that it passes the checks. I'm reviewing your change but I'm also going to ask @shubnil to review as he has more +TCP expertise than I do |
@kstribrnAmzn @evpopov You can just comment |
@evpopov I am modifying just enough to make uncrustify unhappy.
|
/bot run uncrustify |
|
@kstribrnAmzn and @evpopov See this commit for example :) |
|
Hi Emil, Cheers, |
|
Thanks all! |
| * For IPv4 frames, prvProcessIPPacket() stores the version header field at a negative offset, a few bytes before the start | ||
| * of the Ethernet header. That IPv4 version field MUST be stored the same distance from the payload as in IPv6. Make sure that: | ||
| * ipUDP_PAYLOAD_IP_TYPE_OFFSET == ( sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) ) which expands to: | ||
| * ( sizeof( UDPPacket_t ) + ipIP_TYPE_OFFSET ) != ( sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) ) which means that: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be ( sizeof( UDPPacket_t ) + ipIP_TYPE_OFFSET ) == ( sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) ) instead of !=
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @evpopov for this PR.
Background:
Since the beginning of FreeRTOS+TCP, it has had the possibility to do zero-copy UDP transfers.
FreeRTOS_sendto() can be given a network packet, which will be passed directly to the DMA, and FreeRTOS_recvfrom() can be called with the FREERTOS_ZERO_COPY flag to avoid copying.
Before it had implemented IPv6, it was easy to translate a payload pointer to a network buffer, just subtract N bytes and find a stored pointer. For IPv6 packets, N+20 bytes must be subtracted to find the pointer. The question was: should N or N+20 be used to find the pointer?
What we do know is that IPv6 stores the value 0x60 as the first byte of the IP-header, position 14. That is at payload - 48.
IPv4 packets store 0x40 as the first byte of the IP-header, also at position 14, which is at payload - 28.
( Actually 0x6? or 0x4? are stored ).
For IPv4 packets, "payload - 48" points to a hidden and unused part of the packet header at pucEthernetBuffer[-6].
I took me a while before I understood your new #define:
#define ipIP_TYPE_OFFSET sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) - sizeof( UDPPacket_t ) )
But it does deliver the "magic number" 6:
8 + 40 - 42 = 6
Earlier I decided to simply give it the hard-coded value 6.
Alternative:
I also have thought of adding a new lookup function in BufferAllocation_x.c, which would iterate through all buffers and find the correct one. Disadvantage: the function could last long, advantage: we don't need to access the hidden space of pucEthernetBuffer, and so we can add multiple VLAN tags.
Other users complained about the extra RAM costs when the IP-type is stored in the hidden space.
Review:
I have a few comments, most importantly the dysfunctional configASSERT().
|
|
||
| /* ipIP_TYPE_OFFSET = ( sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) - ( sizeof( UDPPacket_t ) ) | ||
| * and it MUST be > 0, otherwise storing the IPv4 version byte will overwrite the Ethernet header. */ | ||
| configASSERT( ipIP_TYPE_OFFSET > 0 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As ipIP_TYPE_OFFSET is a summation of sizeof() expressions, the result is an unsigned number.
I just tested it with dummy structs and it did not assert when it should.
| /* The IP-header type is copied to a location 6 bytes before the messages | ||
| * starts. It might be needed later on when a UDP-payload buffer is being | ||
| * used. */ | ||
| pxNetworkBuffer->pucEthernetBuffer[ 0 - ( BaseType_t ) ipIP_TYPE_OFFSET ] = pxIPHeader_IPv6->ucVersionTrafficClass; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still like to have it set for both IPv4 and IPv6 packets. It can be useful when debugging UDP and zero-copy. When we don't set it, it might have an old value of 0x4?
Maybe adapt the comment, saying that the value is only set for debugging purposes.
| * For IPv4 frames, prvProcessIPPacket() stores the version header field at a negative offset, a few bytes before the start | ||
| * of the Ethernet header. That IPv4 version field MUST be stored the same distance from the payload as in IPv6. Make sure that: | ||
| * ipUDP_PAYLOAD_IP_TYPE_OFFSET == ( sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) ) which expands to: | ||
| * ( sizeof( UDPPacket_t ) + ipIP_TYPE_OFFSET ) != ( sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) ) which means that: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
| * tag support, ipIP_TYPE_OFFSET will shrink to 2. With the current design, the Ethernet header cannot be expanded to contain | ||
| * more than one VLAN tag or ipIP_TYPE_OFFSET will become less than zero. ipIP_TYPE_OFFSET should never be allowed to be <= 0. | ||
| */ | ||
| #define ipIP_TYPE_OFFSET ( sizeof( UDPHeader_t ) + sizeof( IPHeader_IPv6_t ) - sizeof( UDPPacket_t ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first when I say this formula, I got surprised by the combination of IPHeader_IPv6_t and UDPPacket_t, the formula mixes IPv6 and IPv4.
But it is correct.
The only problem is that ipIP_TYPE_OFFSET doesn't become negative, because sizeof() returns unsigned values.
| * For IPv6 packets, this it located in the usual 'ucVersionTrafficClass'. */ | ||
| #define ipIP_TYPE_OFFSET ( 6U ) | ||
| /* The offset into an IP packet into which the IP data (payload) starts. */ | ||
| #define ipIPv6_PAYLOAD_OFFSET ( sizeof( IPPacket_IPv6_t ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any reference to ipIPv6_PAYLOAD_OFFSET in the dev/IPv6_integration branch, might as well remove it.
In stead ipUDP_PAYLOAD_OFFSET_IPv6 is used everywhere.
…k for negative values.
evpopov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Casting to int32_t so that subsequent comparisons can properly check if the value of ipIP_TYPE_OFFSET would corruption of the Ethernet header.
This may look busy with too many casts but I did not feel comfortable allowing the subtraction to be done in unsigned space only to cast the result to signed....
evpopov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fixes the error I had in the ling-winded comment and attempts to make it more clear.
… only used for debugging.
|
@tony-josi-aws you're correct. That comment got out of hand a bit |
|
/bot run uncrustify |
|
@evpopov we merged the dev/IPv6_integration branch to main after the 4.0.0-RC3 release. This would mean that unfortunately you would have to point the PR to main branch. Sorry for the inconvenience. Let us know if we can be of any help. Thank you. |
|
@amazonKamath no worries, just let me know what exactly I need to do. Thanks |
Thank you. No worries. @shubnil @moninom1 @tony-josi-aws - do you have a preference? |
|
Hi @evpopov As the main and devIntegration branch has grown apart, merging from devIntegration branch to main would be difficult. I would suggest you to checkout to main branch cherry-pick your changes and create a new PR. |
|
Got it. |
Cleanup of how the IP-Version byte offset is calculated. The main point of this PR is to remove the "mystic" value of 6 and substitute it with a properly calculated offset.
Description
Removes the storing of the IP-Type byte for IPv6 frames because it never is and never should be used for these frames.
Defines ipUDP_PAYLOAD_IP_TYPE_OFFSET as an offset dependent on the IPv6 and UDP headers. Calculates ipIP_TYPE_OFFSET automatically based on the sizes it depends on instead of using a hardcoded number. Removes the definitions of ipIP_TYPE_OFFSET and ipUDP_PAYLOAD_IP_TYPE_OFFSET from FreeRTOS_IPv6_Private.h because they are already defined in FreeRTOS_IPv4_Private.h Adds an assert to ensure that storing of the IP-Type for IPv4 frames does not result in overwriting the ethernet header which would be the case if ipIP_TYPE_OFFSET somehow became negative or zero.