Skip to content

Commit ac1afaf

Browse files
committed
[tests] address PR review comments for 1.4.3 default route test
This commit addresses unresolved review comments on PR openthread#3443: - Add 'iproute2' to border-router Dockerfile and use 'docker exec' instead of 'nsenter' to delete the default route inside the OTBR container. This removes the requirement for root privileges on the host VM/runner to run the tests. - Add 'procps' package to the test client image in test_dind_dns_sd.sh to ensure 'pgrep' and 'pkill' commands are available for radvd. - Include radvd and tcpdump logs from eth2-server in test_teardown. - Print radvd.log from eth2-server if Step 10 ping unexpectedly succeeded to ease debugging of routing issues. Note: The suggestion to use SIGHUP (pkill -HUP radvd) was evaluated but rejected because radvd does not immediately send a Router Lifetime 0 RA upon reload, causing the default route to remain active on the DUT and failing the verification in Step 10. The original kill/restart approach is maintained as it guarantees immediate route withdrawal.
1 parent af0ffb6 commit ac1afaf

4 files changed

Lines changed: 57 additions & 29 deletions

File tree

etc/docker/border-router/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ RUN set -x \
134134
curl \
135135
ipset \
136136
iptables \
137+
iproute2 \
137138
libjsoncpp25 \
138139
xz-utils \
139140
&& PLATFORM_SPEC="${TARGETARCH}${TARGETVARIANT:+/$TARGETVARIANT}" \

tests/scripts/expect/dind_1_4_pic_tc_1.exp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ send_user "OMR prefix verified in Thread Network Data successfully.\n"
202202
send_user "Step 4b: Validating RA on adjacent infrastructure link...\n"
203203
set py_ra_sniffer {import sys
204204
import ipaddress
205+
import logging
206+
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
205207
from scapy.all import *
206208

207209
target_prefix = sys.argv[1]
@@ -258,7 +260,7 @@ def check_pkt(pkt):
258260
return False
259261

260262
# Sniff until check_pkt returns True, or timeout
261-
sniff(filter="icmp6 and ip6[40] == 134", stop_filter=check_pkt, timeout=20)
263+
sniff(filter="icmp6 and icmp6[0] == 134", stop_filter=check_pkt, timeout=20)
262264

263265
if not found_otbr_ra:
264266
print("FAIL: OTBR RA packet not captured")

tests/scripts/expect/dind_1_4_pic_tc_3.exp

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@
2929

3030
source "tests/scripts/expect/_common.exp"
3131

32+
proc start_radvd {server} {
33+
exec docker exec -d $server bash -c "radvd -C /etc/radvd.conf -u root -n -m stderr >/var/log/radvd.log 2>&1"
34+
sleep 1
35+
if {[catch {exec docker exec -i $server pgrep radvd} radvd_pid]} {
36+
if {![catch {exec docker exec -i $server cat /var/log/radvd.log} radvd_log]} {
37+
send_user "\n=== radvd.log ===\n$radvd_log\n=== end of radvd.log ===\n"
38+
}
39+
fail "Failed to start radvd on $server: $radvd_pid"
40+
}
41+
send_user "radvd started on $server with PID: [string trim $radvd_pid]\n"
42+
}
43+
44+
3245
set pty1 [create_socat_tcp 1 9000]
3346
set container "otbr-test-container"
3447
set eth2_server "eth2-server"
@@ -52,11 +65,12 @@ exec docker run -d \
5265
# Wait for eth2-server eth0 to be ready
5366
sleep 2
5467

55-
# Add 2002:1234::1234 IP to loopback of eth2-server
68+
# Add 2002:1234::1234 IP to loopback and 2001:db8:1::1 to eth0 of eth2-server
5669
exec docker exec -i $eth2_server ip -6 addr add 2002:1234::1234/128 dev lo
70+
exec docker exec -i $eth2_server ip -6 addr add 2001:db8:1::1/64 dev eth0
5771

5872
# Configure and start Kea DHCPv6 PD server on eth2-server (delegating 2005:1234:abcd:0::/56)
59-
set kea_conf {{"Dhcp6": {"interfaces-config": {"interfaces": ["eth0"]}, "lease-database": {"type": "memfile", "persist": true, "name": "/var/lib/kea/kea-leases6.csv"}, "preferred-lifetime": 54000, "valid-lifetime": 86400, "subnet6": [{"subnet": "fd00:db8:1::/64", "interface": "eth0", "pd-pools": [{"prefix": "2005:1234:abcd:0::", "prefix-len": 56, "delegated-len": 64}], "rapid-commit": true}], "loggers": [{"name": "kea-dhcp6", "output_options": [{"output": "stdout"}], "severity": "DEBUG", "debuglevel": 99}]}}}
73+
set kea_conf {{"Dhcp6": {"interfaces-config": {"interfaces": ["eth0"]}, "lease-database": {"type": "memfile", "persist": true, "name": "/var/lib/kea/kea-leases6.csv"}, "preferred-lifetime": 54000, "valid-lifetime": 86400, "subnet6": [{"subnet": "2001:db8:1::/64", "interface": "eth0", "pd-pools": [{"prefix": "2005:1234:abcd:0::", "prefix-len": 56, "delegated-len": 64}], "rapid-commit": true}], "loggers": [{"name": "kea-dhcp6", "output_options": [{"output": "stdout"}], "severity": "DEBUG", "debuglevel": 99}]}}}
6074
exec docker exec -i $eth2_server bash -c "echo '$kea_conf' > /etc/kea/kea-dhcp6.conf"
6175
exec docker exec -i $eth2_server mkdir -p /var/lib/kea /var/run/kea
6276
exec docker exec -d $eth2_server /usr/sbin/kea-dhcp6 -c /etc/kea/kea-dhcp6.conf
@@ -70,16 +84,7 @@ exec docker exec -i $eth2_server sysctl -w net.ipv6.conf.eth0.forwarding=1
7084
set radvd_conf "interface eth0\n{\n AdvSendAdvert on;\n MinRtrAdvInterval 3;\n MaxRtrAdvInterval 10;\n prefix 2001:db8:1::/64\n {\n AdvOnLink on;\n AdvAutonomous on;\n AdvRouterAddr on;\n };\n};"
7185
exec docker exec -i $eth2_server bash -c "echo '$radvd_conf' > /etc/radvd.conf"
7286
exec docker exec -i $eth2_server chmod 600 /etc/radvd.conf
73-
exec docker exec -d $eth2_server bash -c "radvd -C /etc/radvd.conf -u root -n -m stderr >/var/log/radvd.log 2>&1"
74-
sleep 1
75-
76-
if {[catch {exec docker exec -i $eth2_server pgrep radvd} radvd_pid]} {
77-
if {![catch {exec docker exec -i $eth2_server cat /var/log/radvd.log} radvd_log]} {
78-
send_user "\n=== radvd.log ===\n$radvd_log\n=== end of radvd.log ===\n"
79-
}
80-
fail "Failed to start radvd on eth2-server: $radvd_pid"
81-
}
82-
send_user "radvd started on eth2-server with PID: [string trim $radvd_pid]\n"
87+
start_radvd $eth2_server
8388

8489
# 2. Start Eth_1 container (Local Infrastructure Host)
8590
send_user "Starting Eth_1 container (Local Host)...\n"
@@ -122,15 +127,14 @@ start_otbr_docker_dind $container $::env(EXP_OT_RCP_PATH) 2 $pty1
122127
# Wait for otbr-agent to create the domain socket
123128
wait_for_otbr_agent [list $container]
124129

130+
# Delete Docker's static default route so the DUT only relies on RAs
131+
# We can run it via docker exec now that iproute2 package is added to the container
132+
catch { exec docker exec -i $container ip -6 route del default dev eth0 }
133+
125134
# Enable accept_ra=2 on DUT so it configures default route and GUA via SLAAC
126135
exec docker exec -i $container sysctl -w net.ipv6.conf.all.accept_ra=2
127136
exec docker exec -i $container sysctl -w net.ipv6.conf.eth0.accept_ra=2
128137

129-
# Delete Docker's static default route so the DUT only relies on RAs
130-
set dut_pid [exec docker inspect -f {{{.State.Pid}}} $container]
131-
set dut_pid [string trim $dut_pid]
132-
exec nsenter -t $dut_pid -n ip -6 route del default dev eth0
133-
134138
# Setup active dataset on OTBR via ot-ctl
135139
exec docker exec -i $container ot-ctl thread stop
136140
exec docker exec -i $container ot-ctl ifconfig down
@@ -170,12 +174,11 @@ if {!$prefix_acquired} {
170174
}
171175
send_user "Successfully Discovered Delegated Prefix: $delegated_prefix\n"
172176

173-
174177
# Verify OMR prefix properties in netdata (subprefix of 2005:1234:abcd:0::/56, /64, default route, med preference)
175178
# AND verify default route ::/0 with Route sub-TLV (NP=0)
176179
proc verify_netdata {container} {
177180
set omr_regex {2005:1234:abcd:(?:[0-9a-fA-F]{1,2})?::/64\s+([a-z]*r[a-z]*)\s+med}
178-
set route_regex {::/0\s+([a-z]*)\s+med}
181+
set route_regex {::/0(?:\s+([a-z]+))?\s+med}
179182
set netdata_verified false
180183
for {set i 0} {$i < 10} {incr i} {
181184
if {![catch {exec docker exec -i $container ot-ctl netdata show} netdata]} {
@@ -331,10 +334,17 @@ send_user "Ping to Internet Server verified successfully.\n"
331334
# Step 7: Reconfigure radvd on eth2-server to stop advertising default route
332335
send_user "Step 7: Reconfiguring radvd to stop advertising default route...\n"
333336
catch {exec docker exec -i $eth2_server pkill radvd}
337+
# Wait for radvd to fully terminate to avoid port/socket binding conflicts
338+
for {set j 0} {$j < 50} {incr j} {
339+
if {[catch {exec docker exec -i $eth2_server pgrep radvd}]} {
340+
break
341+
}
342+
after 100
343+
}
334344
set radvd_conf_no_default "interface eth0\n{\n AdvSendAdvert on;\n MinRtrAdvInterval 3;\n MaxRtrAdvInterval 10;\n AdvDefaultLifetime 0;\n prefix 2001:db8:1::/64\n {\n AdvOnLink on;\n AdvAutonomous on;\n AdvRouterAddr on;\n };\n};"
335345
exec docker exec -i $eth2_server bash -c "echo '$radvd_conf_no_default' > /etc/radvd.conf"
336-
exec docker exec -d $eth2_server bash -c "radvd -C /etc/radvd.conf -u root -n -m stderr >/var/log/radvd.log 2>&1"
337-
sleep 5
346+
start_radvd $eth2_server
347+
sleep 4
338348

339349
# Step 8: Verify DUT *still* advertises default route in Thread Network Data
340350
send_user "Step 8: Verifying default route is still advertised in Thread Network Data...\n"
@@ -392,9 +402,9 @@ send_user "Ping to Local Host verified successfully.\n"
392402
# Step 10: Ping 2002:1234::1234 from ED_1. Ping response MUST NOT be received. Ping request MUST NOT be sent on AIL.
393403
send_user "Step 10: Verifying Ping to Internet Server does NOT work and is NOT forwarded...\n"
394404

395-
# Start tcpdump on eth2-server to detect any ICMPv6 echo requests
405+
# Start tcpdump on eth2-server to detect any ICMPv6 echo requests (line-buffered with -l)
396406
# Run in background via exec docker exec -d. Timeout in 8 seconds to allow ping tool to finish.
397-
exec docker exec -d $eth2_server bash -c "timeout 8 tcpdump -c 1 -i eth0 'icmp6 and ip6\[40\] == 128' > /var/log/tcpdump.log 2>&1"
407+
exec docker exec -d $eth2_server bash -c "timeout 8 tcpdump -l -c 1 -i eth0 'icmp6 and icmp6\[0\] == 128' > /var/log/tcpdump.log 2>&1"
398408
sleep 1
399409

400410
# Send ping from ED_1
@@ -415,11 +425,15 @@ expect {
415425
}
416426
}
417427
if {$ping_received} {
428+
catch {
429+
set radvd_log [exec docker exec -i $eth2_server cat /var/log/radvd.log]
430+
send_user "\n=== radvd.log ===\n$radvd_log\n=== end of radvd.log ===\n"
431+
}
418432
fail "Ping from ED_1 to Internet Server succeeded, but it was expected to fail"
419433
}
420434

421435
# Check if tcpdump captured any packet
422-
sleep 5
436+
sleep 9
423437
set tcpdump_log [exec docker exec -i $eth2_server cat /var/log/tcpdump.log]
424438
send_user "tcpdump log on eth2-server:\n$tcpdump_log\n"
425439
if {![string match "*listening on*" $tcpdump_log]} {
@@ -433,10 +447,17 @@ send_user "Verified: Ping request was not forwarded to AIL and no response was r
433447
# Step 11: Reconfigure radvd on eth2-server to start advertising default route again
434448
send_user "Step 11: Reconfiguring radvd to start advertising default route again...\n"
435449
catch {exec docker exec -i $eth2_server pkill radvd}
450+
# Wait for radvd to fully terminate to avoid port/socket binding conflicts
451+
for {set j 0} {$j < 50} {incr j} {
452+
if {[catch {exec docker exec -i $eth2_server pgrep radvd}]} {
453+
break
454+
}
455+
after 100
456+
}
436457
set radvd_conf_with_default "interface eth0\n{\n AdvSendAdvert on;\n MinRtrAdvInterval 3;\n MaxRtrAdvInterval 10;\n AdvDefaultLifetime 875;\n prefix 2001:db8:1::/64\n {\n AdvOnLink on;\n AdvAutonomous on;\n AdvRouterAddr on;\n };\n};"
437458
exec docker exec -i $eth2_server bash -c "echo '$radvd_conf_with_default' > /etc/radvd.conf"
438-
exec docker exec -d $eth2_server bash -c "radvd -C /etc/radvd.conf -u root -n -m stderr >/var/log/radvd.log 2>&1"
439-
sleep 5
459+
start_radvd $eth2_server
460+
sleep 4
440461

441462
# Step 12: Verify default route is advertised in Thread Network Data
442463
send_user "Step 12: Verifying default route is advertised in Thread Network Data again...\n"

tests/scripts/test_dind_dns_sd.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,14 @@ test_teardown()
7575
echo "Active and inactive containers:"
7676
docker ps -a || true
7777
echo "Container logs:"
78-
for c in "${CONTAINER_NAME}" "otbr-test-container-1" "otbr-test-container-2" "otbr-test-container-3" "otbr-test-container-web" "test-client" "dhcp6-server"; do
78+
for c in "${CONTAINER_NAME}" "otbr-test-container-1" "otbr-test-container-2" "otbr-test-container-3" "otbr-test-container-web" "test-client" "dhcp6-server" "eth1-server" "eth2-server"; do
7979
docker logs "$c" || true
8080
done
8181

82+
echo "Radvd/Tcpdump logs on eth2-server:"
83+
docker exec -i eth2-server cat /var/log/radvd.log || true
84+
docker exec -i eth2-server cat /var/log/tcpdump.log || true
85+
8286
echo "Agent logs:"
8387
for c in "${CONTAINER_NAME}" "otbr-test-container-1" "otbr-test-container-2" "otbr-test-container-3" "otbr-test-container-web"; do
8488
docker exec -i "$c" cat /var/log/otbr-agent.log || true
@@ -141,7 +145,7 @@ test_setup()
141145
echo "Building test client image with mdns-scan and ping/ndisc6 tools..."
142146
docker build -t "${TEST_CLIENT_IMAGE}" - <<EOF
143147
FROM ubuntu:24.04
144-
RUN apt-get update && apt-get install -y mdns-scan iputils-ping ndisc6 python3-zeroconf iproute2 kea-dhcp6-server dnsmasq python3-scapy radvd tcpdump --no-install-recommends && rm -rf /var/lib/apt/lists/*
148+
RUN apt-get update && apt-get install -y mdns-scan iputils-ping ndisc6 python3-zeroconf iproute2 kea-dhcp6-server dnsmasq python3-scapy radvd tcpdump procps --no-install-recommends && rm -rf /var/lib/apt/lists/*
145149
ENTRYPOINT ["mdns-scan"]
146150
EOF
147151

0 commit comments

Comments
 (0)