]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon: optimize memory consumption for outgoing UDP
authorOto Šťáva <oto.stava@nic.cz>
Wed, 1 Mar 2023 10:24:10 +0000 (11:24 +0100)
committerOto Šťáva <oto.stava@nic.cz>
Fri, 17 Mar 2023 07:18:43 +0000 (08:18 +0100)
daemon/io.c
daemon/session2.c
daemon/session2.h
daemon/worker.c

index 27606c75df3843d2ab23adaeabafc466781246d0..485f5b29e4f8c7ca95ea7997d1f6e6cd1ed4849d 100644 (file)
@@ -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,
index 85bbd22bd414ae6ee9086a3e8f98fea053f82d10..2bba4a220a31a96eb938529ca8520f5a3da41188 100644 (file)
@@ -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);
 
index a82470127079dfa4203b24970ac9d244430194ff..04e090675dd9aa6344f7240d00515fae8898e7ef 100644 (file)
@@ -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. */
index 9b5ad5484e6ad38ceeb06a2658f4cae1aba3f49d..e529e5b917f978559a7be9e3e47f99d9ae3f3078 100644 (file)
@@ -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
        };