diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at
index 28a9873d6..d4f334036 100644
--- a/tests/system-common-macros.at
+++ b/tests/system-common-macros.at
@@ -299,6 +299,18 @@ m4_define([OVS_START_L7],
    ]
 )
 
+# NETNS_START_TCPDUMP([namespace], [params], [name])
+#
+# Helper to properly start tcpdump and wait for the startup.
+# The tcpdump output is available in <name>.tcpdump file.
+m4_define([NETNS_START_TCPDUMP],
+    [
+     NETNS_DAEMONIZE([$1], [tcpdump -l $2 >$3.tcpdump 2>$3.stderr], [$3.pid])
+     OVS_WAIT_UNTIL([grep -q "listening" $3.stderr])
+    ]
+)
+
+
 # OVS_CHECK_VXLAN()
 #
 # Do basic check for vxlan functionality, skip the test if it's not there.
@@ -453,8 +465,7 @@ chown root:dhcpd /var/lib/dhcp /var/lib/dhcp/dhcpd6.leases
 chmod 775 /var/lib/dhcp
 chmod 664 /var/lib/dhcp/dhcpd6.leases
 
-NS_CHECK_EXEC([server], [tcpdump -nni s1 > pkt.pcap &])
-
+NETNS_START_TCPDUMP([server], [-nni s1], [server])
 NETNS_DAEMONIZE([server], [dhcpd -6 -f s1 > dhcpd.log 2>&1], [dhcpd.pid])
 ovn-nbctl --wait=hv sync
 
@@ -477,22 +488,20 @@ ovn-nbctl list logical_router_port rp-public > /tmp/rp-public
 ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
 ovn-nbctl set logical_router_port rp-sw1 options:prefix=false
 # Renew message
-NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[48:1]]=0x05 and ip6[[113:4]]=0x${prefix} > renew.pcap &])
+NETNS_START_TCPDUMP([server], [-c 1 -nni s1 ip6[[48:1]]=0x05 and ip6[[113:4]]=0x${prefix}], [renew])
 # Reply message with Status OK
-NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[48:1]]=0x07 and ip6[[81:4]]=0x${prefix} > reply.pcap &])
+NETNS_START_TCPDUMP([server], [-c 1 -nni s1 ip6[[48:1]]=0x07 and ip6[[81:4]]=0x${prefix}], [reply])
 
 OVS_WAIT_UNTIL([
-    total_pkts=$(cat renew.pcap | wc -l)
+    total_pkts=$(cat renew.tcpdump | wc -l)
     test "${total_pkts}" = "1"
 ])
 
 OVS_WAIT_UNTIL([
-    total_pkts=$(cat reply.pcap | wc -l)
+    total_pkts=$(cat reply.tcpdump | wc -l)
     test "${total_pkts}" = "1"
 ])
 
-kill $(pidof tcpdump)
-
 ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
 ovn-nbctl clear logical_router_port rp-sw0 ipv6_prefix
 OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16)" = "[2001:1db8:3333]"])
diff --git a/tests/system-ovn-kmod.at b/tests/system-ovn-kmod.at
index db4191f31..7122b909c 100644
--- a/tests/system-ovn-kmod.at
+++ b/tests/system-ovn-kmod.at
@@ -320,14 +320,10 @@ while True:
 NETNS_DAEMONIZE([server], [$PYTHON3 ./server.py > server.log], [server.pid])
 
 dnl Collect packets on server side.
-NETNS_DAEMONIZE([server], [tcpdump -l -U -i server -vnne \
-          'ip and (icmp or udp)' > server.tcpdump 2>server_err], [tcpdump0.pid])
-OVS_WAIT_UNTIL([grep "listening" server_err])
+NETNS_START_TCPDUMP([server], [-U -i server -vnne 'ip and (icmp or udp)'], [tcpdump-server])
 
 dnl Collect packets on client side.
-NETNS_DAEMONIZE([client], [tcpdump -l -U -i client -vnne \
-          'ip and (icmp or udp)' > client.tcpdump 2>client_err], [tcpdump1.pid])
-OVS_WAIT_UNTIL([grep "listening" client_err])
+NETNS_START_TCPDUMP([client], [-U -i client -vnne 'ip and (icmp or udp)'], [tcpdump-client])
 
 dnl Send two packets to the server with a short interval.
 dnl First packet should generate 'needs frag', the second should result in
@@ -345,7 +341,7 @@ time.sleep(5)
 NS_CHECK_EXEC([client], [$PYTHON3 ./client.py])
 
 dnl Expecting 2 outgoing packets and 2 fragments back - 8 lines total.
-OVS_WAIT_UNTIL([test "$(cat client.tcpdump | wc -l)" = "8"])
+OVS_WAIT_UNTIL([test "$(cat tcpdump-client.tcpdump | wc -l)" = "8"])
 
 ovn-appctl -t ovn-controller vlog/set info
 
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 9e2507a7a..d66c9ab63 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -1602,12 +1602,11 @@ OVS_WAIT_UNTIL([
 ovn-nbctl --reject lb-add lb3 30.0.0.10:80 ""
 ovn-nbctl ls-lb-add foo lb3
 # Filter reset segments
-NS_CHECK_EXEC([foo1], [tcpdump -l -c 1 -neei foo1 ip[[33:1]]=0x14 > rst.pcap 2>tcpdump_err &])
-OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+NETNS_START_TCPDUMP([foo1], [-c 1 -neei foo1 ip[[33:1]]=0x14], [rst])
 NS_CHECK_EXEC([foo1], [wget -q 30.0.0.10],[4])
 
 OVS_WAIT_UNTIL([
-    n_reset=$(cat rst.pcap | wc -l)
+    n_reset=$(cat rst.tcpdump | wc -l)
     test "${n_reset}" = "1"
 ])
 
@@ -3644,8 +3643,7 @@ icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src
 ])
 
 # Try to ping external network
-NS_CHECK_EXEC([ext-net], [tcpdump -l -n -c 3 -i ext-veth dst 172.16.1.3 and icmp > ext-net.pcap 2>tcpdump_err &])
-OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+NETNS_START_TCPDUMP([ext-net], [-n -c 3 -i ext-veth dst 172.16.1.3 and icmp], [ext-net])
 AT_CHECK([ovn-nbctl lr-nat-del R1 snat])
 NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.1 | FORMAT_PING], \
 [0], [dnl
@@ -3653,7 +3651,7 @@ NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.1 | FORMAT_PING], \
 ])
 
 OVS_WAIT_UNTIL([
-    total_pkts=$(cat ext-net.pcap | wc -l)
+    total_pkts=$(cat ext-net.tcpdump | wc -l)
     test "${total_pkts}" = "3"
 ])
 
@@ -4391,19 +4389,19 @@ ovn-nbctl set Logical_Switch sw2 \
     other_config:mcast_ip6_src="2000::fe"
 
 # Check that v4 queries are generated.
-NS_CHECK_EXEC([sw2-p1], [tcpdump -n -c 2 -i sw2-p1 igmp > sw2-p1-v4.pcap &])
+NETNS_START_TCPDUMP([sw2-p1], [-n -c 2 -i sw2-p1 igmp], [sw2-p1-v4])
 
 OVS_WAIT_UNTIL([
-    total_queries=`grep "igmp query" -c sw2-p1-v4.pcap`
+    total_queries=`grep "igmp query" -c sw2-p1-v4.tcpdump`
     test "${total_queries}" = "2"
 ])
 
 # Check that v6 queries are generated (ip6 next header == Hop-By-Hop and
 # icmpv6 type == MLD Query).
-NS_CHECK_EXEC([sw2-p1], [tcpdump -n -c 2 -i sw2-p1 ip6[[6]]==0 and ip6[[48]]==0x82 > sw2-p1-v6.pcap &])
+NETNS_START_TCPDUMP([sw2-p1], [-n -c 2 -i sw2-p1 ip6[[6]]==0 and ip6[[48]]==0x82], [sw2-p1-v6])
 
 OVS_WAIT_UNTIL([
-    total_queries=`grep "multicast listener query" -c sw2-p1-v6.pcap`
+    total_queries=`grep "multicast listener query" -c sw2-p1-v6.tcpdump`
     test "${total_queries}" = "2"
 ])
 
@@ -4621,13 +4619,13 @@ service_monitor protocol=udp | sed '/^$/d' | grep offline | wc -l`])
 pid_file=$(cat l7_pid_file)
 NS_CHECK_EXEC([sw1-p1], [kill $(cat $pid_file)])
 
-NS_CHECK_EXEC([sw0-p2], [tcpdump -c 1 -neei sw0-p2 ip[[33:1]]=0x14 > rst.pcap &])
+NETNS_START_TCPDUMP([sw0-p2], [-c 1 -neei sw0-p2 ip[[33:1]]=0x14], [rst])
 OVS_WAIT_UNTIL([test 2 = `ovn-sbctl --bare --columns status find \
 service_monitor protocol=tcp | sed '/^$/d' | grep offline | wc -l`])
 NS_CHECK_EXEC([sw0-p2], [wget 10.0.0.10 -v -o wget$i.log],[4])
 
 OVS_WAIT_UNTIL([
-    n_reset=$(cat rst.pcap | wc -l)
+    n_reset=$(cat rst.tcpdump | wc -l)
     test "${n_reset}" = "1"
 ])
 
@@ -4710,8 +4708,7 @@ NS_CHECK_EXEC([lsp], [nc 88.88.88.90 4041 -z], [0], [ignore], [ignore])
 
 # Capture IPv4 UDP hairpinned packets.
 filter="dst 42.42.42.1 and dst port 2021 and udp"
-NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp ${filter} > lsp.pcap 2>tcpdump_err &])
-OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+NETNS_START_TCPDUMP([lsp], [-nn -c 3 -i lsp ${filter}], [lsp])
 
 # Generate IPv4 UDP hairpin traffic.
 NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.88 4040 &], [0])
@@ -4720,7 +4717,7 @@ NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.90 2021 &], [0])
 
 # Check hairpin traffic.
 OVS_WAIT_UNTIL([
-    total_pkts=$(cat lsp.pcap | wc -l)
+    total_pkts=$(cat lsp.tcpdump | wc -l)
     test "${total_pkts}" = "3"
 ])
 
@@ -4808,8 +4805,7 @@ NS_CHECK_EXEC([lsp], [nc 8800::0090 4041 -z], [0], [ignore], [ignore])
 
 # Capture IPv6 UDP hairpinned packets.
 filter="dst 4200::1 and dst port 2021 and udp"
-NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp $filter > lsp.pcap 2>tcpdump_err &])
-OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
+NETNS_START_TCPDUMP([lsp], [-nn -c 3 -i lsp $filter], [lsp])
 
 # Generate IPv6 UDP hairpin traffic.
 NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0088 4040 &], [0])
@@ -4818,7 +4814,7 @@ NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0090 2021 &], [0])
 
 # Check hairpin traffic.
 OVS_WAIT_UNTIL([
-    total_pkts=$(cat lsp.pcap | wc -l)
+    total_pkts=$(cat lsp.tcpdump | wc -l)
     test "${total_pkts}" = "3"
 ])
 
@@ -4934,7 +4930,7 @@ ADD_VETH(sw1-p1-rej, sw1-p1-rej, br-int, "20.0.0.3/24", "40:54:00:00:00:03", \
 sleep 1
 
 # Capture packets in sw0-p1-rej.
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 4 -i sw0-p1-rej tcp > sw0-p1-rej-ip4.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 4 -i sw0-p1-rej tcp], [sw0-p1-rej-ip4])
 
 sleep 1
 
@@ -4954,7 +4950,7 @@ grep controller | grep tp_dst=84 -c)
 ])
 
 OVS_WAIT_UNTIL([
-    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
+    total=`cat sw0-p1-rej-ip4.tcpdump |  wc -l`
     echo "total = $total"
     test "${total}" = "4"
 ])
@@ -4962,8 +4958,7 @@ OVS_WAIT_UNTIL([
 # Without this sleep, test case fails intermittently.
 sleep 3
 
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2-rej-ip6.pcap &], [0])
-
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 2 -i sw0-p2-rej tcp port 80], [sw0-p2-rej-ip6])
 sleep 1
 
 OVS_WAIT_UNTIL([
@@ -4972,7 +4967,7 @@ OVS_WAIT_UNTIL([
 
 
 OVS_WAIT_UNTIL([
-    total=`cat sw0-p2-rej-ip6.pcap |  wc -l`
+    total=`cat sw0-p2-rej-ip6.tcpdump |  wc -l`
     echo "total = $total"
     test "${total}" = "2"
 ])
@@ -4986,49 +4981,51 @@ OVS_WAIT_UNTIL([
 ])
 
 # Now test for IPv4 UDP.
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej udp port 90], [sw0-p1-rej-udp])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej icmp], [sw0-p1-rej-icmp])
 
 printf '.%.0s' {1..100} > foo
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
-    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+    c=$(cat sw0-p1-rej-icmp.tcpdump | grep \
 "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l)
     test $c -ge 1
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej udp port 94 > sw0-p1-rej-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej udp port 94], [sw0-p1-rej-udp])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej icmp], [sw0-p1-rej-icmp])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo
-    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+    c=$(cat sw0-p1-rej-icmp.tcpdump | grep \
 "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 94 unreachable" | uniq | wc -l)
     test $c -ge 1
 ])
 
 # Now test for IPv6 UDP.
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej udp port 90 > sw0-p2-rej-ip6-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej udp port 90], [sw0-p2-rej-ip6-udp])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej icmp6], [sw0-p2-rej-icmp6])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
-    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+    c=$(cat sw0-p2-rej-icmp6.tcpdump | grep \
 "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
 aef0::3 udp port 90" | uniq | wc -l)
     test $c -ge 1
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej udp port 94 > sw0-p2-rej-ip6-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej udp port 94], [sw0-p2-rej-ip6-udp])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej icmp6], [sw0-p2-rej-icmp6])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -u -6 aef0::3 94 < foo
-    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+    c=$(cat sw0-p2-rej-icmp6.tcpdump | grep \
 "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
 aef0::3 udp port 94" | uniq | wc -l)
     test $c -ge 1
@@ -5047,31 +5044,32 @@ OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -vz6 aef0::3 80 2>&1 | grep -i 'connection refused'
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej icmp], [sw0-p1-rej-icmp])
 
 printf '.%.0s' {1..100} > foo
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
-    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+    c=$(cat sw0-p1-rej-icmp.tcpdump | grep \
 "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l)
     test $c -ge 1
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 # Now test for IPv6 UDP.
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej icmp6], [sw0-p2-rej-icmp6])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
-    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+    c=$(cat sw0-p2-rej-icmp6.tcpdump | grep \
 "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
 aef0::3 udp port 90" | uniq | wc -l)
     test $c -ge 1
 ])
 
-
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb
@@ -5175,7 +5173,7 @@ ADD_VETH(sw1-p1-rej, sw1-p1-rej, br-int, "20.0.0.3/24", "40:54:00:00:00:03", \
 sleep 1
 
 # Capture packets in sw0-p1-rej.
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 4 -i sw0-p1-rej tcp > sw0-p1-rej-ip4.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 4 -i sw0-p1-rej tcp ], [sw0-p1-rej-ip4])
 
 sleep 1
 
@@ -5195,7 +5193,7 @@ grep controller | grep tp_dst=84 -c)
 ])
 
 OVS_WAIT_UNTIL([
-    total=`cat sw0-p1-rej-ip4.pcap |  wc -l`
+    total=`cat sw0-p1-rej-ip4.tcpdump |  wc -l`
     echo "total = $total"
     test "${total}" = "4"
 ])
@@ -5203,7 +5201,7 @@ OVS_WAIT_UNTIL([
 # Without this sleep, test case fails intermittently.
 sleep 3
 
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2-rej-ip6.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 2 -i sw0-p2-rej tcp port 80], [sw0-p2-rej-ip6])
 
 sleep 1
 
@@ -5213,7 +5211,7 @@ OVS_WAIT_UNTIL([
 
 
 OVS_WAIT_UNTIL([
-    total=`cat sw0-p2-rej-ip6.pcap |  wc -l`
+    total=`cat sw0-p2-rej-ip6.tcpdump |  wc -l`
     echo "total = $total"
     test "${total}" = "2"
 ])
@@ -5227,49 +5225,51 @@ OVS_WAIT_UNTIL([
 ])
 
 # Now test for IPv4 UDP.
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej udp port 90], [sw0-p1-rej-udp])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej icmp], [sw0-p1-rej-icmp])
 
 printf '.%.0s' {1..100} > foo
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
-    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+    c=$(cat sw0-p1-rej-icmp.tcpdump | grep \
 "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l)
     test $c -ge 1
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej udp port 94 > sw0-p1-rej-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej udp port 94], [sw0-p1-rej-udp])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej icmp], [sw0-p1-rej-icmp])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo
-    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+    c=$(cat sw0-p1-rej-icmp.tcpdump | grep \
 "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 94 unreachable" | uniq | wc -l)
     test $c -ge 1
 ])
 
 # Now test for IPv6 UDP.
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej udp port 90 > sw0-p2-rej-ip6-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej udp port 90], [sw0-p2-rej-ip6-udp])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej icmp6], [sw0-p2-rej-icmp6])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
-    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+    c=$(cat sw0-p2-rej-icmp6.tcpdump | grep \
 "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
 aef0::3 udp port 90" | uniq | wc -l)
     test $c -ge 1
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej udp port 94 > sw0-p2-rej-ip6-udp.pcap &], [0])
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej udp port 94], [sw0-p2-rej-ip6-udp])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej icmp6], [sw0-p2-rej-icmp6])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -u -6 aef0::3 94 < foo
-    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+    c=$(cat sw0-p2-rej-icmp6.tcpdump | grep \
 "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
 aef0::3 udp port 94" | uniq | wc -l)
     test $c -ge 1
@@ -5288,25 +5288,27 @@ OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -vz6 aef0::3 80 2>&1 | grep -i 'connection refused'
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 
-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -nn -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p1-rej], [-nn -c 1 -i sw0-p1-rej icmp], [sw0-p1-rej-icmp])
 
 printf '.%.0s' {1..100} > foo
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo
-    c=$(cat sw0-p1-rej-icmp.pcap | grep \
+    c=$(cat sw0-p1-rej-icmp.tcpdump | grep \
 "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l)
     test $c -ge 1
 ])
 
-rm -f *.pcap
+kill $(pidof tcpdump)
+rm -f *.tcpdump
 # Now test for IPv6 UDP.
-NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -nn -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0])
+NETNS_START_TCPDUMP([sw0-p2-rej], [-nn -c 1 -i sw0-p2-rej icmp6], [sw0-p2-rej-icmp6])
 
 OVS_WAIT_UNTIL([
     ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo
-    c=$(cat sw0-p2-rej-icmp6.pcap | grep \
+    c=$(cat sw0-p2-rej-icmp6.tcpdump | grep \
 "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \
 aef0::3 udp port 90" | uniq | wc -l)
     test $c -ge 1
@@ -6466,10 +6468,10 @@ OVS_WAIT_UNTIL([ovn-sbctl dump-flows R1 | grep 'match=(ip4.dst == 100.0.0.0/8)'
 check ovn-nbctl clear logical_router_static_route $route_uuid bfd
 wait_column "admin_down" nb:bfd status logical_port=rp-public
 OVS_WAIT_UNTIL([ip netns exec server bfdd-control status | grep -qi state=Down])
-NS_CHECK_EXEC([server], [tcpdump -nni s1 udp port 3784 -Q in > bfd.pcap &])
+NETNS_START_TCPDUMP([server], [-nni s1 udp port 3784 -Q in], [bfd])
 sleep 5
 kill $(pidof tcpdump)
-AT_CHECK([grep -qi bfd bfd.pcap],[1])
+AT_CHECK([grep -qi bfd bfd.tcpdump],[1])
 
 # restart the connection
 check ovn-nbctl set logical_router_static_route $route_uuid bfd=$uuid
@@ -6495,10 +6497,10 @@ OVS_WAIT_UNTIL([test "$(ovn-sbctl dump-flows R1 | grep 'match=(ip4.dst == 100.0.
 # remove bfd entry
 ovn-nbctl destroy bfd $uuid
 check_row_count bfd 0
-NS_CHECK_EXEC([server], [tcpdump -nni s1 udp port 3784 -Q in > bfd.pcap &])
+NETNS_START_TCPDUMP([server], [-nni s1 udp port 3784 -Q in], [bfd])
 sleep 5
 kill $(pidof tcpdump)
-AT_CHECK([grep -qi bfd bfd.pcap],[1])
+AT_CHECK([grep -qi bfd bfd.tcpdump],[1])
 
 uuid_v6=$(ovn-nbctl create bfd logical_port=rp-public dst_ip=\"1000::b\")
 check ovn-nbctl lr-route-add R1 2000::/64 1000::b
@@ -6944,7 +6946,7 @@ check ovn-nbctl lsp-add public public1 \
         -- lsp-set-type public1 localnet \
         -- lsp-set-options public1 network_name=phynet
 
-NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
+NETNS_START_TCPDUMP([sw01], [-n -i sw01 icmp -Q in], [reject])
 check ovn-nbctl meter-add acl-meter drop 1 pktps 0
 check ovn-nbctl copp-add copp0 reject acl-meter
 check ovn-nbctl ls-copp-add copp0 sw0
@@ -6961,14 +6963,14 @@ EOF
 
 # 1pps
 OVS_WAIT_UNTIL([
-    n_reject=$(grep unreachable reject.pcap | wc -l)
+    n_reject=$(grep unreachable reject.tcpdump | wc -l)
     test "${n_reject}" = "1"
 ])
 kill $(pidof tcpdump)
-rm -f reject.pcap
+rm -f reject.tcpdump
 
 # Let's update the meter
-NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
+NETNS_START_TCPDUMP([sw01], [-n -i sw01 icmp -Q in], [reject])
 check ovn-nbctl --may-exist --wait=hv meter-add acl-meter drop 10 pktps 0
 ip netns exec sw01 scapy -H <<-EOF
 p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64)
@@ -6977,14 +6979,14 @@ EOF
 
 # 10pps
 OVS_WAIT_UNTIL([
-    n_reject=$(grep unreachable reject.pcap | wc -l)
+    n_reject=$(grep unreachable reject.tcpdump | wc -l)
     test "${n_reject}" = "10"
 ])
 
 kill $(pidof tcpdump)
-rm -f reject.pcap
+rm -f reject.tcpdump
 
-NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
+NETNS_START_TCPDUMP([sw01], [-n -i sw01 icmp -Q in], [reject])
 check ovn-nbctl --wait=hv copp-del copp0 reject
 
 ip netns exec sw01 scapy -H <<-EOF
@@ -6993,12 +6995,11 @@ send (p, iface='sw01', loop = 0, verbose = 0, count = 20)
 EOF
 
 OVS_WAIT_UNTIL([
-    n_reject=$(grep unreachable reject.pcap | wc -l)
+    n_reject=$(grep unreachable reject.tcpdump | wc -l)
     test "${n_reject}" = "20"
 ])
-kill $(pidof tcpdump)
 
-NS_EXEC([server], [tcpdump -l -n -i s1 arp[[24:4]]=0xac100164 > arp.pcap &])
+NETNS_START_TCPDUMP([server], [-n -i s1 arp[[24:4]]=0xac100164], [arp])
 check ovn-nbctl meter-add arp-meter drop 1 pktps 0
 check ovn-nbctl copp-add copp1 arp-resolve arp-meter
 check ovn-nbctl --wait=hv lr-copp-add copp1 R1
@@ -7013,10 +7014,9 @@ EOF
 
 # 1pps
 OVS_WAIT_UNTIL([
-    n_arp=$(grep ARP arp.pcap | wc -l)
+    n_arp=$(grep ARP arp.tcpdump | wc -l)
     test "${n_arp}" = "1"
 ])
-kill $(pidof tcpdump)
 
 check ovn-nbctl meter-add icmp-meter drop 1 pktps 0
 check ovn-nbctl copp-add copp2 icmp4-error icmp-meter
@@ -7025,7 +7025,7 @@ AT_CHECK([ovn-nbctl copp-list copp2 |grep icmp4-error], [0], [dnl
 icmp4-error: icmp-meter
 ])
 
-NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp > icmp.pcap &])
+NETNS_START_TCPDUMP([sw01], [-n -i sw01 icmp], [icmp])
 ip netns exec sw01 scapy -H <<-EOF
 p = IP(src="192.168.1.2", dst="172.16.1.100", ttl=1) / TCP(dport = 8080, flags="S") / Raw(b"X"*64)
 send (p, iface='sw01', loop = 0, verbose = 0, count = 100)
@@ -7033,10 +7033,9 @@ EOF
 
 # 1pps
 OVS_WAIT_UNTIL([
-    n_icmp=$(grep ICMP icmp.pcap | wc -l)
+    n_icmp=$(grep ICMP icmp.tcpdump | wc -l)
     test "${n_icmp}" = "1"
 ])
-kill $(pidof tcpdump)
 
 check ovn-nbctl meter-add bfd-meter drop 1 pktps 0
 check ovn-nbctl copp-add copp3 bfd bfd-meter
@@ -7047,7 +7046,7 @@ bfd: bfd-meter
 
 check ovn-nbctl --bfd lr-route-add R1 240.0.0.0/8 172.16.1.50 rp-public
 printf "%08x" $(ovn-sbctl get bfd . disc) > /tmp/disc
-NS_EXEC([server], [tcpdump -l -nn -i s1 udp port 3784 and ip[[29]]==0x90 -Q in > bfd.pcap &])
+NETNS_START_TCPDUMP([server], [-nn -i s1 udp port 3784 and ip[[29]]==0x90 -Q in], [bfd])
 ip netns exec server scapy -H <<-EOF
 import binascii
 f = open("/tmp/disc", "r")
@@ -7062,10 +7061,9 @@ rm /tmp/disc
 
 # 1pps
 OVS_WAIT_UNTIL([
-    n_bfd=$(grep 3784 bfd.pcap | wc -l)
+    n_bfd=$(grep 3784 bfd.tcpdump | wc -l)
     test "${n_bfd}" = "1"
 ])
-kill $(pidof tcpdump)
 
 check ovn-nbctl set nb_global . options:svc_monitor_mac="33:33:33:33:33:33"
 check ovn-nbctl meter-add svc-meter drop 1 pktps 0
@@ -8300,7 +8298,7 @@ NS_CHECK_EXEC([vm2], [ip link set lo up], [0])
 check ovs-vsctl set Interface vm2 external_ids:iface-id=vm2
 
 ADD_NAMESPACES(vm3)
-NETNS_DAEMONIZE([vm3], [tcpdump -n -i any -nnleX > vm3.pcap 2>/dev/null], [tcpdump3.pid])
+NETNS_START_TCPDUMP([vm3], [-n -i any -nnleX], [vm3])
 
 ADD_INT([vm3], [vm3], [br-int], [42.42.42.3/24])
 NS_CHECK_EXEC([vm3], [ip link set vm3 address 00:00:00:00:00:03], [0])
@@ -8318,11 +8316,11 @@ wait_igmp_flows_installed 228.0.0.1
 NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 228.0.0.1], [ignore], [ignore])
 
 OVS_WAIT_UNTIL([
-    requests=`grep "ICMP echo request" -c vm3.pcap`
+    requests=`grep "ICMP echo request" -c vm3.tcpdump`
     test "${requests}" -ge "3"
 ])
 
-NETNS_DAEMONIZE([vm2], [tcpdump -n -i any -nnleX > vm2.pcap 2>/dev/null], [tcpdump2.pid])
+NETNS_START_TCPDUMP([vm2], [-n -i any -nnleX], [vm2])
 
 for i in `seq 1 40`;do
     NS_CHECK_EXEC([vm2], [ip addr add 228.1.$i.1 dev vm2 autojoin &], [0])
@@ -8341,7 +8339,7 @@ ovn-sbctl list multicast_group
 NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 228.1.1.1], [ignore], [ignore])
 
 OVS_WAIT_UNTIL([
-    requests=`grep "ICMP echo request" -c vm2.pcap`
+    requests=`grep "ICMP echo request" -c vm2.tcpdump`
     test "${requests}" -ge "3"
 ])
 
@@ -8748,16 +8746,13 @@ test_related_traffic() {
 
     check ovs-appctl dpctl/flush-conntrack
 
-    NETNS_DAEMONIZE([client], [tcpdump -l -U -i client -w client.pcap 2>client_err], [tcpdump0.pid])
-    NETNS_DAEMONIZE([server], [tcpdump -l -U -i server -w server.pcap 2>server_err], [tcpdump1.pid])
+    NETNS_START_TCPDUMP([client], [-U -i client -w client.pcap], [tcpdump0])
+    NETNS_START_TCPDUMP([server], [-U -i server -w server.pcap], [tcpdump1])
 
     # Setup a dummy UDP listeners so we don't get "port unreachable".
     NETNS_DAEMONIZE([client], [nc -l -u 1], [nc0.pid])
     NETNS_DAEMONIZE([server], [nc -l -u 2], [nc1.pid])
 
-    OVS_WAIT_UNTIL([grep "listening" client_err])
-    OVS_WAIT_UNTIL([grep "listening" server_err])
-
     # Send UDP client -> server
     check ovs-ofctl packet-out br-int "in_port=ovs-client,packet=$client_udp,actions=resubmit(,0)"
 
