Skip to content

Conversation

@Sutter099
Copy link

This PR improves the accuracy of TCP receive statistics in tcptop.

Previously, tcptop used a kprobe on tcp_cleanup_rbuf to track receive traffic. However, this function may be called multiple times in a single tcp_recvmsg() call, with an accumulating copied parameter. This can lead to overcounting.

This issue was reported by @sc07kvm:
#5352

To resolve this, I followed the suggestion from @yonghong-song:

That is really unfortunate. But since it is not accurate any way, so I think we could move current tcptop.py to old directory and add fentry/fexit support in tcptop.py and add comments in the beginning of the tool to mention it only works for kernel >= 5.5.

As a result:

  • The original kprobe-based tcptop.py has been moved to tools/old/
  • A new version based on fentry/fexit hooks is introduced
  • Send/receive tracking is unified under tcp_stat() with shared logic
  • Receive stats now hook into tcp_recvmsg with proper entry/exit coordination

The original tcptop uses kprobes on tcp_sendmsg and tcp_cleanup_rbuf to
trace TCP-level send and receive statistics. However, the current
receive side tracing via tcp_cleanup_rbuf can result in overcounting due
to the way `copied` is used:

    int tcp_recvmsg(...) {
         ...
         int copied = 0;
         ...
         do {
             ...
             tcp_cleanup_rbuf(sk, copied);
             ...
             copied += used;
             ...
         } while (len > 0);

         tcp_cleanup_rbuf(sk, copied);
         return copied;
         ...
    }

    Same data in "copied" might be taken into account several times

Fixing this requires tracing tcp_recvmsg entry/exit, which kretprobe
can't reliably handle due to maxactive limits. fentry/fexit is needed,
but only available on kernels >= 5.5 with BTF.

Move the old version to tools/old/, and introduce a new version using
fentry/fexit.

Reported-by: @sc07kvm <github.com/sc07kvm>
Signed-off-by: Ze Huang <[email protected]>
Replace kprobe/kretprobe with fentry/fexit hooks for tcp_sendmsg.

Signed-off-by: Ze Huang <[email protected]>
Rename tcp_sendstat() to tcp_stat() and extend it to support
receive-side statistics based on is_send flag.

Signed-off-by: Ze Huang <[email protected]>
Replace kprobe on tcp_cleanup_rbuf with fentry/fexit on tcp_recvmsg.
Adds a dedicated sock_recv map to track receive-side sockets.

Signed-of-by: Ze Huang <[email protected]>
@yonghong-song
Copy link
Collaborator

Thanks! I checked the goal and also run the new tcptop.py and LGTM.

@yonghong-song yonghong-song merged commit da3a474 into iovisor:master Jul 24, 2025
1 of 12 checks passed
* we'd much prefer tracepoints once they are available.
*/
int kprobe__tcp_cleanup_rbuf(struct pt_regs *ctx, struct sock *sk, int copied)
KRETFUNC_PROBE(tcp_recvmsg, struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len, int ret)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will only work with 5.19. Since the function signature has changed: torvalds/linux@ec09526

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, only works for linux over v5.19. Change the comment from v5.5 to v5.19?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or support both options =)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants