From: Oto Šťáva Date: Wed, 1 Mar 2023 10:24:10 +0000 (+0100) Subject: daemon: optimize memory consumption for outgoing UDP X-Git-Tag: v6.0.2~42^2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55a7fc96ba2cd91526c4352af8e2a8046943dd29;p=thirdparty%2Fknot-resolver.git daemon: optimize memory consumption for outgoing UDP --- diff --git a/daemon/io.c b/daemon/io.c index 27606c75d..485f5b29e 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -50,8 +50,10 @@ static void check_bufsize(uv_handle_t* handle) static void handle_getbuf(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { struct session2 *s = handle->data; - buf->base = wire_buf_free_space(&s->layers->wire_buf); - buf->len = wire_buf_free_space_length(&s->layers->wire_buf); + struct wire_buf *wb = &s->layers->wire_buf; + + buf->base = wire_buf_free_space(wb); + buf->len = wire_buf_free_space_length(wb); } static void udp_on_unwrapped(int status, struct session2 *session, diff --git a/daemon/session2.c b/daemon/session2.c index 85bbd22bd..2bba4a220 100644 --- a/daemon/session2.c +++ b/daemon/session2.c @@ -576,6 +576,7 @@ static struct protolayer_manager *protolayer_manager_new( return NULL; size_t wire_buf_length = 0; + size_t wire_buf_max_length = 0; ssize_t offsets[2 * num_layers]; manager_size += sizeof(offsets); @@ -594,7 +595,11 @@ static struct protolayer_manager *protolayer_manager_new( iter_offsets[i] = g->iter_size ? total_iter_data_size : -1; total_iter_data_size += ALIGN_TO(g->iter_size, CPU_STRUCT_ALIGN); - wire_buf_length += g->wire_buf_overhead; + size_t wire_buf_overhead = (g->wire_buf_overhead_cb) + ? g->wire_buf_overhead_cb(s->outgoing) + : g->wire_buf_overhead; + wire_buf_length += wire_buf_overhead; + wire_buf_max_length += MAX(g->wire_buf_max_overhead, wire_buf_overhead); } manager_size += total_sess_data_size; cb_ctx_size += total_iter_data_size; @@ -608,6 +613,7 @@ static struct protolayer_manager *protolayer_manager_new( m->cb_ctx_size = cb_ctx_size; memcpy(m->data, offsets, sizeof(offsets)); + m->wire_buf_max_length = wire_buf_max_length; int ret = wire_buf_init(&m->wire_buf, wire_buf_length); kr_require(!ret); diff --git a/daemon/session2.h b/daemon/session2.h index a82470127..04e090675 100644 --- a/daemon/session2.h +++ b/daemon/session2.h @@ -172,13 +172,15 @@ static inline size_t wire_buf_data_length(const struct wire_buf *wb) /** Gets a pointer to the free space after the valid data of the wire buffer. */ static inline void *wire_buf_free_space(const struct wire_buf *wb) { - return &wb->buf[wb->end]; + return (wb->buf) ? &wb->buf[wb->end] : NULL; } /** Gets the length of the free space after the valid data of the wire buffer. */ static inline size_t wire_buf_free_space_length(const struct wire_buf *wb) { - return wb->size - wb->end; + if (kr_fails_assert(wb->end <= wb->size)) + return 0; + return (wb->buf) ? wb->size - wb->end : 0; } @@ -565,6 +567,9 @@ typedef int (*protolayer_data_sess_init_cb)(struct protolayer_manager *manager, void *data, void *param); +/** Function type for determining the size of a layer's wire buffer overhead. */ +typedef size_t (*protolayer_wire_buf_overhead_cb)(bool outgoing); + /** Function type for (de)initialization callback of layer iteration data. * * `ctx` points to the iteration context that `data` belongs to. @@ -601,6 +606,7 @@ typedef void (*protolayer_request_cb)(struct protolayer_manager *manager, struct protolayer_manager { enum protolayer_grp grp; struct wire_buf wire_buf; + size_t wire_buf_max_length; struct session2 *session; size_t num_layers; size_t cb_ctx_size; /**< Size of a single callback context, including @@ -661,11 +667,28 @@ struct protolayer_globals { * no iteration struct is used by the layer, the value may be zero. */ size_t iter_size; - /** Number of bytes that this layer adds onto the session's wire - * buffer. All overheads in a group are summed together to form the - * resulting wire buffer length. */ + /** Number of bytes that this layer adds onto the session's wire buffer + * by default. All overheads in a group are summed together to form the + * resulting default wire buffer length. + * + * Ignored when `wire_buf_overhead_cb` is non-NULL. */ size_t wire_buf_overhead; + /** Called during session initialization to determine the number of + * bytes that this layer adds onto the session's wire buffer. + * + * It is the dynamic version of `wire_buf_overhead`, which is ignored + * when this is non-NULL. */ + protolayer_wire_buf_overhead_cb wire_buf_overhead_cb; + + /** Number of bytes that this layer adds onto the session's wire buffer + * at most. All overheads in a group are summed together to form the + * resulting default wire buffer length. + * + * If this is less than the default overhead, the default is used + * instead. */ + size_t wire_buf_max_overhead; + /** Called during session creation to initialize * layer-specific session data. The data is always provided * zero-initialized to this function. */ diff --git a/daemon/worker.c b/daemon/worker.c index 9b5ad5484..e529e5b91 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1737,6 +1737,18 @@ static enum protolayer_event_cb_result pl_dns_dgram_event_unwrap( return PROTOLAYER_EVENT_PROPAGATE; } +static size_t pl_dns_dgram_wire_buf_overhead(bool outgoing) +{ + if (outgoing) { + if (the_resolver->upstream_opt_rr) + return knot_edns_get_payload(the_resolver->upstream_opt_rr); + } else { + if (the_resolver->downstream_opt_rr) + return knot_edns_get_payload(the_resolver->downstream_opt_rr); + } + return KNOT_WIRE_MAX_PKTSIZE; +} + static enum protolayer_iter_cb_result pl_dns_dgram_unwrap( void *sess_data, void *iter_data, struct protolayer_iter_ctx *ctx) { @@ -2264,7 +2276,8 @@ int worker_init(void) /* DNS protocol layers */ protolayer_globals[PROTOLAYER_PROTOCOL_DNS_DGRAM] = (struct protolayer_globals){ - .wire_buf_overhead = KNOT_WIRE_MAX_PKTSIZE, + .wire_buf_overhead_cb = pl_dns_dgram_wire_buf_overhead, + .wire_buf_max_overhead = KNOT_WIRE_MAX_PKTSIZE, .unwrap = pl_dns_dgram_unwrap, .event_unwrap = pl_dns_dgram_event_unwrap };