Skip to content

Commit f0306d8

Browse files
committed
Ethernet test: Make interface detection dynamic, robustify bring-up and ping validation
- Add logic to auto-detect active Ethernet interface using ip/ipconfig - Enhance bring-up sequence with retries and logging - Improve ping test error handling and reporting - Refactor for better CI diagnostics Signed-off-by: Srikanth Muppandam <smuppand@qti.qualcomm.com>
1 parent edfad16 commit f0306d8

File tree

3 files changed

+230
-60
lines changed

3 files changed

+230
-60
lines changed

Runner/suites/Connectivity/Ethernet/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ cd <this-repo>
2828
scp -r common Runner user@target_device_ip:<Path in device>
2929
ssh user@target_device_ip
3030
cd <Path in device>/Runner && ./run-test.sh Ethernet
31+
# Optional: specify preferred interface (e.g., eth1)
32+
./run.sh [preferred-interface]
3133
```
3234

3335
## Prerequisites
@@ -53,5 +55,14 @@ Test result will be saved in `Ethernet.res` as:
5355
## Output
5456
A .res file is generated in the same directory:
5557

56-
`PASS Ethernet` OR `FAIL Ethernet`
58+
`Ethernet PASS` OR `Ethernet FAIL`
5759

60+
## Sample Log
61+
```
62+
Output
63+
64+
[INFO] 2025-06-11 10:12:23 - Detected Ethernet interface: enP1p4s0u1u1
65+
[PASS] 2025-06-11 10:12:30 - enP1p4s0u1u1 is UP
66+
[INFO] 2025-06-11 10:12:31 - Assigned IP: 10.0.0.55
67+
[PASS] 2025-06-11 10:12:35 - Ping successful on enP1p4s0u1u1
68+
```

Runner/suites/Connectivity/Ethernet/run.sh

Lines changed: 83 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,90 +3,114 @@
33
#Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
44
#SPDX-License-Identifier: BSD-3-Clause-Clear
55

6-
# Source init_env and functestlib.sh
6+
# Robustly find and source init_env
77
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
88
INIT_ENV=""
99
SEARCH="$SCRIPT_DIR"
10-
1110
while [ "$SEARCH" != "/" ]; do
1211
if [ -f "$SEARCH/init_env" ]; then
1312
INIT_ENV="$SEARCH/init_env"
1413
break
1514
fi
1615
SEARCH=$(dirname "$SEARCH")
1716
done
18-
17+
1918
if [ -z "$INIT_ENV" ]; then
2019
echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2
2120
exit 1
2221
fi
23-
24-
# shellcheck disable=SC1090
25-
. "$INIT_ENV"
22+
23+
if [ -z "$__INIT_ENV_LOADED" ]; then
24+
# shellcheck disable=SC1090
25+
. "$INIT_ENV"
26+
fi
2627
# shellcheck disable=SC1090,SC1091
2728
. "$TOOLS/functestlib.sh"
28-
29+
2930
TESTNAME="Ethernet"
30-
test_path=$(find_test_case_by_name "$TESTNAME") || {
31-
log_fail "$TESTNAME : Test directory not found."
32-
echo "FAIL $TESTNAME" > "./$TESTNAME.res"
33-
exit 1
34-
}
35-
31+
test_path=$(find_test_case_by_name "$TESTNAME")
3632
cd "$test_path" || exit 1
3733
res_file="./$TESTNAME.res"
38-
rm -f "$res_file"
34+
summary_file="./$TESTNAME.summary"
35+
rm -f "$res_file" "$summary_file"
3936

4037
log_info "--------------------------------------------------------------------------"
4138
log_info "-------------------Starting $TESTNAME Testcase----------------------------"
42-
39+
40+
# Check for dependencies
4341
check_dependencies ip ping
44-
45-
IFACE="eth0"
46-
RETRIES=3
47-
SLEEP_SEC=3
48-
49-
# Check interface existence
50-
if ! ip link show "$IFACE" >/dev/null 2>&1; then
51-
log_fail "Ethernet interface $IFACE not found"
52-
echo "FAIL $TESTNAME" > "$res_file"
53-
exit 1
42+
43+
# User-specified interface (argument) or all detected
44+
# Accept user-preferred interface as argument
45+
user_iface="$1"
46+
if [ -n "$user_iface" ]; then
47+
IFACES="$user_iface"
48+
log_info "User specified interface: $user_iface"
49+
else
50+
IFACES=$(get_ethernet_interfaces)
51+
log_info "Auto-detected Ethernet interfaces: $IFACES"
5452
fi
55-
56-
# Bring up interface with retries
57-
log_info "Ensuring $IFACE is UP..."
58-
i=0
59-
while [ $i -lt $RETRIES ]; do
60-
ip link set "$IFACE" up
61-
sleep "$SLEEP_SEC"
62-
if ip link show "$IFACE" | grep -q "state UP"; then
63-
log_info "$IFACE is UP"
64-
break
53+
54+
iface_passed=0
55+
iface_failed=0
56+
iface_skipped=0
57+
58+
for iface in $IFACES; do
59+
log_info "---- Testing interface: $iface ----"
60+
61+
# Check if interface is up
62+
if ! is_interface_up "$iface"; then
63+
log_warn "$iface is DOWN, skipping"
64+
echo "$iface: SKIP (down/no cable)" >> "$summary_file"
65+
iface_skipped=$((iface_skipped+1))
66+
continue
67+
fi
68+
69+
ip_addr="$(get_ip_address "$iface")"
70+
71+
if [ -z "$ip_addr" ]; then
72+
log_info "$iface has no IP, attempting DHCP"
73+
run_dhcp_client "$iface" 10
74+
sleep 2
75+
ip_addr="$(get_ip_address "$iface")"
76+
fi
77+
78+
if [ -z "$ip_addr" ]; then
79+
log_warn "$iface has no IP assigned, skipping"
80+
echo "$iface: SKIP (no IP assigned)" >> "$summary_file"
81+
iface_skipped=$((iface_skipped+1))
82+
continue
83+
elif echo "$ip_addr" | grep -q '^169\.254'; then
84+
log_warn "$iface got only link-local IP ($ip_addr), skipping"
85+
echo "$iface: SKIP (link-local IP: $ip_addr)" >> "$summary_file"
86+
iface_skipped=$((iface_skipped+1))
87+
continue
88+
else
89+
log_info "$iface got IP: $ip_addr"
90+
fi
91+
92+
# Ping test
93+
if ping -I "$iface" -c 4 -W 2 8.8.8.8 >/dev/null 2>&1; then
94+
log_pass "$iface connectivity verified via ping"
95+
echo "$iface: PASS" >> "$summary_file"
96+
iface_passed=$((iface_passed+1))
97+
else
98+
log_fail "Ping test failed for $iface"
99+
echo "$iface: FAIL (ping failed)" >> "$summary_file"
100+
iface_failed=$((iface_failed+1))
65101
fi
66-
log_warn "$IFACE is still DOWN (attempt $((i + 1))/$RETRIES)..."
67-
i=$((i + 1))
68102
done
69-
70-
if [ $i -eq $RETRIES ]; then
71-
log_fail "Failed to bring up $IFACE after $RETRIES attempts"
72-
echo "FAIL $TESTNAME" > "$res_file"
103+
104+
log_info "---- Ethernet Interface Test Summary ----"
105+
cat "$summary_file"
106+
107+
if [ "$iface_passed" -gt 0 ]; then
108+
echo "$TESTNAME PASS" > "$res_file"
109+
exit 0
110+
elif [ "$iface_failed" -gt 0 ]; then
111+
echo "$TESTNAME FAIL" > "$res_file"
73112
exit 1
113+
else
114+
echo "$TESTNAME SKIP" > "$res_file"
115+
exit 2
74116
fi
75-
76-
# Ping test with retries
77-
log_info "Running ping test to 8.8.8.8 via $IFACE..."
78-
i=0
79-
while [ $i -lt $RETRIES ]; do
80-
if ping -I "$IFACE" -c 4 -W 2 8.8.8.8 >/dev/null 2>&1; then
81-
log_pass "Ethernet connectivity verified via ping"
82-
echo "PASS $TESTNAME" > "$res_file"
83-
exit 0
84-
fi
85-
log_warn "Ping failed (attempt $((i + 1))/$RETRIES)... retrying"
86-
sleep "$SLEEP_SEC"
87-
i=$((i + 1))
88-
done
89-
90-
log_fail "Ping test failed after $RETRIES attempts"
91-
echo "FAIL $TESTNAME" > "$res_file"
92-
exit 1

Runner/utils/functestlib.sh

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
44
# SPDX-License-Identifier: BSD-3-Clause-Clear
55

6+
# Suppress 'Broken pipe' errors globally in this shell (put this at the very top once)
7+
trap '' PIPE
8+
69
# --- Logging helpers ---
710
log() {
811
level=$1
@@ -391,3 +394,135 @@ weston_start() {
391394
fi
392395
}
393396

397+
# Returns true (0) if interface is administratively and physically up
398+
is_interface_up() {
399+
iface="$1"
400+
if [ -f "/sys/class/net/$iface/operstate" ]; then
401+
[ "$(cat "/sys/class/net/$iface/operstate")" = "up" ]
402+
elif command -v ip >/dev/null 2>&1; then
403+
ip link show "$iface" 2>/dev/null | grep -qw "state UP"
404+
elif command -v ifconfig >/dev/null 2>&1; then
405+
ifconfig "$iface" 2>/dev/null | grep -qw "UP"
406+
else
407+
return 1
408+
fi
409+
}
410+
411+
# Returns true (0) if physical link/carrier is detected (cable plugged in)
412+
is_link_up() {
413+
iface="$1"
414+
[ -f "/sys/class/net/$iface/carrier" ] && [ "$(cat "/sys/class/net/$iface/carrier")" = "1" ]
415+
}
416+
417+
# Returns true (0) if interface is Ethernet type (type 1 in sysfs)
418+
is_ethernet_interface() {
419+
iface="$1"
420+
[ -f "/sys/class/net/$iface/type" ] && [ "$(cat "/sys/class/net/$iface/type")" = "1" ]
421+
}
422+
423+
# Get all Ethernet interfaces (excluding common virtual types)
424+
get_ethernet_interfaces() {
425+
for path in /sys/class/net/*; do
426+
iface=$(basename "$path")
427+
case "$iface" in
428+
lo|docker*|br-*|veth*|virbr*|tap*|tun*|wl*) continue ;;
429+
esac
430+
if is_ethernet_interface "$iface"; then
431+
echo "$iface"
432+
fi
433+
done
434+
}
435+
436+
# Bring up interface with retries (down before up).
437+
bringup_interface() {
438+
iface="$1"; retries="${2:-3}"; sleep_sec="${3:-2}"; i=0
439+
while [ $i -lt "$retries" ]; do
440+
if command -v ip >/dev/null 2>&1; then
441+
ip link set "$iface" down
442+
sleep 1
443+
ip link set "$iface" up
444+
sleep "$sleep_sec"
445+
ip link show "$iface" | grep -q "state UP" && return 0
446+
elif command -v ifconfig >/dev/null 2>&1; then
447+
ifconfig "$iface" down
448+
sleep 1
449+
ifconfig "$iface" up
450+
sleep "$sleep_sec"
451+
ifconfig "$iface" | grep -q "UP" && return 0
452+
fi
453+
i=$((i + 1))
454+
done
455+
return 1
456+
}
457+
458+
# Wait for a valid IPv4 address on the given interface, up to a timeout (default 30s)
459+
wait_for_ip_address() {
460+
iface="$1"
461+
timeout="${2:-30}"
462+
elapsed=0
463+
while [ "$elapsed" -lt "$timeout" ]; do
464+
ip_addr=$(get_ip_address "$iface")
465+
if [ -n "$ip_addr" ]; then
466+
if echo "$ip_addr" | grep -q '^169\.254'; then
467+
echo "$ip_addr"
468+
return 2
469+
fi
470+
echo "$ip_addr"
471+
return 0
472+
fi
473+
sleep 1
474+
elapsed=$((elapsed + 1))
475+
done
476+
return 1
477+
}
478+
479+
# Get the IPv4 address for a given interface.
480+
get_ip_address() {
481+
iface="$1"
482+
if command -v ip >/dev/null 2>&1; then
483+
ip -4 -o addr show "$iface" | awk '{print $4}' | cut -d/ -f1 | head -n1
484+
elif command -v ifconfig >/dev/null 2>&1; then
485+
ifconfig "$iface" 2>/dev/null | awk '/inet / {print $2}' | head -n1
486+
fi
487+
}
488+
489+
# Run a command with a timeout (in seconds)
490+
run_with_timeout() {
491+
timeout="$1"; shift
492+
( "$@" ) &
493+
pid=$!
494+
( sleep "$timeout"; kill "$pid" 2>/dev/null ) &
495+
watcher=$!
496+
wait $pid 2>/dev/null
497+
status=$?
498+
kill $watcher 2>/dev/null
499+
return $status
500+
}
501+
502+
# DHCP client logic (dhclient and udhcpc with timeouts)
503+
run_dhcp_client() {
504+
iface="$1"
505+
timeout="${2:-10}"
506+
ip_addr=""
507+
log_info "Attempting DHCP on $iface (timeout ${timeout}s)..."
508+
if command -v dhclient >/dev/null 2>&1; then
509+
log_info "Trying dhclient for $iface"
510+
run_with_timeout "$timeout" dhclient "$iface"
511+
ip_addr=$(wait_for_ip_address "$iface" 5)
512+
if [ -n "$ip_addr" ]; then
513+
echo "$ip_addr"
514+
return 0
515+
fi
516+
fi
517+
if command -v udhcpc >/dev/null 2>&1; then
518+
log_info "Trying udhcpc for $iface"
519+
run_with_timeout "$timeout" udhcpc -i "$iface" -T 3 -t 3
520+
ip_addr=$(wait_for_ip_address "$iface" 5)
521+
if [ -n "$ip_addr" ]; then
522+
echo "$ip_addr"
523+
return 0
524+
fi
525+
fi
526+
log_warn "DHCP failed for $iface"
527+
return 1
528+
}

0 commit comments

Comments
 (0)