edns\-client\-subnet: BOOL
answer\-rotation: BOOL
listen: ADDR[@INT] ...
+ listen\-xdp: STR ...
.ft P
.fi
.UNINDENT
Change of this parameter requires restart of the Knot server to take effect.
.sp
\fIDefault:\fP equal to the number of online CPUs, default value is at least 10
-.SS xdp\-workers
-.sp
-A number of XDP workers (threads) used to process incoming queries
-over UDP with the use of eXpress Data Path, bypassing Linux network stack.
-.sp
-Change of this parameter requires restart of the Knot server to take effect.
-.sp
-If set to zero, XDP is not initialized at all.
-.sp
-Pre\-requisite: compiled\-in support for XDP.
-.sp
-It\(aqs recommended to be set only if the server listens on one interface.
-The number of workers should match the number of network interface RX queues.
-.sp
-\fIDefault:\fP 0
.SS background\-workers
.sp
A number of workers (threads) used to execute background operations (zone
Change of this parameter requires restart of the Knot server to take effect.
.sp
\fIDefault:\fP not set
+.SS listen\-xdp
+.sp
+One or more specifications in the form \fBeth_dev@port\fP, e.g. \fBeth1@53\fP\&.
+Alternatively, an IP address can be used instead of a device name, but Knot
+will still listen on all addresses belonging to the same interface!
+.sp
+If specified, Knot will create additional XDP workers, listening
+on specified interface(s) and port(s) on UDP protocol, with enhanced
+performance. The number of XDP workers is equal to the sum of the
+interfaces\(aq RX queues.
+.sp
+It is strongly recommended to also \fI\%listen\fP on all those
+addresses, at least to fulfill the requirement of working TCP fallback.
+.sp
+Change of this parameter requires restart of the Knot server to take effect.
+.sp
+\fIDefault:\fP not set
.SH KEY SECTION
.sp
Shared TSIG keys used to authenticate communication with the server.
Notes
-----
-The number of configured :ref:`server_xdp-workers` shall match the number of network
-card's queues.
-
Don't attempt settings like::
# ip link set mtu $mtu dev $dev
edns-client-subnet: BOOL
answer-rotation: BOOL
listen: ADDR[@INT] ...
+ listen-xdp: STR ...
.. CAUTION::
When you change configuration parameters dynamically or via configuration file
*Default:* equal to the number of online CPUs, default value is at least 10
-.. _server_xdp-workers:
-
-xdp-workers
------------
-
-A number of XDP workers (threads) used to process incoming queries
-over UDP with the use of eXpress Data Path, bypassing Linux network stack.
-
-Change of this parameter requires restart of the Knot server to take effect.
-
-If set to zero, XDP is not initialized at all.
-
-Pre-requisite: compiled-in support for XDP.
-
-It's recommended to be set only if the server listens on one interface.
-The number of workers should match the number of network interface RX queues.
-
-*Default:* 0
-
.. _server_background-workers:
background-workers
*Default:* not set
+.. _server_listen-xdp:
+
+listen-xdp
+----------
+
+One or more specifications in the form ``eth_dev@port``, e.g. ``eth1@53``.
+Alternatively, an IP address can be used instead of a device name, but Knot
+will still listen on all addresses belonging to the same interface!
+
+If specified, Knot will create additional XDP workers, listening
+on specified interface(s) and port(s) on UDP protocol, with enhanced
+performance. The number of XDP workers is equal to the sum of the
+interfaces' RX queues.
+
+It is strongly recommended to also :ref:`server_listen` on all those
+addresses, at least to fulfill the requirement of working TCP fallback.
+
+Change of this parameter requires restart of the Knot server to take effect.
+
+*Default:* not set
+
.. _Key section:
Key section
static bool first_init = true;
static bool running_tcp_reuseport;
static size_t running_udp_threads;
- static size_t running_xdp_threads;
static size_t running_tcp_threads;
static size_t running_bg_threads;
if (first_init || reinit_cache) {
running_tcp_reuseport = conf_tcp_reuseport(conf);
running_udp_threads = conf_udp_threads(conf);
- running_xdp_threads = conf_xdp_threads(conf);
running_tcp_threads = conf_tcp_threads(conf);
running_bg_threads = conf_bg_threads(conf);
conf->cache.srv_udp_threads = running_udp_threads;
- conf->cache.srv_xdp_threads = running_xdp_threads;
-
conf->cache.srv_tcp_threads = running_tcp_threads;
conf->cache.srv_bg_threads = running_bg_threads;
return workers;
}
-size_t conf_xdp_threads_txn(
- conf_t *conf,
- knot_db_txn_t *txn)
-{
- conf_val_t val = conf_get_txn(conf, txn, C_SRV, C_XDP_WORKERS);
- int64_t workers = conf_int(&val);
- if (workers == YP_NIL) {
- return 0;
- }
-
- return workers;
-}
-
size_t conf_tcp_threads_txn(
conf_t *conf,
knot_db_txn_t *txn)
return conf_udp_threads_txn(conf, &conf->read_txn);
}
-/*!
- * Gets the configured number of XDP threads.
- *
- * \param[in] conf Configuration.
- * \param[in] txn Configuration DB transaction.
- *
- * \return Number of threads.
- */
-size_t conf_xdp_threads_txn(
- conf_t *conf,
- knot_db_txn_t *txn
-);
-static inline size_t conf_xdp_threads(
- conf_t *conf)
-{
- return conf_xdp_threads_txn(conf, &conf->read_txn);
-}
-
/*!
* Gets the configured number of TCP threads.
*
{ C_USER, YP_TSTR, YP_VNONE },
{ C_PIDFILE, YP_TSTR, YP_VSTR = { "knot.pid" } },
{ C_UDP_WORKERS, YP_TINT, YP_VINT = { 1, 255, YP_NIL } },
- { C_XDP_WORKERS, YP_TINT, YP_VINT = { 0, 255, YP_NIL } },
{ C_TCP_WORKERS, YP_TINT, YP_VINT = { 1, 255, YP_NIL } },
{ C_BG_WORKERS, YP_TINT, YP_VINT = { 1, 255, YP_NIL } },
{ C_ASYNC_START, YP_TBOOL, YP_VNONE },
#define C_USER "\x04""user"
#define C_VERSION "\x07""version"
#define C_VIA "\x03""via"
-#define C_XDP_WORKERS "\x0B""xdp-workers"
#define C_ZONE "\x04""zone"
#define C_ZONEFILE_LOAD "\x0D""zonefile-load"
#define C_ZONEFILE_SYNC "\x0D""zonefile-sync"
CHECK_LEGACY_NAME(C_SRV, C_MAX_IPV4_UDP_PAYLOAD, C_UDP_MAX_PAYLOAD_IPV4);
CHECK_LEGACY_NAME(C_SRV, C_MAX_IPV6_UDP_PAYLOAD, C_UDP_MAX_PAYLOAD_IPV6);
-#ifndef ENABLE_XDP
- if (conf_xdp_threads_txn(args->extra->conf, args->extra->txn) > 0) {
- args->err_str = "not compiled with XDP support";
- return KNOT_EINVAL;
- }
-#endif
-
return KNOT_EOK;
}
int running_bkg_wrk, wrk_queue;
worker_pool_status(args->server->workers, &running_bkg_wrk, &wrk_queue);
ret = snprintf(buff, sizeof(buff), "UDP workers: %zu, TCP workers %zu, "
- "XDP workers: %zu, "
"background workers: %zu (running: %d, pending: %d)",
conf()->cache.srv_udp_threads, conf()->cache.srv_tcp_threads,
- conf()->cache.srv_xdp_threads,
conf()->cache.srv_bg_threads, running_bkg_wrk, wrk_queue);
} else if (strcasecmp(type, "configure") == 0) {
ret = snprintf(buff, sizeof(buff), "%s", CONFIGURE_SUMMARY);
case KNOTD_CONF_ENV_WORKERS_UDP:
out.single.integer = config->cache.srv_udp_threads;
break;
- case KNOTD_CONF_ENV_WORKERS_XDP:
- out.single.integer = config->cache.srv_xdp_threads;
- break;
case KNOTD_CONF_ENV_WORKERS_TCP:
out.single.integer = config->cache.srv_tcp_threads;
break;
return matches == 0 ? KNOT_EADDRNOTAVAIL : KNOT_ELIMIT;
}
+// returns >= 0: the number of RX queues; < 0 : error
+static int get_xdp_iface(struct sockaddr_storage *addr, char **out_devname, uint16_t *out_port)
+{
+#ifndef ENABLE_XDP
+ return 0;
+#else
+
+ char *dev = NULL;
+ int port = 0;
+ if (addr->ss_family == AF_UNIX) {
+ dev = strdup(((struct sockaddr_un *)addr)->sun_path);
+ if (dev == NULL) {
+ log_warning("%s", knot_strerror(KNOT_ENOMEM));
+ return KNOT_ENOMEM;
+ }
+ char *sport = strchr(dev, '@');
+ if (sport == NULL || (port = atoi(sport + 1)) < 1 || port > 0xffff) {
+ log_warning("Wrong format of XDP listen, expected 'dev@port': '%s'", dev);
+ free(dev);
+ return KNOT_EINVAL;
+ }
+ *sport = '\0';
+ } else {
+ int ret = iface_addr2name(addr, &dev);
+ if (ret != KNOT_EOK) {
+ if (dev != NULL) {
+ log_warning("XDP failed: address %s corresponds to %s net devices", dev, ret == KNOT_EADDRNOTAVAIL ? "none" : "more");
+ } else {
+ log_warning("failed to find dev for address (%s)", knot_strerror(ret));
+ }
+ return ret;
+ }
+ port = sockaddr_port(addr);
+ if (port < 1 || port > 0xffff) {
+ log_warning("port out of range");
+ free(dev);
+ return KNOT_ELIMIT;
+ }
+ }
+
+ int rx_queues = knot_eth_get_rx_queues(dev);
+ if (rx_queues < 0) {
+ log_warning("failed to obtain RX queue count for iface %s (%s)\n", dev, knot_strerror(rx_queues));
+ free(dev);
+ return rx_queues;
+ }
+
+ if (out_devname != NULL) {
+ *out_devname = dev;
+ } else {
+ free(dev);
+ }
+ if (out_port != NULL) {
+ *out_port = port;
+ }
+ return rx_queues;
+#endif
+}
+
+static iface_t *server_init_xdp_iface(struct sockaddr_storage *addr, unsigned *thread_id_start)
+{
+#ifndef ENABLE_XDP
+ assert(0);
+ return NULL;
+#else
+ char *dev = NULL;
+ uint16_t port = 0;
+ int rx_queues = get_xdp_iface(addr, &dev, &port);
+ if (rx_queues < 0) {
+ return NULL;
+ }
+
+ iface_t *new_if = calloc(1, sizeof(*new_if));
+ if (new_if == NULL) {
+ log_error("failed to initialize interface");
+ free(dev);
+ return NULL;
+ }
+ memcpy(&new_if->addr, addr, sizeof(*addr));
+
+ new_if->fd_xdp = malloc(rx_queues * sizeof(int));
+ new_if->sock_xdp = calloc(rx_queues, sizeof(*new_if->sock_xdp));
+ if (new_if->fd_xdp == NULL || new_if->sock_xdp == NULL) {
+ log_warning("failed to init XDP: not enough memory\n");
+ free(new_if);
+ free(dev);
+ return NULL;
+ }
+ new_if->fd_thread_ids = *thread_id_start;
+ *thread_id_start += rx_queues;
+
+ for (int i = 0; i < rx_queues; i++) {
+ int ret = knot_xsk_init(new_if->sock_xdp + i, dev, i, port, i == 0);
+
+ if (ret != KNOT_EOK) {
+ log_warning("failed to init XDP in dev %s queue %d (%s)", dev, i, knot_strerror(ret));
+ new_if->fd_xdp[i] = -1;
+ } else {
+ new_if->fd_xdp[i] = knot_xsk_get_poll_fd(new_if->sock_xdp[i]);
+
+ }
+ new_if->fd_xdp_count++;
+ }
+ return new_if;
+#endif
+}
+
/*!
* \brief Create and initialize new interface.
*
*/
static iface_t *server_init_iface(struct sockaddr_storage *addr,
int udp_thread_count, int tcp_thread_count,
- int xdp_thread_count, bool tcp_reuseport)
+ bool tcp_reuseport)
{
iface_t *new_if = calloc(1, sizeof(*new_if));
if (new_if == NULL) {
int udp_bind_flags = 0;
int tcp_socket_count = 1;
int tcp_bind_flags = 0;
- int xdp_socket_count = 0;
#ifdef ENABLE_REUSEPORT
udp_socket_count = udp_thread_count;
}
#endif
-#ifdef ENABLE_XDP
- xdp_socket_count = xdp_thread_count;
-#endif
-
new_if->fd_udp = malloc(udp_socket_count * sizeof(int));
new_if->fd_tcp = malloc(tcp_socket_count * sizeof(int));
new_if->fd_udp_count += 1;
}
- if (xdp_socket_count > 0) {
-#ifndef ENABLE_XDP
- assert(0);
-#else
- char *dev = NULL;
- int ret = iface_addr2name(addr, &dev);
- if (ret != KNOT_EOK) {
- if (dev != NULL) {
- log_warning("XDP failed: address %s corresponds to %s net devices", dev, ret == KNOT_EADDRNOTAVAIL ? "none" : "more");
- } else {
- log_warning("failed to find dev for address (%s)", knot_strerror(ret));
- }
- goto skip_xdp;
- }
-
- int rx_queues = knot_eth_get_rx_queues(dev);
- if (rx_queues < 0) {
- log_warning("failed to obtain RX queue count for iface %s (%s)\n", dev, knot_strerror(rx_queues));
- goto skip_xdp;
- }
-
- assert(new_if->fd_xdp == NULL);
- assert(new_if->sock_xdp == NULL);
- new_if->fd_xdp = malloc(rx_queues * sizeof(int));
- new_if->sock_xdp = calloc(rx_queues, sizeof(*new_if->sock_xdp));
- if (new_if->fd_xdp == NULL || new_if->sock_xdp == NULL) {
- log_warning("failed to init XDP: not enough memory\n");
- goto skip_xdp;
- }
-
- for (int i = 0; i < rx_queues; i++) {
- assert(sockaddr_port(addr) < (1 << 16));
- ret = knot_xsk_init(new_if->sock_xdp + i, dev, i,
- sockaddr_port(addr), i == 0);
-
- if (ret != KNOT_EOK) {
- log_warning("failed to init XDP in dev %s queue %d (%s)", dev, i, knot_strerror(ret));
- new_if->fd_xdp[i] = -1;
- } else {
- new_if->fd_xdp[i] = knot_xsk_get_poll_fd(new_if->sock_xdp[i]);
-
- }
- new_if->fd_xdp_count++;
- }
-skip_xdp:
- free(dev);
-#endif
- }
-
-
warn_bind = true;
warn_bufsize = true;
warn_flag_misc = true;
log_info("using reuseport for UDP%s", conf->cache.srv_tcp_reuseport ? " and TCP" : "");
#endif
- if (conf->cache.srv_xdp_threads > 0) {
+ /* Update bound interfaces. */
+ conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN);
+ conf_val_t lisxdp_val = conf_get(conf, C_SRV, C_LISTEN_XDP);
+ conf_val_t rundir_val = conf_get(conf, C_SRV, C_RUNDIR);
+
+ if (lisxdp_val.code == KNOT_EOK) {
struct rlimit no_limit = { RLIM_INFINITY, RLIM_INFINITY };
int ret = setrlimit(RLIMIT_MEMLOCK, &no_limit);
if (ret) {
}
}
- /* Update bound interfaces. */
- conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN);
- conf_val_t rundir_val = conf_get(conf, C_SRV, C_RUNDIR);
-
- size_t nifs = conf_val_count(&listen_val), real_n = 0;
+ size_t nifs = conf_val_count(&listen_val) + conf_val_count(&lisxdp_val), real_n = 0;
iface_t *newlist = calloc(nifs, sizeof(*newlist));
if (newlist == NULL) {
return KNOT_ENOMEM;
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;
- iface_t *new_if = server_init_iface(&addr, size_udp, size_tcp, conf->cache.srv_xdp_threads, tcp_reuseport);
+ iface_t *new_if = server_init_iface(&addr, size_udp, size_tcp, tcp_reuseport);
if (new_if != NULL) {
memcpy(&newlist[real_n++], new_if, sizeof(*newlist));
free(new_if);
conf_val_next(&listen_val);
}
+ unsigned thread_id = s->handlers[IO_UDP].handler.unit->size + s->handlers[IO_TCP].handler.unit->size;
+ while (lisxdp_val.code == KNOT_EOK) {
+ struct sockaddr_storage addr = conf_addr(&lisxdp_val, NULL);
+ char addr_str[SOCKADDR_STRLEN] = { 0 };
+ sockaddr_tostr(addr_str, sizeof(addr_str), &addr);
+ log_info("binding to xdp interface %s", addr_str);
+
+ iface_t *new_if = server_init_xdp_iface(&addr, &thread_id);
+ if (new_if != NULL) {
+ memcpy(&newlist[real_n++], new_if, sizeof(*newlist));
+ free(new_if);
+ }
+ conf_val_next(&lisxdp_val);
+ }
assert(real_n <= nifs);
nifs = real_n;
free(rundir);
return KNOT_EOK;
}
+int server_count_xdp_threads(conf_t *conf)
+{
+ int res = 0, ret;
+ conf_val_t lisxdp_val = conf_get(conf, C_SRV, C_LISTEN_XDP);
+ while (lisxdp_val.code == KNOT_EOK) {
+ struct sockaddr_storage addr = conf_addr(&lisxdp_val, NULL);
+ ret = get_xdp_iface(&addr, NULL, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+ res += ret;
+ conf_val_next(&lisxdp_val);
+ }
+ return res;
+}
+
int server_init(server_t *server, int bg_workers)
{
if (server == NULL) {
static bool warn_tcp_reuseport = true;
static bool warn_udp = true;
- static bool warn_xdp = true;
static bool warn_tcp = true;
static bool warn_bg = true;
static bool warn_listen = true;
warn_udp = false;
}
- if (warn_xdp && server->handlers[IO_XDP].size != conf_xdp_threads(conf)) {
- log_warning(msg, "xdp-workers");
- warn_xdp = false;
- }
-
if (warn_tcp && server->handlers[IO_TCP].size != conf_tcp_threads(conf)) {
log_warning(msg, "tcp-workers");
warn_tcp = false;
server->state &= ~ServerRunning;
}
-static int set_handler(server_t *server, int index, unsigned size, bool use_xdp, runnable_t run)
+static int set_handler(server_t *server, int index, unsigned size, runnable_t run)
{
/* Initialize I/O handlers. */
int ret = server_init_handler(server, index, size, run, NULL);
}
server->handlers[index].size = size;
- server->handlers[index].handler.use_xdp = use_xdp;
return KNOT_EOK;
}
/*! \brief Reconfigure UDP and TCP query processing threads. */
-static int configure_threads(conf_t *conf, server_t *server)
+static int configure_threads(conf_t *conf, server_t *server, size_t xdp_threads)
{
- int ret = set_handler(server, IO_UDP, conf->cache.srv_udp_threads, false, udp_master);
+ int ret = set_handler(server, IO_UDP, conf->cache.srv_udp_threads, udp_master);
if (ret != KNOT_EOK) {
return ret;
}
- if (conf->cache.srv_xdp_threads > 0) {
- ret = set_handler(server, IO_XDP, conf->cache.srv_xdp_threads, true, udp_master);
+ if (xdp_threads > 0) {
+ ret = set_handler(server, IO_XDP, xdp_threads, udp_master);
if (ret != KNOT_EOK) {
return ret;
}
}
- return set_handler(server, IO_TCP, conf->cache.srv_tcp_threads, false, tcp_master);
+ return set_handler(server, IO_TCP, conf->cache.srv_tcp_threads, tcp_master);
}
static int reconfigure_journal_db(conf_t *conf, server_t *server)
knot_db_lmdb_get_path(conf->db));
}
+ if ((ret = server_count_xdp_threads(conf)) < 0) {
+ log_error("failed to configure XDP thread count (%s)",
+ knot_strerror(ret));
+ ret = 0;
+ }
+
/* Configure server threads. */
- if ((ret = configure_threads(conf, server)) != KNOT_EOK) {
+ if ((ret = configure_threads(conf, server, ret)) != KNOT_EOK) {
log_error("failed to configure server threads (%s)",
knot_strerror(ret));
}
dt_unit_t *unit; /*!< Threading unit */
unsigned *thread_state; /*!< Thread state */
unsigned *thread_id; /*!< Thread identifier. */
- bool use_xdp; /*!< Using XDP. */
} iohandler_t;
/*! \brief Server state flags.
int fd_tcp_count;
int *fd_xdp;
int fd_xdp_count;
+ unsigned fd_thread_ids;
struct knot_xsk_socket **sock_xdp;
struct sockaddr_storage addr;
} iface_t;
-/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2020 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
fdset_clear(fds);
for (const iface_t *i = ifaces; i != ifaces + n_ifaces; i++) {
int tcp_id = 0;
+ if (i->fd_tcp_count < 1) {
+ continue;
+ }
#ifdef ENABLE_REUSEPORT
if (conf()->cache.srv_tcp_reuseport) {
/* Note: thread_ids start with UDP threads, TCP threads follow. */
};
#endif /* ENABLE_XDP */
+static bool is_xdp_iface(const iface_t *iface)
+{
+ bool is_xdp1 = (iface->fd_xdp_count > 0);
+ bool is_xdp2 = (iface->fd_udp_count == 0 && iface->fd_tcp_count == 0);
+ assert(is_xdp1 == is_xdp2);
+ return is_xdp1 || is_xdp2;
+}
+
+static bool is_xdp_thread(const iface_t *iface_zero, int thread_id)
+{
+ return (thread_id >= iface_zero->fd_udp_count + iface_zero->fd_tcp_count);
+}
+
/*! \brief Get interface UDP descriptor for a given thread. */
-static int iface_udp_fd(const iface_t *iface, int thread_id, bool use_xdp, void **socket_ctx)
+static int iface_udp_fd(const iface_t *iface, const iface_t *iface_zero, int thread_id, void **socket_ctx)
{
- if (use_xdp) {
-#ifdef ENABLE_XDP
- size_t udp_wrk = conf()->cache.srv_udp_threads;
- size_t tcp_wrk = conf()->cache.srv_tcp_threads;
- size_t xdp_wrk = conf()->cache.srv_xdp_threads;
- // XDP worker thread follow after UDP and TCP worker threads
- assert(thread_id >= udp_wrk + tcp_wrk);
- assert(thread_id < udp_wrk + tcp_wrk + xdp_wrk);
+ assert(!is_xdp_iface(iface_zero));
+
+ bool xdp_iface = is_xdp_iface(iface);
+ bool xdp_thread = is_xdp_thread(iface_zero, thread_id);
+ assert(xdp_thread || thread_id < iface_zero->fd_udp_count);
- size_t xdp_wrk_id = thread_id - udp_wrk - tcp_wrk;
+ if (xdp_iface != xdp_thread) {
+ return -1;
+ }
- if (xdp_wrk_id >= iface->fd_xdp_count) {
+ if (xdp_thread) {
+#ifdef ENABLE_XDP
+ size_t xdp_wrk_id = thread_id - iface->fd_thread_ids;
+ if (thread_id < iface->fd_thread_ids || xdp_wrk_id >= iface->fd_xdp_count) {
return -1;
}
* \return Number of watched descriptors, zero on error.
*/
static unsigned udp_set_ifaces(const iface_t *ifaces, size_t n_ifaces, struct pollfd **fds_ptr,
- int thread_id, bool use_xdp, void **socket_ctxs)
+ int thread_id, void **socket_ctxs)
{
memset(socket_ctxs, 0, n_ifaces * sizeof(*socket_ctxs));
}
for (size_t i = 0; i < n_ifaces; i++) {
- fds[i].fd = iface_udp_fd(&ifaces[i], thread_id, use_xdp, &socket_ctxs[i]);
+ fds[i].fd = iface_udp_fd(&ifaces[i], &ifaces[0], thread_id, &socket_ctxs[i]);
if (fds[i].fd < 0) {
- return 0;
+ continue;
}
fds[i].events = POLLIN;
fds[i].revents = 0;
/* Prepare structures for bound sockets. */
unsigned thr_id = dt_get_id(thread);
iohandler_t *handler = (iohandler_t *)thread->data;
+ if (handler->server->n_ifaces == 0) {
+ return KNOT_EOK;
+ }
+
udp_api_t *api = NULL;
- if (handler->use_xdp) {
+ if (is_xdp_thread(&handler->server->ifaces[0], handler->thread_id[thr_id])) {
#ifndef ENABLE_XDP
assert(0);
#else
size_t nifs = handler->server->n_ifaces;
void *socket_ctxs[nifs]; // only for XDP: pointers on knot_xsk_socket
unsigned nfds = udp_set_ifaces(handler->server->ifaces, handler->server->n_ifaces, &fds,
- udp.thread_id, handler->use_xdp, socket_ctxs);
+ udp.thread_id, socket_ctxs);
if (nfds == 0) {
goto finish;
}
"server.tcp-max-clients\n"
"server.tcp-reuseport\n"
"server.udp-workers\n"
- "server.xdp-workers\n"
"server.tcp-workers\n"
"server.background-workers\n"
"server.udp-max-payload\n"
{ C_TCP_MAX_CLIENTS, YP_TINT, YP_VNONE },
{ C_TCP_REUSEPORT, YP_TBOOL, YP_VNONE },
{ C_UDP_WORKERS, YP_TINT, YP_VNONE },
- { C_XDP_WORKERS, YP_TINT, YP_VNONE },
{ C_TCP_WORKERS, YP_TINT, YP_VNONE },
{ C_BG_WORKERS, YP_TINT, YP_VNONE },
{ C_UDP_MAX_PAYLOAD, YP_TINT, YP_VNONE },