Blob Blame History Raw
From bd201746f8cf0e95615b3e98868555451b5e66b8 Mon Sep 17 00:00:00 2001
From: Tomas Halman <thalman@redhat.com>
Date: Mon, 2 Dec 2019 11:11:52 +0100
Subject: [PATCH] sdap: Add randomness to ldap connection timeout

In case of mass deployment, mass registration of IPA clients roughly on
the same time leads to regular CPU load spikes on IPA servers, the load
spikes are caused by all/most clients refreshing their LDAP connections
(ldap_connection_expire_timeout) every 15 minutes.

This patch introduces new random value (from 0 up to
ldap_connection_expire_offset) that is added to the timeout.

Resolves:
https://pagure.io/SSSD/sssd/issue/3630

Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
---
 src/config/cfg_rules.ini                   |  1 +
 src/config/etc/sssd.api.d/sssd-ad.conf     |  1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf    |  1 +
 src/config/etc/sssd.api.d/sssd-ldap.conf   |  1 +
 src/man/sssd-ldap.5.xml                    | 19 +++++++++++++++++++
 src/providers/ad/ad_opts.c                 |  1 +
 src/providers/ipa/ipa_opts.c               |  1 +
 src/providers/ldap/ldap_opts.c             |  1 +
 src/providers/ldap/sdap.h                  |  1 +
 src/providers/ldap/sdap_async_connection.c | 12 ++++++++++++
 10 files changed, 39 insertions(+)

diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 8c73c89ac..c56d5a668 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -600,6 +600,7 @@ option = ldap_chpass_dns_service_name
 option = ldap_chpass_update_last_change
 option = ldap_chpass_uri
 option = ldap_connection_expire_timeout
+option = ldap_connection_expire_offset
 option = ldap_default_authtok
 option = ldap_default_authtok_type
 option = ldap_default_bind_dn
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index 80e329b3b..aaa0b2345 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -58,6 +58,7 @@ ldap_deref = str, None, false
 ldap_page_size = int, None, false
 ldap_deref_threshold = int, None, false
 ldap_connection_expire_timeout = int, None, false
+ldap_connection_expire_offset = int, None, false
 ldap_disable_paging = bool, None, false
 krb5_confd_path = str, None, false
 wildcard_limit = int, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index e2d46db75..7ed153d36 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -52,6 +52,7 @@ ldap_deref = str, None, false
 ldap_page_size = int, None, false
 ldap_deref_threshold = int, None, false
 ldap_connection_expire_timeout = int, None, false
+ldap_connection_expire_offset = int, None, false
 ldap_disable_paging = bool, None, false
 krb5_confd_path = str, None, false
 wildcard_limit = int, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index 01c1d7f12..4f73e901e 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -36,6 +36,7 @@ ldap_deref_threshold = int, None, false
 ldap_sasl_canonicalize = bool, None, false
 ldap_sasl_minssf = int, None, false
 ldap_connection_expire_timeout = int, None, false
+ldap_connection_expire_offset = int, None, false
 ldap_disable_paging = bool, None, false
 ldap_disable_range_retrieval = bool, None, false
 wildcard_limit = int, None, false
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 6d1ae23ec..f8bb973c7 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -509,12 +509,31 @@
                             the two values (this value vs. the TGT lifetime)
                             will be used.
                         </para>
+                        <para>
+                            This timeout can be extended of a random
+                            value specified by
+                            <emphasis>ldap_connection_expire_offset</emphasis>
+                        </para>
                         <para>
                             Default: 900 (15 minutes)
                         </para>
                     </listitem>
                 </varlistentry>
 
+                <varlistentry>
+                    <term>ldap_connection_expire_offset (integer)</term>
+                    <listitem>
+                        <para>
+                            Random offset between 0 and configured value
+                            is added to
+                            <emphasis>ldap_connection_expire_timeout</emphasis>.
+                        </para>
+                        <para>
+                            Default: 0
+                        </para>
+                    </listitem>
+                </varlistentry>
+
                 <varlistentry>
                     <term>ldap_page_size (integer)</term>
                     <listitem>
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index cd568e466..1293219ee 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -137,6 +137,7 @@ struct dp_option ad_def_ldap_opts[] = {
     { "ldap_deref_threshold", DP_OPT_NUMBER, { .number = 10 }, NULL_NUMBER },
     { "ldap_sasl_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_connection_expire_timeout", DP_OPT_NUMBER, { .number = 900 }, NULL_NUMBER },
+    { "ldap_connection_expire_offset", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },
     { "ldap_disable_paging", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_idmap_range_min", DP_OPT_NUMBER, { .number = 200000 }, NULL_NUMBER },
     { "ldap_idmap_range_max", DP_OPT_NUMBER, { .number = 2000200000LL }, NULL_NUMBER },
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index 7974cb8ea..4fafa073d 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -147,6 +147,7 @@ struct dp_option ipa_def_ldap_opts[] = {
     { "ldap_deref_threshold", DP_OPT_NUMBER, { .number = 10 }, NULL_NUMBER },
     { "ldap_sasl_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_connection_expire_timeout", DP_OPT_NUMBER, { .number = 900 }, NULL_NUMBER },
+    { "ldap_connection_expire_offset", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },
     { "ldap_disable_paging", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_idmap_range_min", DP_OPT_NUMBER, { .number = 200000 }, NULL_NUMBER },
     { "ldap_idmap_range_max", DP_OPT_NUMBER, { .number = 2000200000LL }, NULL_NUMBER },
diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
index a20ec0d86..ffd0c6baa 100644
--- a/src/providers/ldap/ldap_opts.c
+++ b/src/providers/ldap/ldap_opts.c
@@ -107,6 +107,7 @@ struct dp_option default_basic_opts[] = {
     { "ldap_deref_threshold", DP_OPT_NUMBER, { .number = 10 }, NULL_NUMBER },
     { "ldap_sasl_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_connection_expire_timeout", DP_OPT_NUMBER, { .number = 900 }, NULL_NUMBER },
+    { "ldap_connection_expire_offset", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },
     { "ldap_disable_paging", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ldap_idmap_range_min", DP_OPT_NUMBER, { .number = 200000 }, NULL_NUMBER },
     { "ldap_idmap_range_max", DP_OPT_NUMBER, { .number = 2000200000LL }, NULL_NUMBER },
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index d0a19a660..f27b3c480 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -221,6 +221,7 @@ enum sdap_basic_opt {
     SDAP_DEREF_THRESHOLD,
     SDAP_SASL_CANONICALIZE,
     SDAP_EXPIRE_TIMEOUT,
+    SDAP_EXPIRE_OFFSET,
     SDAP_DISABLE_PAGING,
     SDAP_IDMAP_LOWER,
     SDAP_IDMAP_UPPER,
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index 0260cba6f..7438d14a7 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -1803,6 +1803,8 @@ static void sdap_cli_auth_step(struct tevent_req *req)
     struct tevent_req *subreq;
     time_t now;
     int expire_timeout;
+    int expire_offset;
+
     const char *sasl_mech = dp_opt_get_string(state->opts->basic,
                                               SDAP_SASL_MECH);
     const char *user_dn = dp_opt_get_string(state->opts->basic,
@@ -1832,6 +1834,16 @@ static void sdap_cli_auth_step(struct tevent_req *req)
      */
     now = time(NULL);
     expire_timeout = dp_opt_get_int(state->opts->basic, SDAP_EXPIRE_TIMEOUT);
+    expire_offset = dp_opt_get_int(state->opts->basic, SDAP_EXPIRE_OFFSET);
+    if (expire_offset > 0) {
+        expire_timeout += sss_rand() % (expire_offset + 1);
+    } else if (expire_offset < 0) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "Negative value [%d] of ldap_connection_expire_offset "
+              "is not allowed.\n",
+              expire_offset);
+    }
+
     DEBUG(SSSDBG_CONF_SETTINGS, "expire timeout is %d\n", expire_timeout);
     if (!state->sh->expire_time
             || (state->sh->expire_time > (now + expire_timeout))) {
-- 
2.20.1