Skip to content

rose: keep the route needed for routing loop detection - #4

Merged
kuba-moo merged 1 commit into
linux-netdev:mainfrom
f6bvp:rose-fix-loop-detection
Sep 11, 2026
Merged

rose: keep the route needed for routing loop detection#4
kuba-moo merged 1 commit into
linux-netdev:mainfrom
f6bvp:rose-fix-loop-detection

Conversation

@f6bvp

@f6bvp f6bvp commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

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.

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>
@kuba-moo
kuba-moo merged commit a7e8082 into linux-netdev:main Sep 11, 2026
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.

2 participants