RDKEMW-21581: Network connection recovery script should handle IPv4-only/IPv6-only networks - #570
Conversation
There was a problem hiding this comment.
Pull request overview
Updates the RDK network connection recovery script to make packet-loss based recovery decisions correctly on IPv4-only, IPv6-only, and dual-stack networks.
Changes:
- Refactors logging by adding a
log()helper and converting many directecho ... >> $logsFilecalls tolog .... - Updates packet-loss probing and recovery decision logic to evaluate “bad vs good connectivity” per routed IP stack (IPv4/IPv6), rather than requiring both stacks to be present.
- Adds lightweight state tracking (
/tmp/.ncr_laststate) to log route/loss transitions only when they change.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
968658c to
e54744a
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
lib/rdk/networkConnectionRecovery.sh:244
pingCmdis built as a single string including-I $gwIp_interface, butgwIp_interfacecan be empty ifip routeparsing fails. In that case the script would attempt to runping -I -c ..., which errors and makespacketLossunparseable. Build the base command first and only append-I <iface>when the interface value is non-empty.
if [ "$version" = "V4" ] ; then
gwIp=$(/sbin/ip -4 route | awk '/default/ { print $3 }' | head -n1 | awk '{print $1;}')
gwIp_interface=$(/sbin/ip -4 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}')
pingCmd="ping -I $gwIp_interface"
elif [ "$version" = "V6" ] ; then
gwIp=$(/sbin/ip -6 route | awk '/default/ { print $3 }' | head -n1 | awk '{print $1;}')
gwIp_interface=$(/sbin/ip -6 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}')
pingCmd="ping6 -I $gwIp_interface"
fi
e54744a to
99cfab1
Compare
99cfab1 to
b9be278
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
lib/rdk/networkConnectionRecovery.sh:243
- Same issue for IPv6: if
$gwIp_interfaceis empty,ping6 -Iwill treat-cas the interface name and the probe will fail, producing an empty/unparseable packet-loss result.
gwIp=$(/sbin/ip -6 route | awk '/default/ { print $3 }' | head -n1 | awk '{print $1;}')
gwIp_interface=$(/sbin/ip -6 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}')
pingCmd="ping6 -I $gwIp_interface"
| gwIp_interface=$(/sbin/ip -4 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}') | ||
| pingCmd="ping -I $gwIp_interface" |
| tmpFile="/tmp/.Connection.txt" | ||
| prevStateFile="/tmp/.ncr_laststate" | ||
| wifiDriverErrors=0 |
b9be278 to
d529f0b
Compare
d529f0b to
51d9856
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
lib/rdk/networkConnectionRecovery.sh:239
- In checkPacketLoss(V4), default-route parsing can yield an interface name when the route is of the form
default dev <if>(novia), which makesgwIpnon-IP and causes ping to fail / packet loss to become unparseable. Also, buildingping -I $gwIp_interfacebreaks when the interface field is missing/empty (it will consume-cas the interface). Parsingvia/devexplicitly and only adding-Iwhen an interface is present avoids both failure modes.
if [ "$version" = "V4" ] ; then
gwIp=$(/sbin/ip -4 route | awk '/default/ { print $3 }' | head -n1 | awk '{print $1;}')
gwIp_interface=$(/sbin/ip -4 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}')
pingCmd="ping -I $gwIp_interface"
lib/rdk/networkConnectionRecovery.sh:244
- In checkPacketLoss(V6), the same route parsing issue exists as V4: if the default route does not contain
via,gwIpbecomes non-IP (often the interface), andping6 -I $gwIp_interfacemisbehaves when$gwIp_interfaceis empty. Parsevia/devexplicitly and only add-Iwhen an interface is present.
elif [ "$version" = "V6" ] ; then
gwIp=$(/sbin/ip -6 route | awk '/default/ { print $3 }' | head -n1 | awk '{print $1;}')
gwIp_interface=$(/sbin/ip -6 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}')
pingCmd="ping6 -I $gwIp_interface"
fi
…led. Signed-off-by: Balaji Punnuru <Balaji_Punnuru@comcast.com>
…covery trigger Recovery now fires only when no routed IP stack has acceptable connectivity and at least one routed stack is at/above the reassociate tolerance. This fixes the IPv4-only / IPv6-only case where a stack with no default route left packetsLost at 0 and suppressed recovery. Also folded in reliability/logging fixes: - clear stale gwIp on the V6 test-hook path - guard packet-loss comparisons against unparseable ping output - emit SYST_WARN_GW100PERC_PACKETLOSS to the logs file on every run - ping the IPv4 default-route interface explicitly (ping -I) - log total ipv4/ipv6 packet loss when above threshold - simplify the trigger to anyGood/anyBad classification
… packet-loss fix - Introduce a log() helper that prepends the timestamp and appends to $logsFile, and convert the timestamped echo call sites to use it. - Rename packetsLostipv4/packetsLostipv6 globals to ipv4PacketLoss/ipv6PacketLoss for clarity. - Reset the per-call packetLoss to "" at the top of checkPacketLoss and guard the packet-loss telemetry block with [ -n "$packetLoss" ], so a routeless or unparseable ping no longer reuses the other family's value or triggers integer-comparison errors. - Fix a "[" spacing bug in checkWifiDrvErrors. Telemetry markers and t2CountNotify calls are unchanged.
…ate change Emit a "network state changed" line with the per-stack route-present flags and packet-loss values only when the snapshot differs from the previous run (persisted in /tmp/.ncr_laststate), so field logs capture every transition without printing on every run. Debugging aid for customer-site triage.
- Drop the temporary DEBUG_NCR field-debug logging; retain the
"network state changed" transition log (now unprefixed).
- checkWifiDrvErrors(): $dir already holds the full debugfs path, so remove
the duplicated /sys/kernel/debug/ieee80211/ prefix from the log messages,
and capture the cat exit status so the failure log reports the real status
instead of the enclosing test's result.
- Replace bashisms with POSIX/busybox-ash equivalents: source -> .,
[[ =~ ]] -> case, [[ ]] -> [ ], and {1..9} -> explicit list (the brace
form never expands under busybox ash, which had left the
WIFIV_WARN_PL_20..90PERC packet-loss markers non-functional on target).
- Minor whitespace cleanup in checkDnsFile().
Reinstate the field-triage log marker for 100% packet loss that was lost when checkPacketLoss() moved to a tolerance-based recovery decision. The new log-only marker "100% Packet loss is observed on all routed IP stacks" fires when every routed IP stack shows exactly 100% loss. It is independent of WifiReassociateTolerance and does not alter the recovery/return path, so recovery behaviour is unchanged. Unlike the legacy dual-stack "...for both ipv4 and ipv6" print, it is also emitted correctly on IPv4-only and IPv6-only networks. Triage associates the old and new strings to the same 100%-packet-loss marker for trend continuity across images. Also capitalise the "Packet loss more than 10% observed" marker (was lowercase "packet loss ...") since triage marker matching is case-sensitive.
51d9856 to
72c9e89
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
lib/rdk/networkConnectionRecovery.sh:239
- In checkPacketLoss(V4), the interface is parsed as field 5 from
ip route, and then used unconditionally withping -I. For some valid default-route formats (e.g.default dev eth0 ...), field positions differ and$gwIp_interfacecan be empty/incorrect, which can makeping -Itreat-cas the interface and break packet-loss detection.
if [ "$version" = "V4" ] ; then
gwIp=$(/sbin/ip -4 route | awk '/default/ { print $3 }' | head -n1 | awk '{print $1;}')
gwIp_interface=$(/sbin/ip -4 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}')
pingCmd="ping -I $gwIp_interface"
lib/rdk/networkConnectionRecovery.sh:243
- In checkPacketLoss(V6),
ping6 -I $gwIp_interfaceis built even if the route parse fails to produce an interface (or the default route format doesn’t place the interface in field 5). This can turn intoping6 -I -c ...and cause packet loss to be treated as unmeasurable.
elif [ "$version" = "V6" ] ; then
gwIp=$(/sbin/ip -6 route | awk '/default/ { print $3 }' | head -n1 | awk '{print $1;}')
gwIp_interface=$(/sbin/ip -6 route | awk '/default/ { print $5 }' | head -n1 | awk '{print $1;}')
pingCmd="ping6 -I $gwIp_interface"
lib/rdk/networkConnectionRecovery.sh:250
gwResponsecaptures only stdout from ping. If ping fails due to invalid arguments (e.g., malformed-I),gwResponsebecomes empty andpacketLossparses as empty, leading to malformed telemetry lines likeTELEMETRY_GATEWAY_PACKET_LOSS:,$gwIp. Consider capturing stderr and forcing a numeric fallback when the packet-loss parse fails.
gwResponse=$($pingCmd -c "$pingCount" -i "$pingInterval" "$gwIp")
packetLoss=$(echo "$gwResponse" | grep "packet"|awk '{print $7}'|cut -d'%' -f1)
Reason for change: fix network connection recovery script
Test Procedure: See ticket
Priority: P1
Risk: Medium