From 0ce73d80dc0c3996eca0b73c76bf513a33c1dab4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 28 May 2025 23:48:18 +0200 Subject: [PATCH] dns: add cache/queue for outgoing queries Batch outgoing questions and drop redundant ones. Signed-off-by: Felix Fietkau --- cache.c | 27 ++++++++---------------- dns.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- dns.h | 3 ++- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/cache.c b/cache.c index 51eb707..0ccac49 100644 --- a/cache.c +++ b/cache.c @@ -143,26 +143,17 @@ void cache_update(void) { struct cache_service *s; - int count = 2; - dns_packet_init(); - dns_packet_question(C_DNS_SD, TYPE_ANY); - dns_packet_question(C_DNS_SD, TYPE_PTR); + dns_query(C_DNS_SD, TYPE_ANY); + dns_query(C_DNS_SD, TYPE_PTR); avl_for_each_element(&services, s, avl) { if (s->host) { - dns_packet_question(s->host, TYPE_A); - dns_packet_question(s->host, TYPE_AAAA); + dns_query(s->host, TYPE_A); + dns_query(s->host, TYPE_AAAA); } else { - dns_packet_question(s->entry, TYPE_PTR); + dns_query(s->entry, TYPE_PTR); } - if (++count < 16) - continue; - dns_packet_broadcast(); - count = 0; } - - if (count) - dns_packet_broadcast(); } static struct cache_service* @@ -203,14 +194,12 @@ cache_service(struct interface *iface, char *entry, int hlen, int ttl) s->avl.key = type; avl_insert(&services, &s->avl); - dns_packet_init(); if (hlen) { - dns_packet_question(s->host, TYPE_A); - dns_packet_question(s->host, TYPE_AAAA); + dns_query(s->host, TYPE_A); + dns_query(s->host, TYPE_AAAA); } else { - dns_packet_question(entry, TYPE_PTR); + dns_query(entry, TYPE_PTR); } - dns_packet_broadcast(); return s; } diff --git a/dns.c b/dns.c index 715125b..7c24ddc 100644 --- a/dns.c +++ b/dns.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "announce.h" #include "util.h" @@ -39,6 +40,15 @@ #include "service.h" #include "interface.h" +#define QUERY_BATCH_SIZE 16 + +struct query_entry { + struct avl_node node; + uint16_t type; + char name[]; +}; + +static AVL_TREE(queries, avl_strcmp, true, NULL); static char name_buffer[MAX_NAME_LEN + 1]; static struct { @@ -185,7 +195,7 @@ void dns_packet_send(struct interface *iface, struct sockaddr *to, bool query, i perror("failed to send answer"); } -void dns_packet_broadcast(void) +static void dns_packet_broadcast(void) { struct interface *iface; @@ -202,6 +212,58 @@ dns_send_question(struct interface *iface, struct sockaddr *to, dns_packet_send(iface, to, true, multicast); } +static void +dns_query_pending(struct uloop_timeout *t) +{ + struct query_entry *e, *tmp; + int count = 0; + + dns_packet_init(); + avl_remove_all_elements(&queries, e, node, tmp) { + dns_packet_question(e->name, e->type); + free(e); + + if (++count < QUERY_BATCH_SIZE) + continue; + + count = 0; + dns_packet_broadcast(); + } + + if (count) + dns_packet_broadcast(); +} + +void dns_query(const char *name, uint16_t type) +{ + static struct uloop_timeout timer = { + .cb = dns_query_pending + }; + struct query_entry *e; + + e = avl_find_element(&queries, name, e, node); + while (e) { + if (e->type == type) + return; + + e = avl_next_element(e, node); + if (strcmp(e->name, name) != 0) + break; + } + + e = calloc(1, sizeof(*e) + strlen(name) + 1); + e->type = type; + e->node.key = e->name; + strcpy(e->name, name); + avl_insert(&queries, &e->node); + + if (queries.count > QUERY_BATCH_SIZE) + timer.cb(&timer); + + if (!timer.pending) + uloop_timeout_set(&timer, 100); +} + void dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname) { diff --git a/dns.h b/dns.h index 65efcf7..fde049f 100644 --- a/dns.h +++ b/dns.h @@ -77,7 +77,8 @@ void dns_packet_init(void); bool dns_packet_question(const char *name, int type); void dns_packet_answer(const char *name, int type, const uint8_t *rdata, uint16_t rdlength, int ttl); void dns_packet_send(struct interface *iface, struct sockaddr *to, bool query, int multicast); -void dns_packet_broadcast(void); + +void dns_query(const char *name, uint16_t type); void dns_send_question(struct interface *iface, struct sockaddr *to, const char *question, int type, int multicast); -- 2.30.2