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
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
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
*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
-/* 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
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;
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);
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;
-/* 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
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;
-/* 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
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)
-/* 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
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.
*
-/* 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
{ 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 } },
-/* 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"
-/* 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
* \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) {
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");
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");
#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. */
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);
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);
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;
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;
-/* 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
"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"
{ 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 },