diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index 856a038726..21e19e0dce 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -258,7 +258,8 @@ daemonConfigNew(bool privileged ATTRIBUTE_UNUSED) data->min_workers = 5; data->max_workers = 20; - data->max_clients = 20; + data->max_clients = 5000; + data->max_anonymous_clients = 20; data->prio_workers = 5; @@ -415,6 +416,7 @@ daemonConfigLoadOptions(struct daemonConfig *data, GET_CONF_INT(conf, filename, max_workers); GET_CONF_INT(conf, filename, max_clients); GET_CONF_INT(conf, filename, max_queued_clients); + GET_CONF_INT(conf, filename, max_anonymous_clients); GET_CONF_INT(conf, filename, prio_workers); diff --git a/daemon/libvirtd-config.h b/daemon/libvirtd-config.h index 0829273db4..8d3d085ae2 100644 --- a/daemon/libvirtd-config.h +++ b/daemon/libvirtd-config.h @@ -64,6 +64,7 @@ struct daemonConfig { int max_workers; int max_clients; int max_queued_clients; + int max_anonymous_clients; int prio_workers; diff --git a/daemon/libvirtd.aug b/daemon/libvirtd.aug index 70fce5c089..5a0807c368 100644 --- a/daemon/libvirtd.aug +++ b/daemon/libvirtd.aug @@ -57,6 +57,7 @@ module Libvirtd = | int_entry "max_workers" | int_entry "max_clients" | int_entry "max_queued_clients" + | int_entry "max_anonymous_clients" | int_entry "max_requests" | int_entry "max_client_requests" | int_entry "prio_workers" diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 27c4fff679..83d45c69fd 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1383,6 +1383,7 @@ int main(int argc, char **argv) { config->max_workers, config->prio_workers, config->max_clients, + config->max_anonymous_clients, config->keepalive_interval, config->keepalive_count, !!config->keepalive_required, diff --git a/daemon/libvirtd.conf b/daemon/libvirtd.conf index 073c1784fa..64c215d6c3 100644 --- a/daemon/libvirtd.conf +++ b/daemon/libvirtd.conf @@ -255,7 +255,7 @@ # The maximum number of concurrent client connections to allow # over all sockets combined. -#max_clients = 20 +#max_clients = 5000 # The maximum length of queue of connections waiting to be # accepted by the daemon. Note, that some protocols supporting @@ -263,6 +263,10 @@ # connection succeeds. #max_queued_clients = 1000 +# The maximum length of queue of accepted but not yet not +# authenticated clients. The default value is zero, meaning +# the feature is disabled. +#max_anonymous_clients = 20 # The minimum limit sets the number of workers to start up # initially. If the number of active clients exceeds this, diff --git a/daemon/test_libvirtd.aug.in b/daemon/test_libvirtd.aug.in index a7e8515c6e..37ff33d603 100644 --- a/daemon/test_libvirtd.aug.in +++ b/daemon/test_libvirtd.aug.in @@ -34,8 +34,9 @@ module Test_libvirtd = { "1" = "joe@EXAMPLE.COM" } { "2" = "fred@EXAMPLE.COM" } } - { "max_clients" = "20" } + { "max_clients" = "5000" } { "max_queued_clients" = "1000" } + { "max_anonymous_clients" = "20" } { "min_workers" = "5" } { "max_workers" = "20" } { "prio_workers" = "5" } diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index 7dc4292a92..89fa93963c 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -145,7 +145,7 @@ virLockDaemonNew(virLockDaemonConfigPtr config, bool privileged) } if (!(lockd->srv = virNetServerNew(1, 1, 0, config->max_clients, - -1, 0, + config->max_clients, -1, 0, false, NULL, virLockDaemonClientNew, virLockDaemonClientPreExecRestart, diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 5ca960f13e..ab140f1dd3 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -737,7 +737,7 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl) return -1; if (!(ctrl->server = virNetServerNew(0, 0, 0, 1, - -1, 0, false, + 0, -1, 0, false, NULL, virLXCControllerClientPrivateNew, NULL, diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 683b06379a..dfa3565924 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -92,6 +92,7 @@ struct _virNetServer { virNetServerClientPtr *clients; /* Clients */ size_t nclients_max; /* Max allowed clients count */ size_t nclients_unauth; /* Unauthenticated clients count */ + size_t nclients_unauth_max; /* Max allowed unauth clients count */ int keepaliveInterval; unsigned int keepaliveCount; @@ -279,6 +280,14 @@ static int virNetServerAddClient(virNetServerPtr srv, if (virNetServerClientNeedAuth(client)) virNetServerTrackPendingAuthLocked(srv); + if (srv->nclients_unauth_max && + srv->nclients_unauth == srv->nclients_unauth_max) { + /* Temporarily stop accepting new clients */ + VIR_DEBUG("Temporarily suspending services " + "due to max_anonymous_clients"); + virNetServerUpdateServicesLocked(srv, false); + } + if (srv->nclients == srv->nclients_max) { /* Temporarily stop accepting new clients */ VIR_DEBUG("Temporarily suspending services due to max_clients"); @@ -362,6 +371,7 @@ virNetServerPtr virNetServerNew(size_t min_workers, size_t max_workers, size_t priority_workers, size_t max_clients, + size_t max_anonymous_clients, int keepaliveInterval, unsigned int keepaliveCount, bool keepaliveRequired, @@ -388,6 +398,7 @@ virNetServerPtr virNetServerNew(size_t min_workers, goto error; srv->nclients_max = max_clients; + srv->nclients_unauth_max = max_anonymous_clients; srv->keepaliveInterval = keepaliveInterval; srv->keepaliveCount = keepaliveCount; srv->keepaliveRequired = keepaliveRequired; @@ -457,6 +468,7 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, unsigned int max_workers; unsigned int priority_workers; unsigned int max_clients; + unsigned int max_anonymous_clients; unsigned int keepaliveInterval; unsigned int keepaliveCount; bool keepaliveRequired; @@ -482,6 +494,13 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, _("Missing max_clients data in JSON document")); goto error; } + if (virJSONValueObjectHasKey(object, "max_anonymous_clients") && + virJSONValueObjectGetNumberUint(object, "max_anonymous_clients", + &max_anonymous_clients) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed max_anonymous_clients data in JSON document")); + goto error; + } if (virJSONValueObjectGetNumberUint(object, "keepaliveInterval", &keepaliveInterval) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing keepaliveInterval data in JSON document")); @@ -507,6 +526,7 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, if (!(srv = virNetServerNew(min_workers, max_clients, priority_workers, max_clients, + max_anonymous_clients, keepaliveInterval, keepaliveCount, keepaliveRequired, mdnsGroupName, clientPrivNew, clientPrivPreExecRestart, @@ -625,6 +645,12 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv) _("Cannot set max_clients data in JSON document")); goto error; } + if (virJSONValueObjectAppendNumberUint(object, "max_anonymous_clients", + srv->nclients_unauth_max) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set max_anonymous_clients data in JSON document")); + goto error; + } if (virJSONValueObjectAppendNumberUint(object, "keepaliveInterval", srv->keepaliveInterval) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot set keepaliveInterval data in JSON document")); @@ -1068,6 +1094,34 @@ void virNetServerUpdateServices(virNetServerPtr srv, virObjectUnlock(srv); } +/** + * virNetServerCheckLimits: + * @srv: server to check limits on + * + * Check if limits like max_clients or max_anonymous_clients + * are satisfied and if so, re-enable accepting new clients. + * The @srv must be locked when this function is called. + */ +static void +virNetServerCheckLimits(virNetServerPtr srv) +{ + /* Enable services if we can accept a new client. + * The new client can be accepted if both max_clients and + * max_anonymous_clients wouldn't get overcommitted by + * accepting it. */ + VIR_DEBUG("Considering re-enabling services: " + "nclients=%zu nclients_max=%zu " + "nclients_unauth=%zu nclients_unauth_max=%zu", + srv->nclients, srv->nclients_max, + srv->nclients_unauth, srv->nclients_unauth_max); + if (srv->nclients < srv->nclients_max && + (!srv->nclients_unauth_max || + srv->nclients_unauth < srv->nclients_unauth_max)) { + /* Now it makes sense to accept() a new client. */ + VIR_DEBUG("Re-enabling services"); + virNetServerUpdateServicesLocked(srv, true); + } +} void virNetServerRun(virNetServerPtr srv) { @@ -1142,13 +1196,7 @@ void virNetServerRun(virNetServerPtr srv) if (virNetServerClientNeedAuth(client)) virNetServerTrackCompletedAuthLocked(srv); - /* Enable services if we can accept a new client. - * The new client can be accepted if we are at the limit. */ - if (srv->nclients == srv->nclients_max - 1) { - /* Now it makes sense to accept() a new client. */ - VIR_DEBUG("Re-enabling services"); - virNetServerUpdateServicesLocked(srv, true); - } + virNetServerCheckLimits(srv); virObjectUnlock(srv); virObjectUnref(client); @@ -1265,6 +1313,7 @@ size_t virNetServerTrackCompletedAuth(virNetServerPtr srv) size_t ret; virObjectLock(srv); ret = virNetServerTrackCompletedAuthLocked(srv); + virNetServerCheckLimits(srv); virObjectUnlock(srv); return ret; } diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index b56540cfed..8c5ae072db 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -39,6 +39,7 @@ virNetServerPtr virNetServerNew(size_t min_workers, size_t max_workers, size_t priority_workers, size_t max_clients, + size_t max_anonymous_clients, int keepaliveInterval, unsigned int keepaliveCount, bool keepaliveRequired,