Add comprehensive tests for DNS query statistics tracking using
coverage counters in ovn-controller.

The test suite includes:
- Basic counter functionality (total queries, query types, cache hits,
  responses sent)
- Query type classification (A, AAAA, ANY records)
- Cache hit and miss tracking
- Error counter verification

Tests verify coverage counters using:
  ovn-appctl -t ovn-controller coverage/read-counter <counter_name>

The tests use OVS_WAIT_UNTIL to reliably wait for coverage counters
to update before verification, following the pattern used in other
OVN controller tests.

Signed-off-by: Ketan Supanekar <[email protected]>
---
 tests/automake.mk      |   3 +-
 tests/ovn-dns-stats.at | 497 +++++++++++++++++++++++++++++++++++++++++
 tests/testsuite.at     |   1 +
 3 files changed, 500 insertions(+), 1 deletion(-)
 create mode 100644 tests/ovn-dns-stats.at

diff --git a/tests/automake.mk b/tests/automake.mk
index c8047371b..db9cea6ee 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -48,7 +48,8 @@ TESTSUITE_AT = \
        tests/ovn-vif-plug.at \
        tests/ovn-util.at \
        tests/ovn-br-controller.at \
-       tests/ovn-inc-proc-graph-dump.at
+       tests/ovn-inc-proc-graph-dump.at \
+       tests/ovn-dns-stats.at
 
 SYSTEM_DPDK_TESTSUITE_AT = \
        tests/system-dpdk-testsuite.at \
diff --git a/tests/ovn-dns-stats.at b/tests/ovn-dns-stats.at
new file mode 100644
index 000000000..28cf1877b
--- /dev/null
+++ b/tests/ovn-dns-stats.at
@@ -0,0 +1,497 @@
+AT_BANNER([OVN DNS Statistics])
+
+# DNS Statistics - Basic functionality
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([dns statistics - basic counters])
+ovn_start
+
+# Define helper functions
+set_dns_params() {
+    local hname=$1
+    local ttl=00000e10
+    an_count=0001
+    type=0001
+    case $hname in
+    vm1)
+        query_name=03766d31036f766e036f726700
+        expected_dns_answer=${query_name}00010001${ttl}00040a000004
+        ;;
+    vm2)
+        query_name=03766d32036f766e036f726700
+        expected_dns_answer=${query_name}00010001${ttl}00040a000006
+        
expected_dns_answer=${expected_dns_answer}${query_name}00010001${ttl}000414000004
+        an_count=0002
+        ;;
+    vm3)
+        query_name=03766d33036f766e036f726700
+        expected_dns_answer=${query_name}00010001${ttl}000428000004
+        ;;
+    vm1_ipv6_only)
+        query_name=03766d31036f766e036f726700
+        type=001c
+        
expected_dns_answer=${query_name}${type}0001${ttl}0010aef00000000000000000000000000004
+        ;;
+    vm1_ipv4_v6)
+        query_name=03766d31036f766e036f726700
+        type=00ff
+        an_count=0002
+        expected_dns_answer=${query_name}00010001${ttl}00040a000004
+        
expected_dns_answer=${expected_dns_answer}${query_name}001c0001${ttl}0010
+        
expected_dns_answer=${expected_dns_answer}aef00000000000000000000000000004
+        ;;
+    vm1_invalid_type)
+        query_name=03766d31036f766e036f726700
+        type=0002
+        ;;
+    esac
+    local dns_req_header=010201200001000000000000
+    local dns_resp_header=010281200001${an_count}00000000
+    dns_req_data=${dns_req_header}${query_name}${type}0001
+    
dns_resp_data=${dns_resp_header}${query_name}${type}0001${expected_dns_answer}
+}
+
+test_dns() {
+    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 dns_reply=$6
+    local dns_query_data=$7
+    shift; shift; shift; shift; shift; shift; shift;
+    ip_len=`expr 28 + ${#dns_query_data} / 2`
+    udp_len=`expr $ip_len - 20`
+    ip_len=$(printf "%x" $ip_len)
+    udp_len=$(printf "%x" $udp_len)
+    local request=${dst_mac}${src_mac}0800450000${ip_len}0000000080110000
+    request=${request}${src_ip}${dst_ip}9234003500${udp_len}0000
+    request=${request}${dns_query_data}
+
+    if test $dns_reply != 0; then
+        local dns_reply=$1
+        ip_len=`expr 28 + ${#dns_reply} / 2`
+        udp_len=`expr $ip_len - 20`
+        ip_len=$(printf "%x" $ip_len)
+        udp_len=$(printf "%x" $udp_len)
+        local reply=${src_mac}${dst_mac}0800450000${ip_len}0000000080110000
+        reply=${reply}${dst_ip}${src_ip}0035923400${udp_len}0000${dns_reply}
+        echo $reply >> $inport.expected
+    else
+        for outport; do
+            echo $request >> $outport.expected
+        done
+    fi
+    as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
+}
+
+check ovn-nbctl ls-add ls1
+
+check ovn-nbctl lsp-add ls1 ls1-lp1 \
+-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.0.0.4"
+
+check ovn-nbctl lsp-set-port-security ls1-lp1 "f0:00:00:00:00:01 10.0.0.4"
+
+DNS1=`ovn-nbctl create DNS records={}`
+
+check ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="10.0.0.4"
+check ovn-nbctl set DNS $DNS1 records:vm2.ovn.org="10.0.0.6"
+
+check ovn-nbctl set Logical_switch ls1 dns_records="$DNS1"
+
+net_add n1
+sim_add hv1
+
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+    set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \
+    options:tx_pcap=hv1/vif1-tx.pcap \
+    options:rxq_pcap=hv1/vif1-rx.pcap \
+    ofport-request=1
+
+OVN_POPULATE_ARP
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+# Start monitoring OpenFlow
+AT_CAPTURE_FILE([ofctl_monitor0.log])
+as hv1 ovs-ofctl -t 300 monitor br-int resume --detach --no-chdir \
+--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log
+
+# Send DNS query using existing test helper
+set_dns_params vm1
+src_ip=`ip_to_hex 10 0 0 4`
+dst_ip=`ip_to_hex 10 0 0 1`
+dns_reply=1
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data 
$dns_resp_data
+
+# Wait for NXT_RESUME
+OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Verify coverage counters
+OVS_WAIT_UNTIL([test 1 = $(as hv1 ovs-appctl -t ovn-controller 
coverage/read-counter dns_query_total)])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_query_type_a], [0], [1
+])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_cache_hit], [0], [1
+])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_response_sent], [0], [1
+])
+
+# Send another query
+set_dns_params vm2
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data 
$dns_resp_data
+
+OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Verify coverage counters after second query
+OVS_WAIT_UNTIL([test 2 = $(as hv1 ovs-appctl -t ovn-controller 
coverage/read-counter dns_query_total)])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_query_type_a], [0], [2
+])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_cache_hit], [0], [2
+])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_response_sent], [0], [2
+])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+# DNS Statistics - Query types
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([dns statistics - query type classification])
+ovn_start
+
+# Define helper functions
+set_dns_params() {
+    local hname=$1
+    local ttl=00000e10
+    an_count=0001
+    type=0001
+    case $hname in
+    vm1)
+        query_name=03766d31036f766e036f726700
+        expected_dns_answer=${query_name}00010001${ttl}00040a000004
+        ;;
+    vm1_ipv6_only)
+        query_name=03766d31036f766e036f726700
+        type=001c
+        
expected_dns_answer=${query_name}${type}0001${ttl}0010aef00000000000000000000000000004
+        ;;
+    vm1_ipv4_v6)
+        query_name=03766d31036f766e036f726700
+        type=00ff
+        an_count=0002
+        expected_dns_answer=${query_name}00010001${ttl}00040a000004
+        
expected_dns_answer=${expected_dns_answer}${query_name}001c0001${ttl}0010
+        
expected_dns_answer=${expected_dns_answer}aef00000000000000000000000000004
+        ;;
+    esac
+    local dns_req_header=010201200001000000000000
+    local dns_resp_header=010281200001${an_count}00000000
+    dns_req_data=${dns_req_header}${query_name}${type}0001
+    
dns_resp_data=${dns_resp_header}${query_name}${type}0001${expected_dns_answer}
+}
+
+test_dns() {
+    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 dns_reply=$6
+    local dns_query_data=$7
+    shift; shift; shift; shift; shift; shift; shift;
+    ip_len=`expr 28 + ${#dns_query_data} / 2`
+    udp_len=`expr $ip_len - 20`
+    ip_len=$(printf "%x" $ip_len)
+    udp_len=$(printf "%x" $udp_len)
+    local request=${dst_mac}${src_mac}0800450000${ip_len}0000000080110000
+    request=${request}${src_ip}${dst_ip}9234003500${udp_len}0000
+    request=${request}${dns_query_data}
+
+    if test $dns_reply != 0; then
+        local dns_reply=$1
+        ip_len=`expr 28 + ${#dns_reply} / 2`
+        udp_len=`expr $ip_len - 20`
+        ip_len=$(printf "%x" $ip_len)
+        udp_len=$(printf "%x" $udp_len)
+        local reply=${src_mac}${dst_mac}0800450000${ip_len}0000000080110000
+        reply=${reply}${dst_ip}${src_ip}0035923400${udp_len}0000${dns_reply}
+        echo $reply >> $inport.expected
+    else
+        for outport; do
+            echo $request >> $outport.expected
+        done
+    fi
+    as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
+}
+
+check ovn-nbctl ls-add ls1
+
+check ovn-nbctl lsp-add ls1 ls1-lp1 \
+-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.0.0.4 aef0::4"
+
+check ovn-nbctl lsp-set-port-security ls1-lp1 "f0:00:00:00:00:01 10.0.0.4 
aef0::4"
+
+DNS1=`ovn-nbctl create DNS records={}`
+check ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="10.0.0.4 aef0::4"
+
+check ovn-nbctl set Logical_switch ls1 dns_records="$DNS1"
+
+net_add n1
+sim_add hv1
+
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+    set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \
+    options:tx_pcap=hv1/vif1-tx.pcap \
+    options:rxq_pcap=hv1/vif1-rx.pcap \
+    ofport-request=1
+
+OVN_POPULATE_ARP
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+AT_CAPTURE_FILE([ofctl_monitor0.log])
+as hv1 ovs-ofctl -t 300 monitor br-int resume --detach --no-chdir \
+--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log
+
+src_ip=`ip_to_hex 10 0 0 4`
+dst_ip=`ip_to_hex 10 0 0 1`
+dns_reply=1
+
+# Send A record query
+set_dns_params vm1
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data 
$dns_resp_data
+OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Send AAAA record query
+set_dns_params vm1_ipv6_only
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data 
$dns_resp_data
+OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Send ANY record query
+set_dns_params vm1_ipv4_v6
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data 
$dns_resp_data
+OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Verify coverage counters
+OVS_WAIT_UNTIL([test 3 = $(as hv1 ovs-appctl -t ovn-controller 
coverage/read-counter dns_query_total)])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_query_type_a], [0], [1
+])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_query_type_aaaa], [0], [1
+])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_query_type_any], [0], [1
+])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+# DNS Statistics - Cache misses
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([dns statistics - cache hits and misses])
+ovn_start
+
+# Define helper functions
+set_dns_params() {
+    local hname=$1
+    local ttl=00000e10
+    an_count=0001
+    type=0001
+    case $hname in
+    vm1)
+        query_name=03766d31036f766e036f726700
+        expected_dns_answer=${query_name}00010001${ttl}00040a000004
+        ;;
+    vm3)
+        query_name=03766d33036f766e036f726700
+        expected_dns_answer=${query_name}00010001${ttl}000428000004
+        ;;
+    esac
+    local dns_req_header=010201200001000000000000
+    local dns_resp_header=010281200001${an_count}00000000
+    dns_req_data=${dns_req_header}${query_name}${type}0001
+    
dns_resp_data=${dns_resp_header}${query_name}${type}0001${expected_dns_answer}
+}
+
+test_dns() {
+    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 dns_reply=$6
+    local dns_query_data=$7
+    shift; shift; shift; shift; shift; shift; shift;
+    ip_len=`expr 28 + ${#dns_query_data} / 2`
+    udp_len=`expr $ip_len - 20`
+    ip_len=$(printf "%x" $ip_len)
+    udp_len=$(printf "%x" $udp_len)
+    local request=${dst_mac}${src_mac}0800450000${ip_len}0000000080110000
+    request=${request}${src_ip}${dst_ip}9234003500${udp_len}0000
+    request=${request}${dns_query_data}
+
+    if test $dns_reply != 0; then
+        local dns_reply=$1
+        ip_len=`expr 28 + ${#dns_reply} / 2`
+        udp_len=`expr $ip_len - 20`
+        ip_len=$(printf "%x" $ip_len)
+        udp_len=$(printf "%x" $udp_len)
+        local reply=${src_mac}${dst_mac}0800450000${ip_len}0000000080110000
+        reply=${reply}${dst_ip}${src_ip}0035923400${udp_len}0000${dns_reply}
+        echo $reply >> $inport.expected
+    else
+        for outport; do
+            echo $request >> $outport.expected
+        done
+    fi
+    as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
+}
+
+check ovn-nbctl ls-add ls1
+
+check ovn-nbctl lsp-add ls1 ls1-lp1 \
+-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.0.0.4"
+
+check ovn-nbctl lsp-set-port-security ls1-lp1 "f0:00:00:00:00:01 10.0.0.4"
+
+DNS1=`ovn-nbctl create DNS records={}`
+check ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="10.0.0.4"
+
+check ovn-nbctl set Logical_switch ls1 dns_records="$DNS1"
+
+net_add n1
+sim_add hv1
+
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+    set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \
+    options:tx_pcap=hv1/vif1-tx.pcap \
+    options:rxq_pcap=hv1/vif1-rx.pcap \
+    ofport-request=1
+
+OVN_POPULATE_ARP
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+AT_CAPTURE_FILE([ofctl_monitor0.log])
+as hv1 ovs-ofctl -t 300 monitor br-int resume --detach --no-chdir \
+--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log
+
+src_ip=`ip_to_hex 10 0 0 4`
+dst_ip=`ip_to_hex 10 0 0 1`
+dns_reply=1
+
+# Query for existing record (cache hit)
+set_dns_params vm1
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data 
$dns_resp_data
+OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Query for non-existing record (cache miss)
+set_dns_params vm3
+dns_reply=0
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
+OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Verify coverage counters
+OVS_WAIT_UNTIL([test 2 = $(as hv1 ovs-appctl -t ovn-controller 
coverage/read-counter dns_query_total)])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_cache_hit], [0], [1
+])
+AT_CHECK([as hv1 ovs-appctl -t ovn-controller coverage/read-counter 
dns_cache_miss], [0], [1
+])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+# DNS Statistics - Error counters
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([dns statistics - error counters])
+ovn_start
+
+# Define helper functions
+set_dns_params() {
+    local hname=$1
+    local ttl=00000e10
+    an_count=0001
+    type=0001
+    case $hname in
+    vm1_invalid_type)
+        query_name=03766d31036f766e036f726700
+        type=0002
+        ;;
+    esac
+    local dns_req_header=010201200001000000000000
+    local dns_resp_header=010281200001${an_count}00000000
+    dns_req_data=${dns_req_header}${query_name}${type}0001
+    
dns_resp_data=${dns_resp_header}${query_name}${type}0001${expected_dns_answer}
+}
+
+test_dns() {
+    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 dns_reply=$6
+    local dns_query_data=$7
+    shift; shift; shift; shift; shift; shift; shift;
+    ip_len=`expr 28 + ${#dns_query_data} / 2`
+    udp_len=`expr $ip_len - 20`
+    ip_len=$(printf "%x" $ip_len)
+    udp_len=$(printf "%x" $udp_len)
+    local request=${dst_mac}${src_mac}0800450000${ip_len}0000000080110000
+    request=${request}${src_ip}${dst_ip}9234003500${udp_len}0000
+    request=${request}${dns_query_data}
+
+    if test $dns_reply != 0; then
+        local dns_reply=$1
+        ip_len=`expr 28 + ${#dns_reply} / 2`
+        udp_len=`expr $ip_len - 20`
+        ip_len=$(printf "%x" $ip_len)
+        udp_len=$(printf "%x" $udp_len)
+        local reply=${src_mac}${dst_mac}0800450000${ip_len}0000000080110000
+        reply=${reply}${dst_ip}${src_ip}0035923400${udp_len}0000${dns_reply}
+        echo $reply >> $inport.expected
+    else
+        for outport; do
+            echo $request >> $outport.expected
+        done
+    fi
+    as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
+}
+
+check ovn-nbctl ls-add ls1
+
+check ovn-nbctl lsp-add ls1 ls1-lp1 \
+-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.0.0.4"
+
+check ovn-nbctl lsp-set-port-security ls1-lp1 "f0:00:00:00:00:01 10.0.0.4"
+
+DNS1=`ovn-nbctl create DNS records={}`
+check ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="10.0.0.4"
+
+check ovn-nbctl set Logical_switch ls1 dns_records="$DNS1"
+
+net_add n1
+sim_add hv1
+
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+    set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \
+    options:tx_pcap=hv1/vif1-tx.pcap \
+    options:rxq_pcap=hv1/vif1-rx.pcap \
+    ofport-request=1
+
+OVN_POPULATE_ARP
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+AT_CAPTURE_FILE([ofctl_monitor0.log])
+as hv1 ovs-ofctl -t 300 monitor br-int resume --detach --no-chdir \
+--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log
+
+src_ip=`ip_to_hex 10 0 0 4`
+dst_ip=`ip_to_hex 10 0 0 1`
+dns_reply=1
+
+# Test with invalid query type (should increment unsupported counter)
+set_dns_params vm1_invalid_type
+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip 0 $dns_req_data
+OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+# Verify coverage counter
+OVS_WAIT_UNTIL([test 1 = $(as hv1 ovs-appctl -t ovn-controller 
coverage/read-counter dns_query_total)])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 6216ac761..4fa203187 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -43,3 +43,4 @@ m4_include([tests/ovn-vif-plug.at])
 m4_include([tests/ovn-util.at])
 m4_include([tests/ovn-br-controller.at])
 m4_include([tests/ovn-inc-proc-graph-dump.at])
+m4_include([tests/ovn-dns-stats.at])
-- 
2.52.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to