]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
xdp: listen on configured ifaces with workers=RXqueues
authorLibor Peltan <libor.peltan@nic.cz>
Wed, 29 Jan 2020 09:58:12 +0000 (10:58 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Tue, 21 Apr 2020 16:43:10 +0000 (18:43 +0200)
16 files changed:
doc/man/knot.conf.5in
doc/operation.rst
doc/reference.rst
src/knot/conf/base.c
src/knot/conf/conf.c
src/knot/conf/conf.h
src/knot/conf/schema.c
src/knot/conf/schema.h
src/knot/conf/tools.c
src/knot/ctl/commands.c
src/knot/nameserver/query_module.c
src/knot/server/server.c
src/knot/server/server.h
src/knot/server/tcp-handler.c
src/knot/server/udp-handler.c
tests/knot/test_confio.c

index c9641839b7a08ab3f19d021f44a0b237f319f14d..dfabb5b3bdf8810ada35e5e2aa39d75f8e2fa242 100644 (file)
@@ -196,6 +196,7 @@ server:
     edns\-client\-subnet: BOOL
     answer\-rotation: BOOL
     listen: ADDR[@INT] ...
+    listen\-xdp: STR ...
 .ft P
 .fi
 .UNINDENT
@@ -268,21 +269,6 @@ over TCP.
 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
@@ -399,6 +385,23 @@ automatically enabled if supported by the operating system.
 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.
index c5d4bbb0cb6ccb7ae9c9bba227fc6c015698f0dc..9018aabc366b8dde1f5e0cb86198dca84a32eff3 100644 (file)
@@ -968,9 +968,6 @@ Start knotd as root (it may drop to unpriv user after init).
 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
index 7bc144653187df180f7a504aa33c49fa0e227643..e5ca159b6fe112ac42b8eda60aa1b63577d529f1 100644 (file)
@@ -147,6 +147,7 @@ General options related to the server.
      edns-client-subnet: BOOL
      answer-rotation: BOOL
      listen: ADDR[@INT] ...
+     listen-xdp: STR ...
 
 .. CAUTION::
    When you change configuration parameters dynamically or via configuration file
@@ -244,25 +245,6 @@ Change of this parameter requires restart of the Knot server to take effect.
 
 *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
@@ -423,6 +405,27 @@ Change of this parameter requires restart of the Knot server to take effect.
 
 *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
index 01cc1bfdaff471ec9213943884a7de8bdeba1fc3..d724e68d21e4a3192bbf5c59719a78649f1e0c35 100644 (file)
@@ -124,14 +124,12 @@ static void init_cache(
        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);
 
@@ -184,8 +182,6 @@ static void init_cache(
 
        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;
index dbd786e18bf5cb9205611ad5ea767d5947107ae5..1f289529cf90b5cb8db5aa6eb128ea49eacd92e7 100644 (file)
@@ -1114,19 +1114,6 @@ size_t conf_udp_threads_txn(
        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)
index 36adb67985876cc07df84d7d1cbc9cc80821d2ad..a44e879684122521e883873004a0d3f24dd7f86c 100644 (file)
@@ -677,24 +677,6 @@ static inline size_t conf_udp_threads(
        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.
  *
index 2d3acb9fca0ad0ca0970b7153db8396bfed24ac0..03bc54653a49db22bd283b0cf0dc96123134874f 100644 (file)
@@ -155,7 +155,6 @@ static const yp_item_t desc_server[] = {
        { 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 },
index 616ba2381dc663ecdd52a142e3148b974ea03be9..0ddd7be4effc1caaf9ad1d642cc02dbf9ec84cb3 100644 (file)
 #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"
index 276987c94e9f68c8e5a0eb6a8549d8f9c786fbf9..833ccc99596889ae7fcfaf32d54b11e66096e5ad 100644 (file)
@@ -312,13 +312,6 @@ int check_server(
        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;
 }
 
index a20b4b2f473772aab39a1358f22a686e2c2adf63..0ffab8c4c76f38b625f01c3d1b803a4a30a96181 100644 (file)
@@ -1385,10 +1385,8 @@ static int server_status(ctl_args_t *args)
                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);
index b6c3c369ffa03b851088e98e480ff80b1667f959..6768e498a072bec9d753c5d165446ffc1a0c080f 100644 (file)
@@ -345,9 +345,6 @@ knotd_conf_t knotd_conf_env(knotd_mod_t *mod, knotd_conf_env_t env)
        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;
index f52ef04f8733a94908d28516316df0e7501157de..00752562bdedfea0028a7877fb58d7ab822d0aa7 100644 (file)
@@ -240,6 +240,113 @@ static int iface_addr2name(const struct sockaddr_storage *add, char **out)
        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.
  *
@@ -255,7 +362,7 @@ static int iface_addr2name(const struct sockaddr_storage *add, char **out)
  */
 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) {
@@ -272,7 +379,6 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr,
        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;
@@ -284,10 +390,6 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr,
        }
 #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));
 
@@ -344,56 +446,6 @@ static iface_t *server_init_iface(struct sockaddr_storage *addr,
                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;
@@ -458,7 +510,12 @@ static int configure_sockets(conf_t *conf, server_t *s)
        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) {
@@ -466,11 +523,7 @@ static int configure_sockets(conf_t *conf, server_t *s)
                }
        }
 
-       /* 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;
@@ -488,7 +541,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;
-               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);
@@ -496,6 +549,20 @@ static int configure_sockets(conf_t *conf, server_t *s)
 
                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);
@@ -516,6 +583,22 @@ static int configure_sockets(conf_t *conf, server_t *s)
        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) {
@@ -782,7 +865,6 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server)
 
        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;
@@ -797,11 +879,6 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server)
                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;
@@ -907,7 +984,7 @@ void server_stop(server_t *server)
        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);
@@ -916,27 +993,26 @@ static int set_handler(server_t *server, int index, unsigned size, bool use_xdp,
        }
 
        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)
@@ -996,8 +1072,14 @@ void server_reconfigure(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));
                }
index c834261c5c4401728cfc98032c59b2f90db512bf..697c079c46f9ff351de52b2d192c077c76e116e9 100644 (file)
@@ -39,7 +39,6 @@ typedef struct iohandler {
        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.
@@ -59,6 +58,7 @@ typedef struct iface {
        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;
index ef8080b2d55b102136a499c9b6256c696a46ed34..0402bbfaf43398b3a02e432d625f97f68cea2519 100644 (file)
@@ -1,4 +1,4 @@
-/*  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
@@ -133,6 +133,9 @@ static unsigned tcp_set_ifaces(const iface_t *ifaces, size_t n_ifaces, fdset_t *
        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. */
index dcb93eed7aae5d42b94e470a5ee2733aaa31d712..46b31a955d53c16ef5416e1fd8592ac4fccc0d73 100644 (file)
@@ -450,21 +450,36 @@ static udp_api_t xdp_recvmmsg_api = {
 };
 #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;
                }
 
@@ -494,7 +509,7 @@ static int iface_udp_fd(const iface_t *iface, int thread_id, bool use_xdp, void
  * \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));
 
@@ -508,9 +523,9 @@ static unsigned udp_set_ifaces(const iface_t *ifaces, size_t n_ifaces, struct po
        }
 
        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;
@@ -536,8 +551,12 @@ int udp_master(dthread_t *thread)
        /* 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
@@ -570,7 +589,7 @@ int udp_master(dthread_t *thread)
        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;
        }
index aec2ae12f549f8a27eb76dbdfef3573943ad8eda..9eb2b7ee8669866604fe151fc7093aa0b0a730b9 100644 (file)
@@ -909,7 +909,6 @@ static void test_conf_io_list(void)
              "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"
@@ -932,7 +931,6 @@ static const yp_item_t desc_server[] = {
        { 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 },