]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
xdp-quic/refactoring: separate XDP from QUIC routines
authorLibor Peltan <libor.peltan@nic.cz>
Wed, 19 Oct 2022 16:02:03 +0000 (18:02 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Thu, 2 Mar 2023 20:01:33 +0000 (21:01 +0100)
src/knot/server/xdp-handler.c
src/libknot/Makefile.inc
src/libknot/xdp/quic.c
src/libknot/xdp/quic.h
src/libknot/xdp/quic_conn.h
src/utils/kxdpgun/main.c

index dcd88b0493365ad0b1f6fd8fbfaf105a5ae8f20a..4e4682feffaa3bde0d38dad42e1bf6f09315ba68 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -51,7 +51,7 @@ typedef struct xdp_handle_ctx {
 
 #ifdef ENABLE_QUIC
        knot_xquic_conn_t *quic_relays[XDP_BATCHLEN];
-       int quic_rets[XDP_BATCHLEN];
+       knot_quic_reply_t quic_replies[XDP_BATCHLEN];
        knot_xquic_table_t *quic_table;
        knot_sweep_stats_t quic_closed;
 #endif // ENABLE_QUIC
@@ -150,6 +150,22 @@ static void quic_log_cb(const char *line)
 {
        log_debug("QUIC: %s", line);
 }
+
+static int quic_alloc_cb(knot_quic_reply_t *rpl)
+{
+       return knot_xdp_reply_alloc(rpl->sock, rpl->in_ctx, rpl->out_ctx);
+}
+
+static int quic_send_cb(knot_quic_reply_t *rpl)
+{
+       uint32_t sent = 0;
+       return knot_xdp_send(rpl->sock, rpl->out_ctx, 1, &sent);
+}
+
+static void quic_free_cb(knot_quic_reply_t *rpl)
+{
+       knot_xdp_send_free(rpl->sock, rpl->out_ctx, 1);
+}
 #endif // ENABLE_QUIC
 
 xdp_handle_ctx_t *xdp_handle_init(struct server *server, knot_xdp_socket_t *xdp_sock)
@@ -189,6 +205,13 @@ xdp_handle_ctx_t *xdp_handle_init(struct server *server, knot_xdp_socket_t *xdp_
                if (conf_get_bool(pconf, C_XDP, C_QUIC_LOG)) {
                        ctx->quic_table->log_cb = quic_log_cb;
                }
+               for (int i = 0; i < XDP_BATCHLEN; i++) {
+                       knot_quic_reply_t *reply = &ctx->quic_replies[i];
+                       reply->sock = xdp_sock;
+                       reply->alloc_reply = quic_alloc_cb;
+                       reply->send_reply = quic_send_cb;
+                       reply->free_reply = quic_free_cb;
+               }
 #else
                assert(0); // verified in configuration checks
 #endif // ENABLE_QUIC
@@ -368,9 +391,19 @@ static void handle_quic(xdp_handle_ctx_t *ctx, knot_layer_t *layer,
                        continue;
                }
 
-               ctx->quic_rets[i] = knot_xquic_handle(ctx->quic_table, msg_recv,
-                                                     ctx->quic_idle_close,
-                                                     &ctx->quic_relays[i]);
+               knot_quic_reply_t *reply = &ctx->quic_replies[i];
+               knot_xdp_msg_t *msg_out = &ctx->msg_send_udp[i];
+
+               reply->ip_rem = (struct sockaddr_storage *)&msg_recv->ip_from;
+               reply->ip_loc = (struct sockaddr_storage *)&msg_recv->ip_to;
+               reply->in_payload = &msg_recv->payload;
+               reply->out_payload = &msg_out->payload;
+               reply->in_ctx = msg_recv;
+               reply->out_ctx = msg_out;
+
+               (void)knot_quic_handle(ctx->quic_table, reply, ctx->quic_idle_close,
+                                      &ctx->quic_relays[i]);
+
                knot_xquic_conn_t *rl = ctx->quic_relays[i];
 
                int64_t stream_id;
@@ -434,9 +467,8 @@ void xdp_handle_send(xdp_handle_ctx_t *ctx)
                        continue;
                }
 
-               ret = knot_xquic_send(ctx->quic_table, ctx->quic_relays[i], ctx->sock,
-                                     &ctx->msg_recv[i], ctx->quic_rets[i],
-                                     QUIC_MAX_SEND_PER_RECV, false);
+               ret = knot_quic_send(ctx->quic_table, ctx->quic_relays[i],
+                                    &ctx->quic_replies[i], QUIC_MAX_SEND_PER_RECV, false);
                if (ret != KNOT_EOK) {
                        log_notice("QUIC, failed to send some packets");
                }
index 32ea26bce8f44b85431220fd804fd5457f0bb5da..cd500d30e818ac6f1fe0617d4e9e22468199d87b 100755 (executable)
@@ -114,20 +114,20 @@ libknot_la_SOURCES  += \
        libknot/xdp/tcp.c                       \
        libknot/xdp/xdp.c
 
+endif ENABLE_XDP
 if ENABLE_QUIC
 
 libknot_la_CPPFLAGS += $(libngtcp2_CFLAGS) $(gnutls_CFLAGS)
 libknot_la_LIBADD   += $(libngtcp2_LIBS) $(gnutls_LIBS)
 
 nobase_include_libknot_HEADERS += \
-        libknot/xdp/quic.h                      \
-        libknot/xdp/quic_conn.h
+       libknot/xdp/quic.h                      \
+       libknot/xdp/quic_conn.h
 
 libknot_la_SOURCES  += \
        libknot/xdp/quic.c                      \
-        libknot/xdp/quic_conn.c
+       libknot/xdp/quic_conn.c
 
 endif ENABLE_QUIC
-endif ENABLE_XDP
 
 DIST_SUBDIRS = libknot/xdp
index 1a0df337d348471046d1712c3a39da90d8591235..d508724fa6e0a9f275294bef97ba74c05965ff8c 100644 (file)
@@ -106,7 +106,8 @@ int knot_xquic_session_load(knot_xquic_conn_t *conn, struct knot_quic_session *s
                goto session_free;
        }
 
-       ret = gnutls_session_set_data(conn->tls_session, session->tls_session.data, session->tls_session.size);
+       ret = gnutls_session_set_data(conn->tls_session, session->tls_session.data,
+                                     session->tls_session.size);
        if (ret != KNOT_EOK) {
                goto session_free;
        }
@@ -158,7 +159,8 @@ static int self_signed_cert(gnutls_certificate_credentials_t tls_cert)
 
 #define now_years(years) (time(NULL) + 365 * 24 * 3600 * (years))
 
-       CHK(gnutls_x509_privkey_generate(privkey, GNUTLS_PK_ECDSA, GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1), 0));
+       CHK(gnutls_x509_privkey_generate(privkey, GNUTLS_PK_ECDSA,
+                                        GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1), 0));
 
        CHK(gnutls_x509_crt_init(&cert));
        //CHK(gnutls_x509_crt_set_ca_status(cert, 0)); // TODO needed ?
@@ -168,7 +170,8 @@ static int self_signed_cert(gnutls_certificate_credentials_t tls_cert)
        CHK(gnutls_x509_crt_set_key(cert, privkey));
 
        CHK(gnutls_x509_crt_set_serial(cert, serial, sizeof(serial)));
-       CHK(gnutls_x509_crt_set_subject_alt_name(cert, GNUTLS_SAN_DNSNAME, hostname, strlen(hostname), GNUTLS_FSAN_SET));
+       CHK(gnutls_x509_crt_set_subject_alt_name(cert, GNUTLS_SAN_DNSNAME, hostname,
+                                                strlen(hostname), GNUTLS_FSAN_SET));
        CHK(gnutls_x509_crt_set_version(cert, 3));
        CHK(gnutls_x509_crt_sign2(cert, cert, privkey, GNUTLS_DIG_SHA256, 0));
 
@@ -214,7 +217,8 @@ struct knot_quic_creds *knot_xquic_init_creds(bool server, const char *tls_cert,
                goto fail2;
        }
        if (tls_cert != NULL) {
-               ret = gnutls_certificate_set_x509_key_file(creds->tls_cert, tls_cert, tls_key, GNUTLS_X509_FMT_PEM);
+               ret = gnutls_certificate_set_x509_key_file(creds->tls_cert, tls_cert,
+                                                          tls_key, GNUTLS_X509_FMT_PEM);
        } else if (server) {
                ret = self_signed_cert(creds->tls_cert);
        }
@@ -523,7 +527,8 @@ static int recv_stream_data(ngtcp2_conn *conn, uint32_t flags,
        knot_xquic_conn_t *ctx = (knot_xquic_conn_t *)user_data;
        assert(ctx->conn == conn);
 
-       int ret = knot_xquic_stream_recv_data(ctx, stream_id, data, datalen, (flags & NGTCP2_STREAM_DATA_FLAG_FIN));
+       int ret = knot_xquic_stream_recv_data(ctx, stream_id, data, datalen,
+                                             (flags & NGTCP2_STREAM_DATA_FLAG_FIN));
 
        return ret == KNOT_EOK ? 0 : NGTCP2_ERR_CALLBACK_FAILURE;
 }
@@ -556,7 +561,8 @@ static int stream_closed(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
        return 0;
 }
 
-static int recv_stateless_rst(ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset *sr, void *user_data)
+static int recv_stateless_rst(ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset *sr,
+                              void *user_data)
 {
        // NOTE server can't receive stateless resets, only client
 
@@ -682,9 +688,11 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_path *path, const ngtcp2_c
        }
 
        if (server) {
-               return ngtcp2_conn_server_new(pconn, dcid, scid, path, version, &callbacks, &settings, &params, NULL, user_data);
+               return ngtcp2_conn_server_new(pconn, dcid, scid, path, version, &callbacks,
+                                             &settings, &params, NULL, user_data);
        } else {
-               return ngtcp2_conn_client_new(pconn, dcid, scid, path, version, &callbacks, &settings, &params, NULL, user_data);
+               return ngtcp2_conn_client_new(pconn, dcid, scid, path, version, &callbacks,
+                                             &settings, &params, NULL, user_data);
        }
 }
 
@@ -735,7 +743,8 @@ int knot_xquic_client(knot_xquic_table_t *table, struct sockaddr_in6 *dest,
 }
 
 _public_
-int knot_xquic_handle(knot_xquic_table_t *table, knot_xdp_msg_t *msg, uint64_t idle_timeout, knot_xquic_conn_t **out_conn)
+int knot_quic_handle(knot_xquic_table_t *table, knot_quic_reply_t *reply,
+                     uint64_t idle_timeout, knot_xquic_conn_t **out_conn)
 {
        *out_conn = NULL;
 
@@ -743,13 +752,14 @@ int knot_xquic_handle(knot_xquic_table_t *table, knot_xdp_msg_t *msg, uint64_t i
        ngtcp2_cid scid = { 0 }, dcid = { 0 }, odcid = { 0 };
        uint64_t now = get_timestamp();
        int ret = ngtcp2_pkt_decode_version_cid(&decoded_cids,
-                                               msg->payload.iov_base,
-                                               msg->payload.iov_len,
+                                               reply->in_payload->iov_base,
+                                               reply->in_payload->iov_len,
                                                SERVER_DEFAULT_SCIDLEN);
        if (ret == NGTCP2_ERR_VERSION_NEGOTIATION) {
-               return -XQUIC_SEND_VERSION_NEGOTIATION;
+               ret = -XQUIC_SEND_VERSION_NEGOTIATION;
+               goto finish;
        } else if (ret != NGTCP2_NO_ERROR) {
-               return ret;
+               goto finish;
        }
        ngtcp2_cid_init(&dcid, decoded_cids.dcid, decoded_cids.dcidlen);
        ngtcp2_cid_init(&scid, decoded_cids.scid, decoded_cids.scidlen);
@@ -757,40 +767,48 @@ int knot_xquic_handle(knot_xquic_table_t *table, knot_xdp_msg_t *msg, uint64_t i
        knot_xquic_conn_t *xconn = xquic_table_lookup(&dcid, table);
 
        if (decoded_cids.version == 0 /* short header */ && xconn == NULL) {
-               return KNOT_EOK; // NOOP
+               ret = KNOT_EOK; // NOOP
+               goto finish;
        }
 
        ngtcp2_path path;
-       path.remote.addr = (struct sockaddr *)&msg->ip_from;
-       path.remote.addrlen = addr_len(&msg->ip_from);
-       path.local.addr = (struct sockaddr *)&msg->ip_to;
-       path.local.addrlen = addr_len(&msg->ip_to);
+       path.remote.addr = (struct sockaddr *)reply->ip_rem;
+       path.remote.addrlen = addr_len((struct sockaddr_in6 *)reply->ip_rem);
+       path.local.addr = (struct sockaddr *)reply->ip_loc;
+       path.local.addrlen = addr_len((struct sockaddr_in6 *)reply->ip_loc);
 
        if (xconn == NULL) {
                // new conn
 
                ngtcp2_pkt_hd header = { 0 };
-               ret = ngtcp2_accept(&header, msg->payload.iov_base, msg->payload.iov_len);
+               ret = ngtcp2_accept(&header, reply->in_payload->iov_base,
+                                   reply->in_payload->iov_len);
                if (ret == NGTCP2_ERR_RETRY) {
-                       return -XQUIC_SEND_RETRY;
+                       ret = -XQUIC_SEND_RETRY;
+                       goto finish;
                } else if (ret != NGTCP2_NO_ERROR) { // discard packet
-                       return KNOT_EOK;
+                       ret = KNOT_EOK;
+                       goto finish;
                }
 
                assert(header.type == NGTCP2_PKT_INITIAL);
                if (header.tokenlen == 0 && xquic_require_retry(table)) {
-                       return -XQUIC_SEND_RETRY;
+                       ret = -XQUIC_SEND_RETRY;
+                       goto finish;
                }
 
                if (header.tokenlen > 0) {
                        ret = ngtcp2_crypto_verify_retry_token(
                                &odcid, header.token, header.tokenlen,
-                               (const uint8_t *)table->hash_secret, sizeof(table->hash_secret), header.version,
-                               (const struct sockaddr *)&msg->ip_from, addr_len(&msg->ip_from),
+                               (const uint8_t *)table->hash_secret,
+                               sizeof(table->hash_secret), header.version,
+                               (const struct sockaddr *)reply->ip_rem,
+                               addr_len((struct sockaddr_in6 *)reply->ip_rem),
                                &dcid, idle_timeout, now // NOTE setting retry token validity to idle_timeout for simplicity
                        );
                        if (ret != 0) {
-                               return KNOT_EOK;
+                               ret = KNOT_EOK;
+                               goto finish;
                        }
                } else {
                        memcpy(&odcid, &dcid, sizeof(odcid));
@@ -798,42 +816,51 @@ int knot_xquic_handle(knot_xquic_table_t *table, knot_xdp_msg_t *msg, uint64_t i
 
                // server chooses his CID to his liking
                if (!init_unique_cid(&dcid, 0, table)) {
-                       return KNOT_ERROR;
+                       ret = KNOT_ERROR;
+                       goto finish;
                }
 
                xconn = xquic_table_add(NULL, &dcid, table);
                if (xconn == NULL) {
-                       return ENOMEM;
+                       ret = KNOT_ENOMEM;
+                       goto finish;
                }
                xquic_conn_mark_used(xconn, table, now);
 
-               ret = conn_new(&xconn->conn, &path, &dcid, &scid, &odcid, decoded_cids.version, now,
-                              table->udp_payload_limit, idle_timeout, xconn, true, header.tokenlen > 0);
+               ret = conn_new(&xconn->conn, &path, &dcid, &scid, &odcid, decoded_cids.version,
+                              now, table->udp_payload_limit, idle_timeout, xconn, true,
+                              header.tokenlen > 0);
                if (ret >= 0) {
                        ret = tls_init_conn_session(xconn, true);
                }
                if (ret < 0) {
                        knot_xquic_table_rem(xconn, table);
-                       return ret;
+                       goto finish;
                }
        }
 
        ngtcp2_pkt_info pi = { .ecn = NGTCP2_ECN_NOT_ECT, };
 
-       ret = ngtcp2_conn_read_pkt(xconn->conn, &path, &pi, msg->payload.iov_base, msg->payload.iov_len, now);
+       ret = ngtcp2_conn_read_pkt(xconn->conn, &path, &pi, reply->in_payload->iov_base,
+                                  reply->in_payload->iov_len, now);
 
        *out_conn = xconn;
        if (ret == NGTCP2_ERR_DRAINING // received CONNECTION_CLOSE from the counterpart
            || ngtcp2_err_is_fatal(ret)) { // connection doomed
                knot_xquic_table_rem(xconn, table);
-               return KNOT_ECONN;
+               ret = KNOT_ECONN;
+               goto finish;
        } else if (ret != NGTCP2_NO_ERROR) { // non-fatal error, discard packet
-               return KNOT_EOK;
+               ret = KNOT_EOK;
+               goto finish;
        }
 
        xquic_conn_mark_used(xconn, table, now);
 
-       return KNOT_EOK;
+       ret = KNOT_EOK;
+finish:
+       reply->handle_ret = ret;
+       return ret;
 }
 
 static bool stream_exists(knot_xquic_conn_t *xconn, int64_t stream_id)
@@ -842,9 +869,9 @@ static bool stream_exists(knot_xquic_conn_t *xconn, int64_t stream_id)
        return (ngtcp2_conn_set_stream_user_data(xconn->conn, stream_id, NULL) == NGTCP2_NO_ERROR);
 }
 
-static int send_stream(knot_xquic_table_t *quic_table, knot_xdp_socket_t *sock,
-                      knot_xdp_msg_t *in_msg, knot_xquic_conn_t *relay, int64_t stream_id,
-                      uint8_t *data, size_t len, bool fin, ngtcp2_ssize *sent)
+static int send_stream(knot_xquic_table_t *quic_table, knot_quic_reply_t *rpl,
+                       knot_xquic_conn_t *relay, int64_t stream_id,
+                       uint8_t *data, size_t len, bool fin, ngtcp2_ssize *sent)
 {
        (void)quic_table;
        assert(stream_id >= 0 || (data == NULL && len == 0));
@@ -858,40 +885,37 @@ static int send_stream(knot_xquic_table_t *quic_table, knot_xdp_socket_t *sock,
                assert((bool)(opened == stream_id) == stream_exists(relay, stream_id));
        }
 
-       uint32_t xdp_sent = 0;
-       knot_xdp_msg_t out_msg = { 0 };
-       int ret = knot_xdp_reply_alloc(sock, in_msg, &out_msg);
+       int ret = rpl->alloc_reply(rpl);
        if (ret != KNOT_EOK) {
                return ret;
        }
 
-       uint32_t fl = ((stream_id >= 0 && fin) ? NGTCP2_WRITE_STREAM_FLAG_FIN : NGTCP2_WRITE_STREAM_FLAG_NONE);
+       uint32_t fl = ((stream_id >= 0 && fin) ? NGTCP2_WRITE_STREAM_FLAG_FIN :
+                                                NGTCP2_WRITE_STREAM_FLAG_NONE);
        ngtcp2_vec vec = { .base = data, .len = len };
 
-       ret = ngtcp2_conn_writev_stream(relay->conn, NULL, NULL, out_msg.payload.iov_base, out_msg.payload.iov_len,
-                                       sent, fl, stream_id, &vec, (stream_id >= 0 ? 1 : 0), get_timestamp());
+       ret = ngtcp2_conn_writev_stream(relay->conn, NULL, NULL, rpl->out_payload->iov_base,
+                                       rpl->out_payload->iov_len, sent, fl, stream_id,
+                                       &vec, (stream_id >= 0 ? 1 : 0), get_timestamp());
        if (ret <= 0) {
-               knot_xdp_send_free(sock, &out_msg, 1);
+               rpl->free_reply(rpl);
                return ret;
        }
        if (*sent < 0) {
                *sent = 0;
        }
 
-       out_msg.payload.iov_len = ret;
-       ret = knot_xdp_send(sock, &out_msg, 1, &xdp_sent);
+       rpl->out_payload->iov_len = ret;
+       ret = rpl->send_reply(rpl);
        if (ret == KNOT_EOK) {
-               assert(xdp_sent == 1);
                return 1;
        }
        return ret;
 }
 
-static int send_special(knot_xquic_table_t *quic_table, knot_xdp_socket_t *sock,
-                        knot_xdp_msg_t *in_msg, int handle_ret)
+static int send_special(knot_xquic_table_t *quic_table, knot_quic_reply_t *rpl)
 {
-       knot_xdp_msg_t out_msg;
-       int ret = knot_xdp_reply_alloc(sock, in_msg, &out_msg);
+       int ret = rpl->alloc_reply(rpl);
        if (ret != KNOT_EOK) {
                return ret;
        }
@@ -901,8 +925,8 @@ static int send_special(knot_xquic_table_t *quic_table, knot_xdp_socket_t *sock,
        ngtcp2_cid scid = { 0 }, dcid = { 0 };
 
        int dvc_ret = ngtcp2_pkt_decode_version_cid(&decoded_cids,
-                                                   in_msg->payload.iov_base,
-                                                   in_msg->payload.iov_len,
+                                                   rpl->in_payload->iov_base,
+                                                   rpl->in_payload->iov_len,
                                                    SERVER_DEFAULT_SCIDLEN);
 
        uint8_t rnd = 0;
@@ -914,13 +938,14 @@ static int send_special(knot_xquic_table_t *quic_table, knot_xdp_socket_t *sock,
        uint8_t sreset_rand[NGTCP2_MIN_STATELESS_RESET_RANDLEN];
        dnssec_random_buffer(sreset_rand, sizeof(sreset_rand));
 
-       switch (handle_ret) {
+       switch (rpl->handle_ret) {
        case -XQUIC_SEND_VERSION_NEGOTIATION:
                if (dvc_ret != NGTCP2_ERR_VERSION_NEGOTIATION) {
+                       rpl->free_reply(rpl);
                        return KNOT_ERROR;
                }
                ret = ngtcp2_pkt_write_version_negotiation(
-                       out_msg.payload.iov_base, out_msg.payload.iov_len,
+                       rpl->out_payload->iov_base, rpl->out_payload->iov_len,
                        rnd, decoded_cids.scid, decoded_cids.scidlen, decoded_cids.dcid,
                        decoded_cids.dcidlen, supported_quic,
                        sizeof(supported_quic) / sizeof(*supported_quic)
@@ -933,21 +958,23 @@ static int send_special(knot_xquic_table_t *quic_table, knot_xdp_socket_t *sock,
                init_random_cid(&new_dcid, 0);
 
                ret = ngtcp2_crypto_generate_retry_token(
-                       retry_token, (const uint8_t *)quic_table->hash_secret, sizeof(quic_table->hash_secret), decoded_cids.version,
-                       (const struct sockaddr *)&in_msg->ip_from, sockaddr_len((const struct sockaddr_storage *)&in_msg->ip_from),
+                       retry_token, (const uint8_t *)quic_table->hash_secret,
+                       sizeof(quic_table->hash_secret), decoded_cids.version,
+                       (const struct sockaddr *)rpl->ip_rem, sockaddr_len(rpl->ip_rem),
                        &new_dcid, &dcid, now
                );
 
                if (ret >= 0) {
                        ret = ngtcp2_crypto_write_retry(
-                               out_msg.payload.iov_base, out_msg.payload.iov_len,
-                               decoded_cids.version, &scid, &new_dcid, &dcid, retry_token, ret
+                               rpl->out_payload->iov_base, rpl->out_payload->iov_len,
+                               decoded_cids.version, &scid, &new_dcid, &dcid,
+                               retry_token, ret
                        );
                }
                break;
        case -XQUIC_SEND_STATELESS_RESET:
                ret = ngtcp2_pkt_write_stateless_reset(
-                       out_msg.payload.iov_base, out_msg.payload.iov_len,
+                       rpl->out_payload->iov_base, rpl->out_payload->iov_len,
                        stateless_reset_token, sreset_rand, sizeof(sreset_rand)
                );
                break;
@@ -957,45 +984,43 @@ static int send_special(knot_xquic_table_t *quic_table, knot_xdp_socket_t *sock,
        }
 
        if (ret < 0) {
-               knot_xdp_send_free(sock, &out_msg, 1);
+               rpl->free_reply(rpl);
        } else {
-               uint32_t sent;
-               out_msg.payload.iov_len = ret;
-               ret = knot_xdp_send(sock, &out_msg, 1, &sent);
+               rpl->out_payload->iov_len = ret;
+               ret = rpl->send_reply(rpl);
        }
        return ret;
 }
 
 _public_
-int knot_xquic_send(knot_xquic_table_t *quic_table, knot_xquic_conn_t *relay,
-                    knot_xdp_socket_t *sock, knot_xdp_msg_t *in_msg,
-                    int handle_ret, unsigned max_msgs, bool ignore_lastbyte)
+int knot_quic_send(knot_xquic_table_t *quic_table, knot_xquic_conn_t *conn,
+                   knot_quic_reply_t *reply, unsigned max_msgs, bool ignore_lastbyte)
 {
-       if (handle_ret < 0) {
-               return handle_ret;
-       } else if (handle_ret > 0) {
-               return send_special(quic_table, sock, in_msg, handle_ret);
-       } else if (relay == NULL) {
+       if (reply->handle_ret < 0) {
+               return reply->handle_ret;
+       } else if (reply->handle_ret > 0) {
+               return send_special(quic_table, reply);
+       } else if (conn == NULL) {
                return KNOT_EINVAL;
-       } else if (relay->conn == NULL) {
+       } else if (conn->conn == NULL) {
                return KNOT_EOK;
        }
 
        unsigned sent_msgs = 0, stream_msgs = 0;
        int ret = 1;
-       for (int64_t si = 0; si < relay->streams_count && sent_msgs < max_msgs; /* NO INCREMENT */) {
-               int64_t stream_id = 4 * (relay->streams_first + si);
+       for (int64_t si = 0; si < conn->streams_count && sent_msgs < max_msgs; /* NO INCREMENT */) {
+               int64_t stream_id = 4 * (conn->streams_first + si);
 
                ngtcp2_ssize sent = 0;
-               size_t uf = relay->streams[si].unsent_offset;
-               knot_xquic_obuf_t *uo = relay->streams[si].unsent_obuf;
+               size_t uf = conn->streams[si].unsent_offset;
+               knot_xquic_obuf_t *uo = conn->streams[si].unsent_obuf;
                if (uo == NULL) {
                        si++;
                        continue;
                }
 
                bool fin = (((node_t *)uo->node.next)->next == NULL) && !ignore_lastbyte;
-               ret = send_stream(quic_table, sock, in_msg, relay, stream_id,
+               ret = send_stream(quic_table, reply, conn, stream_id,
                                  uo->buf + uf, uo->len - uf - (ignore_lastbyte ? 1 : 0),
                                  fin, &sent);
                if (ret < 0) {
@@ -1008,10 +1033,10 @@ int knot_xquic_send(knot_xquic_table_t *quic_table, knot_xquic_conn_t *relay,
                        sent++;
                }
                if (sent > 0) {
-                       knot_xquic_stream_mark_sent(relay, stream_id, sent);
+                       knot_xquic_stream_mark_sent(conn, stream_id, sent);
                }
 
-               if (stream_msgs >= max_msgs / relay->streams_count) {
+               if (stream_msgs >= max_msgs / conn->streams_count) {
                        stream_msgs = 0;
                        si++; // if this stream is sending too much, give chance to other streams
                }
@@ -1019,7 +1044,7 @@ int knot_xquic_send(knot_xquic_table_t *quic_table, knot_xquic_conn_t *relay,
 
        while (ret == 1) {
                ngtcp2_ssize unused = 0;
-               ret = send_stream(quic_table, sock, in_msg, relay, -1, NULL, 0, false, &unused);
+               ret = send_stream(quic_table, reply, conn, -1, NULL, 0, false, &unused);
        }
 
        return ret;
index 943a2f371ce9dac426978fd5f33e28533d80e743..c4af674b55711f797c69cb6fc2f0f61309930a2d 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #pragma once
 
 #include "libknot/xdp/quic_conn.h"
-#include "libknot/xdp/xdp.h"
 
 struct knot_quic_creds;
 struct knot_quic_session;
 
+typedef struct knot_quic_reply {
+       const struct sockaddr_storage *ip_rem;
+       const struct sockaddr_storage *ip_loc;
+       struct iovec *in_payload;
+       struct iovec *out_payload;
+       void *in_ctx;
+       void *out_ctx;
+
+       void *sock;
+       int handle_ret;
+
+       int (*alloc_reply)(struct knot_quic_reply *);
+       int (*send_reply)(struct knot_quic_reply *);
+       void (*free_reply)(struct knot_quic_reply *);
+} knot_quic_reply_t;
+
 /*!
  * \brief Gets data needed for session resumption.
  *
@@ -104,31 +119,28 @@ int knot_xquic_client(knot_xquic_table_t *table, struct sockaddr_in6 *dest,
 /*!
  * \brief Handle incoming QUIC packet.
  *
- * \param table           QUIC connectoins table-
- * \param msg             Incoming XDP packet.
+ * \param table           QUIC connectoins table.
+ * \param reply           Incoming packet info.
  * \param idle_timeout    Configured idle timeout for connections (in nanoseconds).
  * \param out_conn        Out: QUIC connection that this packet belongs to.
  *
- * \return KNOT_E*
+ * \return KNOT_E* or -XQUIC_SEND_*
  */
-int knot_xquic_handle(knot_xquic_table_t *table, knot_xdp_msg_t *msg,
-                      uint64_t idle_timeout, knot_xquic_conn_t **out_conn);
+int knot_quic_handle(knot_xquic_table_t *table, knot_quic_reply_t *reply,
+                     uint64_t idle_timeout, knot_xquic_conn_t **out_conn);
 
 /*!
  * \brief Send outgoing QUIC packet(s) for a connection.
  *
  * \param quic_table         QUIC connection table.
- * \param relay              QUIC connection.
- * \param sock               XDP socket.
- * \param in_msg             Previous incomming packet for this connection.
- * \param handle_ret         Error returned from knot_xquic_handle() for incoming packet.
+ * \param conn               QUIC connection.
+ * \param reply              Incoming/outgoing packet info.
  * \param max_msgs           Maxmimum packets to be sent.
  * \param ignore_lastbyte    Cut off last byte of QUIC paylod.
  *
  * \return KNOT_E*
  */
-int knot_xquic_send(knot_xquic_table_t *quic_table, knot_xquic_conn_t *relay,
-                    knot_xdp_socket_t *sock, knot_xdp_msg_t *in_msg,
-                    int handle_ret, unsigned max_msgs, bool ignore_lastbyte);
+int knot_quic_send(knot_xquic_table_t *quic_table, knot_xquic_conn_t *conn,
+                   knot_quic_reply_t *reply, unsigned max_msgs, bool ignore_lastbyte);
 
 /*! @} */
index 20ee17653ec89e50714b84beb855ac8b9a3b49b7..ab44e581b900766f5950563a5aa0df484a9c24de 100644 (file)
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include <linux/if_ether.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <sys/uio.h>
index 2ec0c0c064bd923ae056ebf69e01e91eb125851b..4e3a2677fc5981657059683524629f82a3494cce 100644 (file)
@@ -424,6 +424,49 @@ inline static bool check_dns_payload(struct iovec *payl, xdp_gun_ctx_t *ctx,
        return true;
 }
 
+#ifdef ENABLE_QUIC
+static int quic_alloc_cb(knot_quic_reply_t *rpl)
+{
+       xdp_gun_ctx_t *ctx = rpl->in_ctx;
+       knot_xdp_msg_t *msg = rpl->out_ctx;
+
+       unsigned flags = ctx->ipv6 ? KNOT_XDP_MSG_IPV6 : 0;
+       if (ctx->vlan_tci != 0) {
+               flags |= KNOT_XDP_MSG_VLAN;
+       }
+
+       int ret = knot_xdp_send_alloc(rpl->sock, flags, msg);
+       if (ret != KNOT_EOK) {
+               return ret;
+       }
+
+       memcpy(msg->eth_from, ctx->local_mac,  sizeof(ctx->local_mac));
+       memcpy(msg->eth_to,   ctx->target_mac, sizeof(ctx->target_mac));
+       memcpy(&msg->ip_from, &ctx->local_ip,  sizeof(msg->ip_from));
+       memcpy(&msg->ip_to,   &ctx->target_ip, sizeof(msg->ip_to));
+
+       msg->vlan_tci = ctx->vlan_tci;
+
+       return KNOT_EOK;
+}
+
+static int quic_reply_alloc_cb(knot_quic_reply_t *rpl)
+{
+       return knot_xdp_reply_alloc(rpl->sock, rpl->in_ctx, rpl->out_ctx);
+}
+
+static int quic_send_cb(knot_quic_reply_t *rpl)
+{
+       uint32_t sent = 0;
+       return knot_xdp_send(rpl->sock, rpl->out_ctx, 1, &sent);
+}
+
+static void quic_free_cb(knot_quic_reply_t *rpl)
+{
+       knot_xdp_send_free(rpl->sock, rpl->out_ctx, 1);
+}
+#endif // ENABLE_QUIC
+
 void *xdp_gun_thread(void *_ctx)
 {
        xdp_gun_ctx_t *ctx = _ctx;
@@ -437,9 +480,9 @@ void *xdp_gun_thread(void *_ctx)
 #ifdef ENABLE_QUIC
        knot_xquic_table_t *quic_table = NULL;
        struct knot_quic_creds *quic_creds = NULL;
-       knot_xdp_msg_t quic_fake_req = { 0 };
        list_t quic_sessions;
        init_list(&quic_sessions);
+       knot_quic_reply_t replies[ctx->at_once];
 #endif // ENABLE_QUIC
        const uint64_t extra_wait = ctx->quic ? 4000000 : 1000000;
 
@@ -462,13 +505,6 @@ void *xdp_gun_thread(void *_ctx)
                        ERR2("failed to allocate QUIC connection table");
                        return NULL;
                }
-               ctx->target_ip.sin6_port = htobe16(ctx->target_port);
-
-               memcpy(quic_fake_req.eth_from, ctx->target_mac,  sizeof(ctx->target_mac));
-               memcpy(quic_fake_req.eth_to,   ctx->local_mac,   sizeof(ctx->local_mac));
-               memcpy(&quic_fake_req.ip_from, &ctx->target_ip,  sizeof(quic_fake_req.ip_from));
-               memcpy(&quic_fake_req.ip_to,   &ctx->local_ip,   sizeof(quic_fake_req.ip_to));
-               quic_fake_req.flags = ctx->ipv6 ? KNOT_XDP_MSG_IPV6 : 0;
 #else
                assert(0);
 #endif // ENABLE_QUIC
@@ -512,7 +548,30 @@ void *xdp_gun_thread(void *_ctx)
        next_payload(&payload_ptr, ctx->thread_id);
 
 #ifdef ENABLE_QUIC
+       knot_quic_reply_t send_reply = {
+               .out_payload = &pkts->payload,
+               .in_ctx = ctx,
+               .out_ctx = pkts,
+               .sock = xsk,
+               .alloc_reply = quic_alloc_cb,
+               .send_reply = quic_send_cb,
+               .free_reply = quic_free_cb,
+       };
+       knot_xdp_msg_t msg_out;
+       for (int i = 0; i < ctx->at_once; i++) {
+               knot_quic_reply_t *reply = &replies[i];
+               memset(reply, 0, sizeof(*reply));
+               reply->out_payload = &msg_out.payload;
+               reply->out_ctx = &msg_out;
+               reply->sock = xsk;
+               reply->alloc_reply = quic_reply_alloc_cb;
+               reply->send_reply = quic_send_cb;
+               reply->free_reply = quic_free_cb;
+       }
+
+       ctx->target_ip.sin6_port = htobe16(ctx->target_port);
        knot_sweep_stats_t sweep_stats = { 0 };
+
        uint16_t local_ports[QUIC_THREAD_PORTS];
        uint16_t port = LOCAL_PORT_MIN;
        for (int i = 0; i < QUIC_THREAD_PORTS; ++i) {
@@ -546,12 +605,16 @@ void *xdp_gun_thread(void *_ctx)
                                } else if (ctx->quic) {
 #ifdef ENABLE_QUIC
                                        uint16_t local_port = local_ports[local_ports_it++ % QUIC_THREAD_PORTS];
+                                       ctx->local_ip.sin6_port = htobe16(local_port);
+
                                        for (unsigned i = 0; i < ctx->at_once; i++) {
                                                knot_xquic_conn_t *newconn = NULL;
-                                               ctx->local_ip.sin6_port = htobe16(local_port);
                                                ret = knot_xquic_client(quic_table, &ctx->target_ip, &ctx->local_ip, &newconn);
                                                if (ret == KNOT_EOK) {
-                                                       struct iovec tmp = { knot_xquic_stream_add_data(newconn, 0, NULL, payload_ptr->len), 0 };
+                                                       struct iovec tmp = {
+                                                               knot_xquic_stream_add_data(newconn, 0, NULL, payload_ptr->len),
+                                                               0
+                                                       };
                                                        put_dns_payload(&tmp, false, ctx, &payload_ptr);
                                                        if (EMPTY_LIST(quic_sessions)) {
                                                                newconn->streams_count = -1;
@@ -560,8 +623,8 @@ void *xdp_gun_thread(void *_ctx)
                                                                rem_node(session);
                                                                (void)knot_xquic_session_load(newconn, session);
                                                        }
-                                                       quic_fake_req.ip_to.sin6_port = htobe16(local_port);
-                                                       ret = knot_xquic_send(quic_table, newconn, xsk, &quic_fake_req, KNOT_EOK, 1, (ctx->ignore1 & KXDPGUN_IGNORE_LASTBYTE));
+                                                       ret = knot_quic_send(quic_table, newconn, &send_reply, 1,
+                                                                            (ctx->ignore1 & KXDPGUN_IGNORE_LASTBYTE));
                                                }
                                                if (ret == KNOT_EOK) {
                                                        local_stats.qry_sent++;
@@ -659,8 +722,17 @@ void *xdp_gun_thread(void *_ctx)
                                } else if (ctx->quic) {
 #ifdef ENABLE_QUIC
                                        knot_xquic_conn_t *relays[recvd];
+
                                        for (size_t i = 0; i < recvd; i++) {
-                                               ret = knot_xquic_handle(quic_table, &pkts[i], 5000000000L, &relays[i]);
+                                               knot_xdp_msg_t *msg_in = &pkts[i];
+                                               knot_quic_reply_t *reply = &replies[i];
+
+                                               reply->ip_rem = (struct sockaddr_storage *)&msg_in->ip_from;
+                                               reply->ip_loc = (struct sockaddr_storage *)&msg_in->ip_to;
+                                               reply->in_payload = &msg_in->payload;
+                                               reply->in_ctx = msg_in;
+
+                                               ret = knot_quic_handle(quic_table, &replies[i], 5000000000L, &relays[i]);
                                                if (ret == KNOT_ECONN) {
                                                        local_stats.rst_recv++;
                                                        continue;
@@ -723,7 +795,8 @@ void *xdp_gun_thread(void *_ctx)
                                                                continue;
                                                        }
                                                }
-                                               ret = knot_xquic_send(quic_table, rl, xsk, &pkts[i], KNOT_EOK, 4, (ctx->ignore1 & KXDPGUN_IGNORE_LASTBYTE));
+                                               ret = knot_quic_send(quic_table, rl, &replies[i], 4,
+                                                                    (ctx->ignore1 & KXDPGUN_IGNORE_LASTBYTE));
                                                if (ret != KNOT_EOK) {
                                                        errors++;
                                                }