rose: keep the route needed for routing loop detection - #4
Merged
Conversation
rose_route_frame() walks the route list before parsing the Call Request facilities. When a CALL REQUEST arrives on a LCI that already belongs to a route, the "Remove an existing unused route" branch deletes that route with rose_remove_route() and breaks out of the walk, so that a new call is able to reuse a stale LCI. The routing loop detection that follows looks for a route recording the same random number and the same pair of callsigns as the incoming call. The route that has just been deleted is exactly the one it would have matched, so a call coming back to us around a routing loop is not detected: it is routed again, a new route is allocated, and the next copy repeats the cycle. Two nodes whose routes point at each other then relay the same call to each other as fast as the CPU allows. This was observed on an AX.25 network where two nodes each believed the route to a third one went through the other. The same CALL REQUEST, carrying the same random number, was re-sent every 400 us, interleaved with CLEAR REQUEST "Not obtainable", diagnostic 120, until the AX.25 link collapsed. Over nine days one node emitted 204 million frames on a link that normally carries a few frames per minute. The outgoing LCI stayed at 001 the whole time, because deleting the route freed it for immediate reuse. Parse the facilities before walking the route list, and in both branches remove the route only when the incoming call differs from the one it records. When it is the same call, keep the route and clear the call with diagnostic 120, which is what the loop detection would have done. The predicate is factored out as rose_same_call() and reused by the loop detection itself. Tested with two ROSE nodes routing a call back to each other. Before this change the kernel relayed 377 CALL REQUEST in ten seconds, never emitted a CLEAR, and the AX.25 link dropped. After it, the first call is relayed once, the next copy is cleared with diagnostic 120, and the link stays up. Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
This file contains hidden or 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
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.
rose_route_frame() walks the route list before parsing the Call Request
facilities. When a CALL REQUEST arrives on a LCI that already belongs
to a route, the "Remove an existing unused route" branch deletes that
route with rose_remove_route() and breaks out of the walk, so a new
call is able to reuse a stale LCI.
The routing loop detection that follows looks for a route recording
the same random number and the same pair of callsigns as the incoming
call. The route that has just been deleted is exactly the one it would
have matched, so a call coming back to us around a routing loop is not
detected: it is routed again, a new route is allocated, and the next
copy repeats the cycle. Two nodes whose routes point at each other
then relay the same call to each other as fast as the CPU allows.
This was observed on a real AX.25/ROSE (FPAC) network where two nodes
each believed the route to a third one went through the other. The
same CALL REQUEST, carrying the same random number, was re-sent every
400 us, interleaved with CLEAR REQUEST "Not obtainable" diagnostic
120, until the AX.25 link collapsed. Over nine days one node emitted
204 million frames on a link that normally carries a few frames per
minute. The outgoing LCI stayed at 001 the whole time, because
deleting the route freed it for immediate reuse.
Fix: parse the facilities before walking the route list, and in both
branches remove the route only when the incoming call differs from
the one it records. When it is the same call, keep the route and
clear the call with diagnostic 120, which is what the loop detection
would have done. The predicate is factored out as rose_same_call()
and reused by the loop detection itself.
Tested with two ROSE nodes routing a call back to each other. Before
this change the kernel relayed 377 CALL REQUEST in ten seconds, never
emitted a CLEAR, and the AX.25 link dropped. After it, the first call
is relayed once, the next copy is cleared with diagnostic 120, and the
link stays up. Confirmed clean on real-world ROSE/FPAC traffic for
several days on two production nodes after deployment.
Single commit, applies cleanly to current main.