Add comprehensive DNS query statistics tracking to ovn-controller for observability into DNS query processing.
The statistics track query types (A, AAAA, PTR, ANY, Other), cache performance (hits and misses), processing errors, and responses sent. A new unixctl command 'dns/show-stats' displays the statistics. Signed-off-by: Ketan Supanekar <[email protected]> --- controller/ovn-controller.c | 15 ++++++++ controller/pinctrl.c | 74 +++++++++++++++++++++++++++++++++++++ controller/pinctrl.h | 31 ++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 2d9b3e033..f5ff85ffa 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -121,6 +121,7 @@ static unixctl_cb_func debug_dump_peer_ports; static unixctl_cb_func debug_dump_lflow_conj_ids; static unixctl_cb_func lflow_cache_flush_cmd; static unixctl_cb_func lflow_cache_show_stats_cmd; +static unixctl_cb_func dns_show_stats_cmd; static unixctl_cb_func debug_delay_nb_cfg_report; #define DEFAULT_BRIDGE_NAME "br-int" @@ -7377,6 +7378,9 @@ main(int argc, char *argv[]) lflow_cache_show_stats_cmd, &lflow_output_data->pd); + unixctl_command_register("dns/show-stats", "", 0, 0, + dns_show_stats_cmd, NULL); + bool reset_ovnsb_idl_min_index = false; unixctl_command_register("sb-cluster-state-reset", "", 0, 0, cluster_state_reset_cmd, @@ -8401,6 +8405,17 @@ lflow_cache_show_stats_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, ds_destroy(&ds); } +static void +dns_show_stats_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *arg OVS_UNUSED) +{ + struct ds ds = DS_EMPTY_INITIALIZER; + + pinctrl_get_dns_stats(&ds); + unixctl_command_reply(conn, ds_cstr(&ds)); + ds_destroy(&ds); +} + static void cluster_state_reset_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *idl_reset_) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 6f7ae4037..a64d1b8d8 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -184,6 +184,9 @@ struct pinctrl { static struct pinctrl pinctrl; +/* DNS query statistics */ +static struct dns_stats dns_statistics = {0}; + static bool pinctrl_is_sb_commited(int64_t commit_cfg, int64_t cur_cfg); static void init_buffered_packets_ctx(void); static void destroy_buffered_packets_ctx(void); @@ -3366,6 +3369,9 @@ pinctrl_handle_dns_lookup( uint32_t success = 0; bool send_refuse = false; + /* Track total DNS queries received */ + dns_statistics.total_queries++; + /* Parse result field. */ const struct mf_field *f; enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); @@ -3392,6 +3398,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"); + dns_statistics.error_truncated++; goto exit; } @@ -3399,17 +3406,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"); + dns_statistics.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 */ + dns_statistics.skipped_not_request++; goto exit; } /* Check if at least one query request is present */ if (!in_dns_header->qdcount) { + dns_statistics.error_no_query++; goto exit; } @@ -3431,6 +3441,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); + dns_statistics.error_parse_failure++; goto exit; } ds_put_buffer(&query_name, (const char *) in_dns_data + idx, label_len); @@ -3449,6 +3460,20 @@ pinctrl_handle_dns_lookup( } uint16_t query_type = ntohs(get_unaligned_be16((void *) in_dns_data)); + + /* Track query type statistics */ + if (query_type == DNS_QUERY_TYPE_A) { + dns_statistics.query_type_a++; + } else if (query_type == DNS_QUERY_TYPE_AAAA) { + dns_statistics.query_type_aaaa++; + } else if (query_type == DNS_QUERY_TYPE_PTR) { + dns_statistics.query_type_ptr++; + } else if (query_type == DNS_QUERY_TYPE_ANY) { + dns_statistics.query_type_any++; + } else { + dns_statistics.query_type_other++; + } + /* 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 +3492,10 @@ pinctrl_handle_dns_lookup( &ovn_owned); ds_destroy(&query_name); if (!answer_data) { + dns_statistics.cache_misses++; goto exit; } + dns_statistics.cache_hits++; uint16_t ancount = 0; @@ -3511,6 +3538,7 @@ pinctrl_handle_dns_lookup( if (ovn_owned && (query_type == DNS_QUERY_TYPE_AAAA || query_type == DNS_QUERY_TYPE_A) && !ancount) { send_refuse = true; + dns_statistics.unsupported_ovn_owned++; } destroy_lport_addresses(&ip_addrs); @@ -3595,6 +3623,7 @@ pinctrl_handle_dns_lookup( pin->packet_len = dp_packet_size(&pkt_out); success = 1; + dns_statistics.responses_sent++; exit: if (!ofperr) { union mf_subvalue sv; @@ -8863,3 +8892,48 @@ set_from_ctrl_flag_in_pkt_metadata(struct ofputil_packet_in *pin) sv.u8_val = 1; mf_write_subfield(&dst, &sv, &pin->flow_metadata); } + +/* DNS Statistics functions */ +void +pinctrl_get_dns_stats(struct ds *output) +{ + ds_put_format(output, "DNS Query Statistics\n"); + ds_put_format(output, "====================\n\n"); + + ds_put_format(output, "Total queries received: %"PRIu64"\n\n", + dns_statistics.total_queries); + + ds_put_format(output, "Query Types:\n"); + ds_put_format(output, " A (IPv4): %"PRIu64"\n", + dns_statistics.query_type_a); + ds_put_format(output, " AAAA (IPv6): %"PRIu64"\n", + dns_statistics.query_type_aaaa); + ds_put_format(output, " PTR: %"PRIu64"\n", + dns_statistics.query_type_ptr); + ds_put_format(output, " ANY: %"PRIu64"\n", + dns_statistics.query_type_any); + ds_put_format(output, " Other: %"PRIu64"\n\n", + dns_statistics.query_type_other); + + ds_put_format(output, "Cache Performance:\n"); + ds_put_format(output, " Cache hits: %"PRIu64"\n", + dns_statistics.cache_hits); + ds_put_format(output, " Cache misses: %"PRIu64"\n\n", + dns_statistics.cache_misses); + + ds_put_format(output, "Processing Errors (packets reinjected to pipeline):\n"); + ds_put_format(output, " Truncated packets: %"PRIu64"\n", + dns_statistics.error_truncated); + ds_put_format(output, " Skipped (not request): %"PRIu64"\n", + dns_statistics.skipped_not_request); + ds_put_format(output, " No query section: %"PRIu64"\n", + dns_statistics.error_no_query); + ds_put_format(output, " Parse failures: %"PRIu64"\n", + dns_statistics.error_parse_failure); + ds_put_format(output, " Unsupported OVN-owned: %"PRIu64"\n\n", + dns_statistics.unsupported_ovn_owned); + + ds_put_format(output, "Responses:\n"); + ds_put_format(output, " Responses sent: %"PRIu64"\n", + dns_statistics.responses_sent); +} diff --git a/controller/pinctrl.h b/controller/pinctrl.h index 80384ac9b..7df676669 100644 --- a/controller/pinctrl.h +++ b/controller/pinctrl.h @@ -83,4 +83,35 @@ void send_self_originated_neigh_packet(struct rconn *swconn, struct in6_addr *local, struct in6_addr *target, uint8_t table_id); + +/* DNS Statistics */ +struct dns_stats { + /* Total queries received */ + uint64_t total_queries; + + /* Queries by type */ + uint64_t query_type_a; /* IPv4 address lookups */ + uint64_t query_type_aaaa; /* IPv6 address lookups */ + uint64_t query_type_ptr; /* Reverse DNS lookups */ + uint64_t query_type_any; /* ANY type queries */ + uint64_t query_type_other; /* Other/unsupported types */ + + /* Cache performance */ + uint64_t cache_hits; /* Queries with answers found */ + uint64_t cache_misses; /* Queries without answers */ + + /* Processing errors (all packets reinjected to pipeline) */ + uint64_t error_truncated; /* Malformed/truncated packets */ + uint64_t skipped_not_request; /* DNS responses (not queries) */ + uint64_t error_no_query; /* No query section present */ + uint64_t error_parse_failure; /* Query name parsing failure */ + uint64_t unsupported_ovn_owned; /* Unsupported query on OVN-owned record */ + + /* Responses sent */ + uint64_t responses_sent; /* Successfully generated responses */ +}; + +struct ds; +void pinctrl_get_dns_stats(struct ds *output); + #endif /* controller/pinctrl.h */ -- 2.52.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
