Updates to TCP tickle tests and supporting functions.
authorMartin Schwenke <martin@meltin.net>
Fri, 3 Jul 2009 10:44:55 +0000 (20:44 +1000)
committerMartin Schwenke <martin@meltin.net>
Fri, 3 Jul 2009 10:44:55 +0000 (20:44 +1000)
* Removed a race from tpcdump_start().  It seems impossible to tell
  when tcpdump is actually ready to capture packets.  So this function
  now generates some dummy ping packets and waits until it sees them
  in the output file.

* tcpdump_start() sets $tcpdump_filter.  This is the default filter
  for tcpdump_wait() and tcpdump_show(), but other filters may be
  passed to those functions.

* New functions tcptickle_sniff_start() and
  tcptickle_sniff_wait_show() handle capturing TCP tickle packets.
  These are used by complex/31_nfs_tickle.sh and
  complex/32_cifs_tickle.sh.

Signed-off-by: Martin Schwenke <martin@meltin.net>
tests/complex/31_nfs_tickle.sh
tests/complex/32_cifs_tickle.sh
tests/scripts/ctdb_test_functions.bash

index 4961b7dae50786343021ebff87c684a3322c334f..542834db0d55815de29cbb80c8d299c9166cd6c5 100755 (executable)
@@ -98,18 +98,10 @@ else
     testfailures=1
 fi
 
-filter="src host $test_ip and tcp src port $test_port and dst host ${src_socket%:*} and tcp dst port ${src_socket##*:} and tcp[tcpflags] & tcp-rst != 0"
-tcpdump_start "$filter"
+tcptickle_sniff_start $src_socket "${test_ip}:${test_port}"
 
 echo "Disabling node $test_node"
 try_command_on_node 1 $CTDB disable -n $test_node
 onnode 0 $CTDB_TEST_WRAPPER wait_until_node_has_status $test_node disabled
 
-tcpdump_wait
-
-echo "GOOD: here's the tickle reset:"
-tcpdump -n -r $tcpdump_filename 2>/dev/null
-
-echo "Expect a restart..."
-
-ctdb_test_exit
+tcptickle_sniff_wait_show
index 40230c1530b69720b1255aa66353d94fef253ad0..bd1f50aa8e988da101ed4343d5596a1ba8dff01e 100755 (executable)
@@ -95,18 +95,10 @@ else
     testfailures=1
 fi
 
-filter="src host $test_ip and tcp src port $test_port and dst host ${src_socket%:*} and tcp dst port ${src_socket##*:} and tcp[tcpflags] & tcp-rst != 0"
-tcpdump_start "$filter"
+tcptickle_sniff_start $src_socket "${test_ip}:${test_port}"
 
 echo "Disabling node $test_node"
 try_command_on_node 1 $CTDB disable -n $test_node
 onnode 0 $CTDB_TEST_WRAPPER wait_until_node_has_status $test_node disabled
 
-tcpdump_wait
-
-echo "GOOD: here's the tickle reset:"
-tcpdump -n -r $tcpdump_filename 2>/dev/null
-
-echo "Expect a restart..."
-
-ctdb_test_exit
+tcptickle_sniff_wait_show
index 40f1e4fa6f2fb90432d7acee0c922d9846264bb2..b271ddea9517b1dc56b79a6bf746434c310211c3 100644 (file)
@@ -458,36 +458,93 @@ wait_until_get_src_socket ()
     wait_until 5 get_src_socket "$@"
 }
 
+#######################################
+
 # filename will be in $tcpdump_filename, pid in $tcpdump_pid
-# By default, wait for 1 matching packet on any interface.
 tcpdump_start ()
 {
-    local filter="$1"
-    local count="${2:-1}"
-    local iface="${3:-any}"
+    tcpdump_filter="$1" # global
 
-    echo "Running tcpdump to capture ${count} packet(s) on interface ${iface}."
+    echo "Running tcpdump..."
     tcpdump_filename=$(mktemp)
     ctdb_test_exit_hook_add "rm -f $tcpdump_filename"
-    tcpdump -s 1500 -w $tcpdump_filename -c "$count" -i "$iface" "$filter" &
-    tcpdump_pid=$!
-    ctdb_test_exit_hook_add "kill $tcpdump_pid >/dev/null 2>&1"
-    echo "Waiting for tcpdump output file to be initialised..."
-    wait_until 10 test -f $tcpdump_filename
-    sleep_for 1
+
+    # The only way of being sure that tcpdump is listening is to send
+    # some packets that it will see.  So we use dummy pings - the -U
+    # option to tcpdump ensures that packets are flushed to the file
+    # as they are captured.
+    local dummy_addr="127.3.2.1"
+    local dummy="icmp and dst host ${dummy_addr} and icmp[icmptype] == icmp-echo"
+    tcpdump -n -p -s 0 -e -U -w $tcpdump_filename -i any "($tcpdump_filter) or ($dummy)" &
+    ctdb_test_exit_hook_add "kill $! >/dev/null 2>&1"
+
+    echo "Waiting for tcpdump output file to be ready..."
+    ping -q "$dummy_addr" >/dev/null 2>&1 &
+    ctdb_test_exit_hook_add "kill $! >/dev/null 2>&1"
+
+    tcpdump_listen_for_dummy ()
+    {
+       tcpdump -n -r $tcpdump_filename -c 1 "$dummy" >/dev/null 2>&1
+    }
+
+    wait_until 10 tcpdump_listen_for_dummy
 }
 
-not ()
+# By default, wait for 1 matching packet.
+tcpdump_wait ()
 {
-    ! "$@"
+    local count="${1:-1}"
+    local filter="${2:-${tcpdump_filter}}"
+
+    tcpdump_check ()
+    {
+       local found=$(tcpdump -n -r $tcpdump_filename "$filter" 2>/dev/null | wc -l)
+       [ $found -ge $count ]
+    }
+
+    echo "Waiting for tcpdump to capture some packets..."
+    if ! wait_until 30 tcpdump_check ; then
+       echo "DEBUG:"
+       local i
+       for i in "ctdb status" "netstat -tanp" "tcpdump -n -e -r $tcpdump_filename" ; do
+           echo "$i"
+           $i || true
+       done
+       return 1
+    fi
 }
 
-tcpdump_wait ()
+tcpdump_show ()
+{
+    local filter="${1:-${tcpdump_filter}}"
+
+    tcpdump -n -r $tcpdump_filename  "$filter" 2>/dev/null
+}
+
+tcptickle_sniff_start ()
 {
-    echo "Waiting for tcpdump to complete..."
-    wait_until 5 not kill -0 $tcpdump_pid >/dev/null 2>&1      
+    local src="$1"
+    local dst="$2"
+
+    local in="src host ${dst%:*} and tcp src port ${dst##*:} and dst host ${src%:*} and tcp dst port ${src##*:}"
+    local out="src host ${src%:*} and tcp src port ${src##*:} and dst host ${dst%:*} and tcp dst port ${dst##*:}"
+    local tickle_ack="${in} and (tcp[tcpflags] & tcp-ack != 0) and (tcp[14] == 4) and (tcp[15] == 210)" # win == 1234
+    local ack_ack="${out} and (tcp[tcpflags] & tcp-ack != 0)"
+    tcptickle_reset="${in} and tcp[tcpflags] & tcp-rst != 0"
+    local filter="(${tickle_ack}) or (${ack_ack}) or (${tcptickle_reset})"
+
+    tcpdump_start "$filter"
 }
 
+tcptickle_sniff_wait_show ()
+{
+    tcpdump_wait 1 "$tcptickle_reset"
+
+    echo "GOOD: here are some TCP tickle packets:"
+    tcpdump_show
+}
+
+
 #######################################
 
 daemons_stop ()