Skip to content

Optimize syscalls in GTP receiver/sender, GTP UL callback optimization#280

Open
rorsc wants to merge 4 commits into
duranta-project:developfrom
rorsc:gtp-optim
Open

Optimize syscalls in GTP receiver/sender, GTP UL callback optimization#280
rorsc wants to merge 4 commits into
duranta-project:developfrom
rorsc:gtp-optim

Conversation

@rorsc

@rorsc rorsc commented Jul 8, 2026

Copy link
Copy Markdown
Member

Use different syscalls to send data in GTP paths:

  • sender: use sendmsg() to pass both header and packet buffers in kernel instead of a temporary buffer + memcpy()
  • receiver: use recvmmsg() to receive multiple packets at once, reducing syscall overhead in high load scenarios.

Further, for the UL transmission in F1-U, remove a useless malloc() that was done for each packet.

on my laptop, this can reduce losses in high throughput scenarios, tested with the CU-UP load tester:

./tests/nr-cuup/nr-cuup-load-test -t 20 -d 1400 -n 1 -u 200
./nr-cuup -O ../tests/nr-cuup/load-test.conf

the real numbers are platform specific, i.e., one would need to find a maximum value (before/after) to show a change in losses of packets.

This commit makes a simple optimization to avoid unnecessary memcpy()
when sending GTP packets. Instead, it uses struct iovec to indicate both
header and the actual packet to be s end, and uses sendmsg() to pass
both to the kernel, which handles the rest.

Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
@rorsc rorsc requested a review from LaurentThomas July 8, 2026 13:02
@rorsc rorsc added 4G-LTE Perform 4G Tests 5G-NR Perform 5G Tests labels Jul 8, 2026
@durantabot

Copy link
Copy Markdown
Collaborator

CI Build: #726 | Failed on the following stages:

@rorsc rorsc changed the title Optimize syscalls in GTP receiver/sender Optimize syscalls in GTP receiver/sender, GTP UL callback optimization Jul 8, 2026
rorsc added 3 commits July 8, 2026 15:34
This commit tries to reduces the amount of syscalls for receiving GTP
packets. Instead of making a recvfrom() call for each packet, it uses
recvmmsg() to receive multiple (currently, 8) packets at once, which
should reduce overhead, and employs the normal processing chain.

Since this requires a larger number of buffers which still all might
receive up to 64kB of (UDP) data, the actual buffer is moved to
gtpv1uReceiver() to not re-allocate on the stack each time (maybe the
compiler would optimize it, but I think it makes the code a bit
clearer).

Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
In monolithic, at the interface between PDCP and RLC, there is a
pdcp_data_ind_queue to avoid calling into PDCP while holding a lock in
RLC, which could lead to deadlocks if PDCP tries to call into RLC at the
same time.

For reasons I don't understand, we did the same when using F1-U.
However, that seems completely unnecessary:

- there is no RLC (we call from GTP), so deadlocks can't happen
- in DL, GTP calls directly into the stack, so for simplicity, do the
  same in UL.

Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
@durantabot

Copy link
Copy Markdown
Collaborator

CI Build: #728 | Failed on the following stages:

@durantabot

Copy link
Copy Markdown
Collaborator

@LaurentThomas LaurentThomas self-assigned this Jul 10, 2026
@LaurentThomas

Copy link
Copy Markdown
Collaborator

change the title, it is UL in F1, but DL in N3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4G-LTE Perform 4G Tests 5G-NR Perform 5G Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants