nfErrorFunction does string matching to determine error type #16
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
keyop-go/nfq_forwarder#16
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
There has to be a better way than this:
This is used in
RegisterWithErrorFunc- it's a little hard to test, as I don't know that our error function has ever actually been called.Actually, considering what this is doing, we may get called a lot.
Still valid - and it matters more than it looks
nfErrorFunctionis registered viaRegisterWithErrorFuncagainstinitNfqueue'snfqueue.Config{ReadTimeout: 10 * time.Millisecond, ...}. That read timeout is howgo-nfqueue's internal read loop periodically wakes up to check for context cancellation - whichmeans
nfErrorFunctionis called roughly every 10ms whenever no packet is waiting on thequeue, confirming the "we may get called a lot" comment on this ticket. It needs to correctly
and cheaply recognise "this is just the routine timeout wakeup" on every one of those calls.
The current string-matching approach is fragile for exactly the reason the original comment
suspected: the message text ("netlink receive: i/o timeout" / "netlink receive: recvmsg: i/o
timeout") is an implementation detail of
mdlayher/netlink'sOpError.Error()formatting, nota documented contract - it's already two different strings depending on exactly how the
underlying read failed, and any future dependency bump could change it again and silently start
logging a message on every single timeout tick.
Plan
mdlayher/netlink.OpError(the actual concrete error typeConn.Receive()returns) alreadyimplements the standard
net.Errorinterface, including a correctTimeout() boolthatunwraps through
*os.SyscallErrorwhere needed. Replace the string comparison with theidiomatic, documented Go approach:
This is robust to message-text changes across library versions (it checks behavior/type, not
formatted text), and - unlike the string comparison - also correctly recognises a timeout even if
some future code wraps the error further (
errors.Aswalks the fullUnwrap()chain).The existing test (
TestNfErrorFunction) currently constructs plainerrors.New("netlink receive: i/o timeout")strings, which only exercises the current buggy approach faithfully -it'll be updated to construct a real
*netlink.OpErrorwrapping a real timeout-capable error(proving detection works against the actual type this function receives in production, not just
a string that happens to match today), plus a case wrapped an extra level deeper (to prove the
new check's advantage over string matching), and a plain non-timeout error (unchanged "still
logs" case).
No behavior change for real production traffic - this is purely a correctness/robustness fix for
how "is this a benign read-timeout" is detected.
Work is happening on branch
issue16_error_handling; an MR will follow referencing this issue.mentioned in commit
8e9e183a52mentioned in merge request !65
mentioned in commit
50948e433bFixed via MR !65 and released in v1.0.4 (https://gitlab.keyop.co.uk/keyop/go/nfq_forwarder/-/releases/v1.0.4).
nfErrorFunctionnow detects a routine netlink read timeout via the standardnet.Error/Timeout()interface (errors.As) instead of matching hardcoded error-message strings. Closing.