]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
server: add configuration option for enabling socket affinity
authorDaniel Salzman <daniel.salzman@nic.cz>
Mon, 18 Jan 2021 10:19:35 +0000 (11:19 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Mon, 18 Jan 2021 16:41:25 +0000 (17:41 +0100)
doc/man/knot.conf.5in
doc/reference.rst
src/knot/conf/base.c
src/knot/conf/base.h
src/knot/conf/conf.c
src/knot/conf/conf.h
src/knot/conf/schema.c
src/knot/conf/schema.h
src/knot/server/server.c
tests/knot/test_confio.c

index c7b8380393325956360729c333ecd1f8eed818e2..3d7f2098e5a50ae2561a375351504e4a324a9893 100644 (file)
@@ -190,6 +190,7 @@ server:
     tcp\-remote\-io\-timeout: INT
     tcp\-max\-clients: INT
     tcp\-reuseport: BOOL
+    socket\-affinity: BOOL
     udp\-max\-payload: SIZE
     udp\-max\-payload\-ipv4: SIZE
     udp\-max\-payload\-ipv6: SIZE
@@ -332,6 +333,16 @@ advisable to use this option on slave servers.
 Change of this parameter requires restart of the Knot server to take effect.
 .sp
 \fIDefault:\fP off
+.SS socket\-affinity
+.sp
+If enabled and if SO_REUSEPORT is available on Linux, all configured network
+sockets are bound to UDP and TCP workers in order to increase the networking performance.
+This mode isn\(aqt recommended for setups where the number of network card queues
+is lower than the number of UDP or TCP workers.
+.sp
+Change of this parameter requires restart of the Knot server to take effect.
+.sp
+\fIDefault:\fP off
 .SS tcp\-max\-clients
 .sp
 A maximum number of TCP clients connected in parallel, set this below the file
index b4e9f6ba947f545dfcaf563878f45339be1b2cb0..9e06d31d2320d94c864b294f76f8ce65cd6e327c 100644 (file)
@@ -141,6 +141,7 @@ General options related to the server.
      tcp-remote-io-timeout: INT
      tcp-max-clients: INT
      tcp-reuseport: BOOL
+     socket-affinity: BOOL
      udp-max-payload: SIZE
      udp-max-payload-ipv4: SIZE
      udp-max-payload-ipv6: SIZE
@@ -328,6 +329,20 @@ Change of this parameter requires restart of the Knot server to take effect.
 
 *Default:* off
 
+.. _server_socket-affinity:
+
+socket-affinity
+---------------
+
+If enabled and if SO_REUSEPORT is available on Linux, all configured network
+sockets are bound to UDP and TCP workers in order to increase the networking performance.
+This mode isn't recommended for setups where the number of network card queues
+is lower than the number of UDP or TCP workers.
+
+Change of this parameter requires restart of the Knot server to take effect.
+
+*Default:* off
+
 .. _server_tcp-max-clients:
 
 tcp-max-clients
index edb40c02cd26ae441058bd39bccac7f99fb4b37d..279e0df0632f7be1d2f82ee4be33cafd03e582fb 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
@@ -124,6 +124,7 @@ static void init_cache(
 
        static bool   first_init = true;
        static bool   running_tcp_reuseport;
+       static bool   running_socket_affinity;
        static size_t running_udp_threads;
        static size_t running_tcp_threads;
        static size_t running_xdp_threads;
@@ -131,6 +132,7 @@ static void init_cache(
 
        if (first_init || reinit_cache) {
                running_tcp_reuseport = conf_tcp_reuseport(conf);
+               running_socket_affinity = conf_socket_affinity(conf);
                running_udp_threads = conf_udp_threads(conf);
                running_tcp_threads = conf_tcp_threads(conf);
                running_xdp_threads = conf_xdp_threads(conf);
@@ -183,6 +185,8 @@ static void init_cache(
 
        conf->cache.srv_tcp_reuseport = running_tcp_reuseport;
 
+       conf->cache.srv_socket_affinity = running_socket_affinity;
+
        conf->cache.srv_udp_threads = running_udp_threads;
 
        conf->cache.srv_tcp_threads = running_tcp_threads;
index 464f03c09156a958c05326c29af388dd7d2b08e4..53f97f2c8b168e40a723f276cc12cc9f15a9035f 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
@@ -114,6 +114,7 @@ typedef struct {
                int srv_tcp_io_timeout;
                int srv_tcp_remote_io_timeout;
                bool srv_tcp_reuseport;
+               bool srv_socket_affinity;
                size_t srv_udp_threads;
                size_t srv_tcp_threads;
                size_t srv_xdp_threads;
index 1eba3acf18a81c34a353c8fb3ee1865f38ce38d9..ebd1b050ca9a3b0c82cdf7a778c45ad5e23ebb88 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
@@ -1174,6 +1174,14 @@ bool conf_tcp_reuseport_txn(
        return conf_bool(&val);
 }
 
+bool conf_socket_affinity_txn(
+       conf_t *conf,
+       knot_db_txn_t *txn)
+{
+       conf_val_t val = conf_get_txn(conf, txn, C_SRV, C_SOCKET_AFFINITY);
+       return conf_bool(&val);
+}
+
 size_t conf_udp_threads_txn(
        conf_t *conf,
        knot_db_txn_t *txn)
index 84c90660e0a3499027f04ef7232a8d646b7736bb..e3d01d540f0fa4a1fea3d206600925484bd12307 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
@@ -686,6 +686,24 @@ static inline bool conf_tcp_reuseport(
        return conf_tcp_reuseport_txn(conf, &conf->read_txn);
 }
 
+/*!
+ * Gets the configured setting of the socket affinity switch.
+ *
+ * \param[in] conf  Configuration.
+ * \param[in] txn   Configuration DB transaction.
+ *
+ * \return True if enabled, false otherwise.
+ */
+bool conf_socket_affinity_txn(
+       conf_t *conf,
+       knot_db_txn_t *txn
+);
+static inline bool conf_socket_affinity(
+       conf_t *conf)
+{
+       return conf_socket_affinity_txn(conf, &conf->read_txn);
+}
+
 /*!
  * Gets the configured number of UDP threads.
  *
index a3eb18aea41f05f0ae1b3dbfe937a34125e21dfd..d39fd159089c2a0b6c192877720df29808e716a6 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
@@ -171,6 +171,7 @@ static const yp_item_t desc_server[] = {
        { C_TCP_RMT_IO_TIMEOUT,   YP_TINT,  YP_VINT = { 0, INT32_MAX, 5000 } },
        { C_TCP_MAX_CLIENTS,      YP_TINT,  YP_VINT = { 0, INT32_MAX, YP_NIL } },
        { C_TCP_REUSEPORT,        YP_TBOOL, YP_VNONE },
+       { C_SOCKET_AFFINITY,      YP_TBOOL, YP_VNONE },
        { C_UDP_MAX_PAYLOAD,      YP_TINT,  YP_VINT = { KNOT_EDNS_MIN_DNSSEC_PAYLOAD,
                                                        KNOT_EDNS_MAX_UDP_PAYLOAD,
                                                        1232, YP_SSIZE } },
index 931ad12016b9bf4f28da6529bab189da57e061cc..0039962c90fe12147ea766660c4517fafb5264ab 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
 #define C_SERVER               "\x06""server"
 #define C_SIGNING_THREADS      "\x0F""signing-threads"
 #define C_SINGLE_TYPE_SIGNING  "\x13""single-type-signing"
+#define C_SOCKET_AFFINITY      "\x0F""socket-affinity"
 #define C_SRV                  "\x06""server"
 #define C_STATS                        "\x0A""statistics"
 #define C_STORAGE              "\x07""storage"
index ca42135d15f9a375eb4dca844258dd43a3d5b0fa..b4bf25d9790a59ffb87902550088c8b57a18d71c 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
@@ -307,13 +307,14 @@ static iface_t *server_init_xdp_iface(struct sockaddr_storage *addr, unsigned *t
  * \param udp_thread_count  Number of created UDP workers.
  * \param tcp_thread_count  Number of created TCP workers.
  * \param tcp_reuseport     Indication if reuseport on TCP is enabled.
+ * \param socket_affinity   Indication if CBPF should be attached.
  *
  * \retval Pointer to a new initialized inteface.
  * \retval NULL if error.
  */
 static iface_t *server_init_iface(struct sockaddr_storage *addr,
                                   int udp_thread_count, int tcp_thread_count,
-                                  bool tcp_reuseport)
+                                  bool tcp_reuseport, bool socket_affinity)
 {
        iface_t *new_if = calloc(1, sizeof(*new_if));
        if (new_if == NULL) {
@@ -374,7 +375,7 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr,
                        return NULL;
                }
 
-               if (udp_bind_flags & NET_BIND_MULTIPLE) {
+               if ((udp_bind_flags & NET_BIND_MULTIPLE) && socket_affinity) {
                        if (!server_attach_reuseport_bpf(sock, udp_socket_count) &&
                            warn_cbpf) {
                                log_warning("cannot ensure optimal CPU locality for UDP");
@@ -446,7 +447,7 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr,
                        return NULL;
                }
 
-               if (tcp_bind_flags & NET_BIND_MULTIPLE) {
+               if ((tcp_bind_flags & NET_BIND_MULTIPLE) && socket_affinity) {
                        if (!server_attach_reuseport_bpf(sock, tcp_socket_count) &&
                            warn_cbpf) {
                                log_warning("cannot ensure optimal CPU locality for TCP");
@@ -475,7 +476,9 @@ static int configure_sockets(conf_t *conf, server_t *s)
 
 #ifdef ENABLE_REUSEPORT
        /* Log info if reuseport is used and for what protocols. */
-       log_info("using reuseport for UDP%s", conf->cache.srv_tcp_reuseport ? " and TCP" : "");
+       log_info("using reuseport%s for UDP%s",
+                conf->cache.srv_socket_affinity ? " with socket affinity" : "",
+                conf->cache.srv_tcp_reuseport ? " and TCP" : "");
 #endif
 
        /* Update bound interfaces. */
@@ -505,6 +508,7 @@ static int configure_sockets(conf_t *conf, server_t *s)
        unsigned size_udp = s->handlers[IO_UDP].handler.unit->size;
        unsigned size_tcp = s->handlers[IO_TCP].handler.unit->size;
        bool tcp_reuseport = conf->cache.srv_tcp_reuseport;
+       bool socket_affinity = conf->cache.srv_socket_affinity;
        char *rundir = conf_abs_path(&rundir_val, NULL);
        while (listen_val.code == KNOT_EOK) {
                struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
@@ -513,7 +517,7 @@ static int configure_sockets(conf_t *conf, server_t *s)
                log_info("binding to interface %s", addr_str);
 
                iface_t *new_if = server_init_iface(&addr, size_udp, size_tcp,
-                                                   tcp_reuseport);
+                                                   tcp_reuseport, socket_affinity);
                if (new_if == NULL) {
                        server_deinit_iface_list(newlist, nifs);
                        free(rundir);
@@ -861,6 +865,7 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server)
        const char *msg = "changes of %s require restart to take effect";
 
        static bool warn_tcp_reuseport = true;
+       static bool warn_socket_affinity = true;
        static bool warn_udp = true;
        static bool warn_tcp = true;
        static bool warn_bg = true;
@@ -871,6 +876,11 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server)
                warn_tcp_reuseport = false;
        }
 
+       if (warn_socket_affinity && conf->cache.srv_socket_affinity != conf_socket_affinity(conf)) {
+               log_warning(msg, &C_SOCKET_AFFINITY[1]);
+               warn_socket_affinity = false;
+       }
+
        if (warn_udp && server->handlers[IO_UDP].size != conf_udp_threads(conf)) {
                log_warning(msg, &C_UDP_WORKERS[1]);
                warn_udp = false;
index 191c1616231dc48da219c73dc1b91ec8fa657752..7945d33747c410f925c925f2ec3818c8e4ec84ad 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2021 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
@@ -908,6 +908,7 @@ static void test_conf_io_list(void)
              "server.tcp-remote-io-timeout\n"
              "server.tcp-max-clients\n"
              "server.tcp-reuseport\n"
+             "server.socket-affinity\n"
              "server.udp-workers\n"
              "server.tcp-workers\n"
              "server.background-workers\n"
@@ -930,6 +931,7 @@ static const yp_item_t desc_server[] = {
        { C_TCP_RMT_IO_TIMEOUT,   YP_TINT,  YP_VNONE },
        { C_TCP_MAX_CLIENTS,      YP_TINT,  YP_VNONE },
        { C_TCP_REUSEPORT,        YP_TBOOL, YP_VNONE },
+       { C_SOCKET_AFFINITY,      YP_TBOOL, YP_VNONE },
        { C_UDP_WORKERS,          YP_TINT,  YP_VNONE },
        { C_TCP_WORKERS,          YP_TINT,  YP_VNONE },
        { C_BG_WORKERS,           YP_TINT,  YP_VNONE },