forked from lwip-tcpip/lwip
-
Notifications
You must be signed in to change notification settings - Fork 2
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
Support for TCP/UDP checksum offloading with partial checksums #1
Open
skuenzer
wants to merge
12
commits into
unikraft:UNIKRAFT-2_1_x
Choose a base branch
from
skuenzer:skuenzer/partial-checksum
base: UNIKRAFT-2_1_x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Support for TCP/UDP checksum offloading with partial checksums #1
skuenzer
wants to merge
12
commits into
unikraft:UNIKRAFT-2_1_x
from
skuenzer:skuenzer/partial-checksum
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This commit syncs the netif checksum check and control macros with the `master` branch of lwip. State on master: 61c67fc It basically introduces the macro `NETIF_CHECKSUM_ENABLED` that resolves into condition only instead of an `if`-statement as `IF__NETIF_CHECKSUM_ENABLED` does. This enables the macro to be used as part of conditional expressions. Signed-off-by: Simon Kuenzer <[email protected]>
…F_CHECKSUM_ENABLED` When `LWIP_CHECKSUM_CTRL_PER_NETIF` is not active, the macros `IF__NETIF_CHECKSUM_ENABLED` and `NETIF_SET_CHECKSUM_CTRL` can cause compiler errors under the following circumstances: - Whenever an `else` case is used together with `IF__NETIF_CHECKSUM_ENABLED`, it results in an else case without if statement: IF__NETIF_CHECKSUM_ENABLED(...) { /**/ } else { /**/ } This commit resolve the macro always into an `if`-statement. The originally intended condition is kept: Unlike LWIP_CHECKSUM_ENABLED, it becomes constantly `true` when `LWIP_CHECKSUM_CTRL_PER_NETIF` is inactive. This allows the compiler to optimize out any `else` cases. - Whenever `NETIF_SET_CHECKSUM_CTRL` is used as a single-statement compound under an `if`-statement or `for`-loops (without curly braces `{`, `}`), unintentionally, the successive statement becomes the statement for `if` or `for`: if (condition) NETIF_SET_CHECKSUM_CTRL(...) next_statement(); This commit introduces the best practice construct to avoid such programming mistakes: `do {} while (0)` Signed-off-by: Simon Kuenzer <[email protected]>
Introduces routines to compute the checksum of an TCP/UDP pseudo header only. Such a checksum can be used to initialize the checksum field for partial hardware checksum offloading. Signed-off-by: Simon Kuenzer <[email protected]>
`PBUF_FLAG_CSUM_PARTIAL` indicates that a checksum within a pbuf is only partially computed. For such pbufs, netif drivers can offload completing the calculation to hardware. On receiving, drivers are able to indicate the stack that a checksum is only partially computed. Typically, this can happen in virtual environments (e.g., virtio-net, netfront) where mixed types of traffic can be received (partially and fully computed checksums). The additional pbuf field `csum_start` points to the pbuf payload byte where checksum computation must continue until the end of the payload of a pbuf chain. `csum_offset` points to the checksum field. For implementation simplicity `PBUF_FLAG_CSUM_PARTIAL` can only be set once for a pbuf chain with the heading pbuf. Signed-off-by: Simon Kuenzer <[email protected]>
Implements partial checksumming of TCP segments and control packets. Resulting pbufs will have `PBUF_FLAG_CSUM_PARTIAL` set and `csum_start` and `csum_offset` will point to the corresponding locations within the pbuf payload. Partial checksumming for TCP is only enabled if `CHECKSUM_PARTIAL_TCP` and `CHECKSUM_GEN_TCP` are enabled via `lwipopts.h`. If netif checksum control flags are activated, the control flags `NETIF_CHECKSUM_GEN_TCP` and `NETIF_CHECKSUM_PARTIAL_TCP` must also be set. Signed-off-by: Simon Kuenzer <[email protected]>
Implements checking of partial checksummed TCP segments and control packets. netif drivers that support partial checksums will set `PBUF_FLAG_CSUM_PARTIAL` for such received pbufs. Similar to Linux's implementation, the partial TCP checksum is not checked on reception. It is assumed that such packets can only be originated from in-memory packet transfers (for example from another guest on the same physical machine in case of virtualization). In case the netif driver provides `csum_start` and `csum_offset`, these pointers must point to the checksum field of the TCP header. Otherwise such a packet is dropped. This handling of partial TCP checksums is only enabled if `CHECKSUM_PARTIAL_TCP` and `CHECKSUM_CHECK_TCP` are enabled via `lwipopts.h`. If netif checksum control flags are activated, the control flags `NETIF_CHECKSUM_CHECK_TCP` and `NETIF_CHECKSUM_PARTIAL_TCP` must also be set. Signed-off-by: Simon Kuenzer <[email protected]>
Implements partial checksumming of UDP packets. Resulting pbufs will have `PBUF_FLAG_CSUM_PARTIAL` set and `csum_start` and `csum_offset` will point to the corresponding locations within the pbuf payload. Partial checksumming for UDP is only enabled if `CHECKSUM_PARTIAL_UDP` and `CHECKSUM_GEN_UDP` are enabled via `lwipopts.h`. If netif checksum control flags are activated, the control flags `NETIF_CHECKSUM_GEN_UDP` and `NETIF_CHECKSUM_PARTIAL_UDP` must also be set. Signed-off-by: Simon Kuenzer <[email protected]>
Implements checking of partial checksummed UDP packets. netif drivers that support partial checksums will set `PBUF_FLAG_CSUM_PARTIAL` for such received pbufs. The partial UDP checksum is not checked on reception. It is assumed that such packets can only be originated from in-memory packet transfers (for example from another guest on the same physical machine in case of virtualization). In case the netif driver provides `csum_start` and `csum_offset`, these pointers must point to the checksum field of the UDP header. Otherwise such a packet is dropped. This handling of partial UDP checksums is only enabled if `CHECKSUM_PARTIAL_UDP` and `CHECKSUM_CHECK_UDP` are enabled via `lwipopts.h`. If netif checksum control flags are activated, the control flags `NETIF_CHECKSUM_CHECK_UDP` and `NETIF_CHECKSUM_PARTIAL_UDP` must also be set. Signed-off-by: Simon Kuenzer <[email protected]>
`PBUF_FLAG_DATA_VALID` indicates that the L4 checksum within a pbuf is already validated and further checks are not necessary by the stack. For implementation simplicity `PBUF_FLAG_DATA_VALID` can only be set once for a pbuf chain with the heading pbuf. Typically, this flag is set by netif drivers in virtual environments for traffic that is already validated, e.g., by receiving it on a physical network card. Signed-off-by: Simon Kuenzer <[email protected]>
Checking of TCP checksums can be skipped for pbufs that are marked with `PBUF_FLAG_DATA_VALID`. This feature is only enabled when `CHECKSUM_CHECK_TCP` and `CHECKSUM_SKIPVALID_TCP` is set. If netif checksum control flags are activated, the control flags `NETIF_CHECKSUM_CHECK_TCP` and `NETIF_CHECKSUM_SKIPVALID_TCP` must also be set. Signed-off-by: Simon Kuenzer <[email protected]>
Checking of UDP checksums can be skipped for pbufs that are marked with `PBUF_FLAG_DATA_VALID`. This feature is only enabled when `CHECKSUM_CHECK_UDP` and `CHECKSUM_SKIPVALID_UDP` is set. If netif checksum control flags are activated, the control flags `NETIF_CHECKSUM_CHECK_UDP` and `NETIF_CHECKSUM_SKIPVALID_UDP` must also be set. Signed-off-by: Simon Kuenzer <[email protected]>
In order to allow skipping of checksum checks when looping back traffic, `PBUF_FLAG_DATA_VALID` is set on every generated UDP, TCP packet. Netif drivers that should not set the flag for outgoing traffic (e.g., virtio-net) should ignore this flag. Signed-off-by: Simon Kuenzer <[email protected]>
mogasergiu
approved these changes
Nov 25, 2021
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.
Looks good to me.
Reviewed-by: Sergiu Moga [email protected]
unikraft-bot
pushed a commit
that referenced
this pull request
Apr 7, 2023
Reproducer (in bash): base64 -d <<< "H4sIAP/9L2QCA+3WoQ2AMBSE4QoCTFHBBJfgSRF4RDfpRmgmYBpGQRBCk4ZiSfk/+fJMK+5dZRVpzSQzSs6oPierDV4y87WxLQLwE42SfNCdDyHJB9/xZwAARPbMJbUq4JJmu4JVT1cAAACfbGIqoqcMzy90eu+aBw2+N28WFgAA" | gunzip | test/fuzz/lwip_fuzz2 Crash log: ../../src/core/altcp_tcp.c:178:13: runtime error: member access within null pointer of type 'struct tcp_pcb' SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../../src/core/altcp_tcp.c:178:13 in AddressSanitizer:DEADLYSIGNAL ================================================================= ==192415==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000048 (pc 0x557065081703 bp 0x0aae0cb71204 sp 0x7ffd034dabc0 T0) ==192415==The signal is caused by a READ memory access. ==192415==Hint: address points to the zero page. #0 0x557065081703 in altcp_tcp_setup_callbacks /.../lwip/test/fuzz/../../src/core/altcp_tcp.c:178:19 #1 0x55706508206f in altcp_tcp_setup /.../lwip/test/fuzz/../../src/core/altcp_tcp.c:189:3 lwip-tcpip#2 0x55706508206f in altcp_tcp_accept /.../lwip/test/fuzz/../../src/core/altcp_tcp.c:84:5 lwip-tcpip#3 0x557065095592 in tcp_input /.../lwip/test/fuzz/../../src/core/tcp_in.c:380:9 lwip-tcpip#4 0x5570650e752f in ip4_input /.../lwip/test/fuzz/../../src/core/ipv4/ip4.c:743:9 lwip-tcpip#5 0x55706513d4de in ethernet_input /.../lwip/test/fuzz/../../src/netif/ethernet.c:186:9 lwip-tcpip#6 0x557064fe0959 in input_pkt /.../lwip/test/fuzz/fuzz_common.c:209:9 lwip-tcpip#7 0x557064fdeb6a in input_pkts /.../lwip/test/fuzz/fuzz_common.c:257:9 lwip-tcpip#8 0x557064fdeb6a in lwip_fuzztest /.../lwip/test/fuzz/fuzz_common.c:669:3 lwip-tcpip#9 0x7ff4f578e189 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 lwip-tcpip#10 0x7ff4f578e244 in __libc_start_main csu/../csu/libc-start.c:381:3 lwip-tcpip#11 0x557064f20420 in _start (/.../lwip/test/fuzz/lwip_fuzz2+0x81420) (BuildId: 8680a96430d5749c90111fe9c3a3d4f881a5dbcd) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /.../lwip/test/fuzz/../../src/core/altcp_tcp.c:178:19 in altcp_tcp_setup_callbacks ==192415==ABORTING Aborted
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR implements checksum offloading capabilities for TCP and UDP, where a partial checksum is computed in software. This checksum covers only the pseudo header, as soon as a packet leaves the host, the physical NIC does complete the calculation from there on. We need this feature to properly support the
virtio-net
andnetfront
network interfaces (and likely for other network adapters as well).For this purpose, we introduce two pbuf flags in order to be able to handle mixed traffic:
PBUF_FLAG_CSUM_PARTIAL
marks a packet as containing only a partially computed TCP or UDP checksum. Thecsum_start
andcsum_offset
fields point to the checksum field of the header and to where the computation needsto be completed. As soon as the stack receives such a packet, we skip checksum validation but check
csum_start
andcsum_offset
. Similar to Linux, we assume that traffic with a partial checksum is only resulting from in-memory communication where corruption is unlikely, e.g., guest-to-guest, host-to-guest.PBUF_FLAG_DATA_VALID
marks a packet whose UDP or TCP checksum has already been validated (e.g., physical NIC on the host). On reception, lwIP will skip checksum validation. For improving loopback traffic, this flag is set for transmitted TCP and UDP packets.A current limitation of this implementation is the lack of support for forwarding and L2-bridging. The missing piece of the puzzle is a function that can complete the checksum computation in the software for partially checksummed packets that are forwarded to devices that do not support partially checksummed packets.
Another version of this PR that applies to lwIP's master branch is also sent to the lwIP community for review.