Skip to content

bgp: return BgpConnectionTcp sockets returned by Listener to nonblocking=false#658

Merged
taspelund merged 1 commit into
mainfrom
trey/not-so-busy-loop
Mar 10, 2026
Merged

bgp: return BgpConnectionTcp sockets returned by Listener to nonblocking=false#658
taspelund merged 1 commit into
mainfrom
trey/not-so-busy-loop

Conversation

@taspelund

Copy link
Copy Markdown
Contributor

It was observed in a customer deployment that several (16) recv loop threads were pinning the CPU due to a busy loop that was constantly handling EAGAIN.
Code analysis showed that non_blocking was set to true only for inbound connections, as the Listener was configured to be nonblocking and TCP sockets returned by accept() inherit this setting. The recv loop thread for each BgpConnectionTcp is structured in a way that depends on SO_RCVTIMEO being respected in order to rate limit the busy loop. However, when nonblocking is true SO_RCVTIMEO is ignored and EAGAIN/EWOULDBLOCK is returned immediately -- short-circuiting the timeout that rate limits the busy loop.

This explicitly sets nonblocking to false for the new sockets returned by accept(), which ensures that the timeout works to rate limit the busy loop as expected.

Fixes: #657

It was observed in a customer deployment that several (16) recv loop
threads were pinning the CPU due to a busy loop that was constantly
handling EAGAIN.
Code analysis showed that non_blocking was set to true only for inbound
connections, as the Listener<BgpConnectionTcp> was configured to be
nonblocking and TCP sockets returned by accept() inherit this setting.
The recv loop thread for each BgpConnectionTcp is structured in a way
that depends on SO_RCVTIMEO being respected in order to rate limit the
busy loop. However, when nonblocking is true SO_RCVTIMEO is ignored and
EAGAIN/EWOULDBLOCK is returned immediately -- short-circuiting the
timeout that rate limits the busy loop.

This explicitly sets nonblocking to false for the new sockets returned
by accept(), which ensures that the timeout works to rate limit the busy
loop as expected.

Fixes: #657
@taspelund taspelund requested a review from rcgoodfellow March 6, 2026 18:09
@taspelund taspelund self-assigned this Mar 6, 2026
@taspelund taspelund added Bug bgp Border Gateway Protocol mgd Maghemite daemon customer For any bug reports or feature requests tied to customer requests labels Mar 6, 2026
@taspelund

Copy link
Copy Markdown
Contributor Author

Output from manual testing below.

This was confirmed to only show up for inbound connections. During testing on the interop topology, all connections came up as active/outbound (which I believe is due to #659) and the recv calls didn't sky-rocket until I reconfigured the peers to make them passive on the mgd side (also removing md5 per #659).

pre-fix:

root@mgd:~# pfexec dtrace -q -n 'syscall::recv*:entry /execname == "mgd"/ { @ = count(); } tick-1sec { printa("Recv calls/sec: %@d\n", @); trunc(@); }'
Recv calls/sec: 1129067
Recv calls/sec: 1084237
Recv calls/sec: 1145660
Recv calls/sec: 1108008
^C

post-fix:

root@mgd:~# pfexec dtrace -q -n 'syscall::recv*:entry /execname == "mgd"/ { @ = count(); } tick-1sec { printa("Recv calls/sec: %@d\n", @); trunc(@); }'
Recv calls/sec: 42
Recv calls/sec: 41
Recv calls/sec: 42
Recv calls/sec: 41
^C

@taspelund taspelund changed the title bgp: return BgpConnectionTcp sockets to blocking bgp: return BgpConnectionTcp sockets returned by Listener to nonblocking=false Mar 9, 2026
@taspelund taspelund merged commit 05e894c into main Mar 10, 2026
15 checks passed
@taspelund taspelund deleted the trey/not-so-busy-loop branch March 10, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bgp Border Gateway Protocol Bug customer For any bug reports or feature requests tied to customer requests mgd Maghemite daemon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CPU pegged in bgp_recv for each peer

2 participants