Add DNS query statistics tracking using OVS coverage counters in ovn-controller for observability into DNS query processing.
Tracked metrics include: - Total queries processed - Query types (A, AAAA, PTR, ANY, Other) - Cache performance (hits/misses) - Responses sent - Error conditions (truncated, parse failures, etc.) Statistics can be queried using: ovn-appctl -t ovn-controller coverage/read-counter <counter_name> ovn-appctl -t ovn-controller coverage/show The implementation uses coverage counter verification into existing DNS tests in tests/ovn.at. Signed-off-by: Ketan Supanekar <[email protected]> --- NEWS | 5 +++++ controller/pinctrl.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ tests/ovn.at | 28 ++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/NEWS b/NEWS index 9883fb81d..dc9d28f2c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ Post v25.09.0 ------------- + - Added DNS query statistics tracking in ovn-controller using OVS coverage + counters. Statistics can be queried using "ovn-appctl -t ovn-controller + coverage/read-counter <counter_name>" or "coverage/show". Tracked metrics + include total queries, query types (A, AAAA, PTR, ANY, Other), cache + performance (hits/misses), responses sent, and error conditions. - Added support for TLS Server Name Indication (SNI) with the new --ssl-server-name option in OVN utilities and daemons. This allows specifying the server name for SNI, which is useful when connecting diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 6f7ae4037..ab8a0a37c 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -391,6 +391,22 @@ COVERAGE_DEFINE(pinctrl_drop_put_vport_binding); COVERAGE_DEFINE(pinctrl_notify_main_thread); COVERAGE_DEFINE(pinctrl_total_pin_pkts); +/* DNS query statistics - thread-safe coverage counters */ +COVERAGE_DEFINE(dns_query_total); +COVERAGE_DEFINE(dns_query_type_a); +COVERAGE_DEFINE(dns_query_type_aaaa); +COVERAGE_DEFINE(dns_query_type_ptr); +COVERAGE_DEFINE(dns_query_type_any); +COVERAGE_DEFINE(dns_query_type_other); +COVERAGE_DEFINE(dns_cache_hit); +COVERAGE_DEFINE(dns_cache_miss); +COVERAGE_DEFINE(dns_error_truncated); +COVERAGE_DEFINE(dns_skipped_not_request); +COVERAGE_DEFINE(dns_error_no_query); +COVERAGE_DEFINE(dns_error_parse_failure); +COVERAGE_DEFINE(dns_unsupported_ovn_owned); +COVERAGE_DEFINE(dns_response_sent); + struct empty_lb_backends_event { struct hmap_node hmap_node; long long int timestamp; @@ -3366,6 +3382,9 @@ pinctrl_handle_dns_lookup( uint32_t success = 0; bool send_refuse = false; + /* Track total DNS queries received */ + COVERAGE_INC(dns_query_total); + /* Parse result field. */ const struct mf_field *f; enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); @@ -3392,6 +3411,7 @@ pinctrl_handle_dns_lookup( /* Check that the packet stores at least the minimal headers. */ if (dp_packet_l4_size(pkt_in) < (UDP_HEADER_LEN + DNS_HEADER_LEN)) { VLOG_WARN_RL(&rl, "truncated dns packet"); + COVERAGE_INC(dns_error_truncated); goto exit; } @@ -3399,17 +3419,20 @@ pinctrl_handle_dns_lookup( struct dns_header const *in_dns_header = dp_packet_get_udp_payload(pkt_in); if (!in_dns_header) { VLOG_WARN_RL(&rl, "truncated dns packet"); + COVERAGE_INC(dns_error_truncated); goto exit; } /* Check if it is DNS request or not */ if (in_dns_header->lo_flag & 0x80) { /* It's a DNS response packet which we are not interested in */ + COVERAGE_INC(dns_skipped_not_request); goto exit; } /* Check if at least one query request is present */ if (!in_dns_header->qdcount) { + COVERAGE_INC(dns_error_no_query); goto exit; } @@ -3431,6 +3454,7 @@ pinctrl_handle_dns_lookup( uint8_t label_len = in_dns_data[idx++]; if (in_dns_data + idx + label_len > end) { ds_destroy(&query_name); + COVERAGE_INC(dns_error_parse_failure); goto exit; } ds_put_buffer(&query_name, (const char *) in_dns_data + idx, label_len); @@ -3449,6 +3473,26 @@ pinctrl_handle_dns_lookup( } uint16_t query_type = ntohs(get_unaligned_be16((void *) in_dns_data)); + + /* Track query type statistics */ + switch (query_type) { + case DNS_QUERY_TYPE_A: + COVERAGE_INC(dns_query_type_a); + break; + case DNS_QUERY_TYPE_AAAA: + COVERAGE_INC(dns_query_type_aaaa); + break; + case DNS_QUERY_TYPE_PTR: + COVERAGE_INC(dns_query_type_ptr); + break; + case DNS_QUERY_TYPE_ANY: + COVERAGE_INC(dns_query_type_any); + break; + default: + COVERAGE_INC(dns_query_type_other); + break; + } + /* Supported query types - A, AAAA, ANY and PTR */ if (!(query_type == DNS_QUERY_TYPE_A || query_type == DNS_QUERY_TYPE_AAAA || query_type == DNS_QUERY_TYPE_ANY @@ -3467,8 +3511,10 @@ pinctrl_handle_dns_lookup( &ovn_owned); ds_destroy(&query_name); if (!answer_data) { + COVERAGE_INC(dns_cache_miss); goto exit; } + COVERAGE_INC(dns_cache_hit); uint16_t ancount = 0; @@ -3511,6 +3557,7 @@ pinctrl_handle_dns_lookup( if (ovn_owned && (query_type == DNS_QUERY_TYPE_AAAA || query_type == DNS_QUERY_TYPE_A) && !ancount) { send_refuse = true; + COVERAGE_INC(dns_unsupported_ovn_owned); } destroy_lport_addresses(&ip_addrs); @@ -3595,6 +3642,7 @@ pinctrl_handle_dns_lookup( pin->packet_len = dp_packet_size(&pkt_out); success = 1; + COVERAGE_INC(dns_response_sent); exit: if (!ofperr) { union mf_subvalue sv; diff --git a/tests/ovn.at b/tests/ovn.at index 445a74ce5..d657bd2e1 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -12136,6 +12136,34 @@ reset_pcap_file hv1-vif1 hv1/vif1 reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected + +AS_BOX([Verify DNS coverage counters]) +# The test has sent multiple DNS queries of various types, verify counters +# Total queries should be > 0 +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_query_total | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) +# A record queries (multiple A queries sent) +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_query_type_a | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) +# AAAA record queries (IPv6 queries sent) +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_query_type_aaaa | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) +# PTR record queries (reverse DNS lookups sent) +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_query_type_ptr | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) +# ANY record queries (vm1_ipv4_v6 queries sent) +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_query_type_any | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) +# Cache hits (repeated queries) +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_cache_hit | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) +# Cache misses (queries for non-existent records) +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_cache_miss | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) +# Responses sent +AT_CHECK([as hv1 ovn-appctl -t ovn-controller coverage/read-counter dns_response_sent | awk '{if ($1 > 0) print "ok"}'], [0], [ok +]) + OVN_CLEANUP([hv1]) AT_CLEANUP -- 2.52.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
