Commit 560ea8e4 authored by Quanah Gibson-Mount's avatar Quanah Gibson-Mount
Browse files

ITS#6234

parent 8032ac7e
......@@ -6,6 +6,7 @@ OpenLDAP 2.4.18 Engineering
Fixed libldap error parsing (ITS#6197)
Fixed libldap native getpass usage (ITS#4643)
Fixed libldap tls_check_hostname for OpenSSL and MozNSS (ITS#6239)
Added slapd tcp buffers support (ITS#6234)
Fixed slapd allow mirrormode to be set to FALSE (ITS#5946)
Fixed slapd certificate list parsing (ITS#6241)
Fixed slapd dncachesize behavior to unlimited by default (ITS#6222)
......
......@@ -747,6 +747,16 @@ The default is 262143.
Specify the maximum incoming LDAP PDU size for authenticated sessions.
The default is 4194303.
.TP
.B olcTCPBuffer [listener=<URL>] [{read|write}=]<size>
Specify the size of the TCP buffer.
A global value for both read and write TCP buffers related to any listener
is defined, unless the listener is explicitly specified,
or either the read or write qualifiers are used.
See
.BR tcp (7)
for details.
Note that some OS-es implement automatic TCP buffer tuning.
.TP
.B olcThreads: <integer>
Specify the maximum size of the primary thread pool.
The default is 16; the minimum value is 2.
......
......@@ -961,6 +961,16 @@ more efficiently. The resulting sort order depends on the
attributes' syntax and matching rules and may not correspond to
lexical order or any other recognizable order.
.TP
.B tcp-buffer [listener=<URL>] [{read|write}=]<size>
Specify the size of the TCP buffer.
A global value for both read and write TCP buffers related to any listener
is defined, unless the listener is explicitly specified,
or either the read or write qualifiers are used.
See
.BR tcp (7)
for details.
Note that some OS-es implement automatic TCP buffer tuning.
.TP
.B threads <integer>
Specify the maximum size of the primary thread pool.
The default is 16; the minimum value is 2.
......
......@@ -120,6 +120,9 @@ static ConfigDriver config_timelimit;
static ConfigDriver config_overlay;
static ConfigDriver config_subordinate;
static ConfigDriver config_suffix;
#ifdef LDAP_TCP_BUFFER
static ConfigDriver config_tcp_buffer;
#endif /* LDAP_TCP_BUFFER */
static ConfigDriver config_rootdn;
static ConfigDriver config_rootpw;
static ConfigDriver config_restrict;
......@@ -604,6 +607,15 @@ static ConfigTable config_back_cf_table[] = {
&syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
{ "tcp-buffer", "[listener=<listener>] [{read|write}=]size", 0, 0, 0,
#ifndef LDAP_TCP_BUFFER
ARG_IGNORED, NULL,
#else /* LDAP_TCP_BUFFER */
ARG_MAGIC, &config_tcp_buffer,
#endif /* LDAP_TCP_BUFFER */
"( OLcfgGlAt:90 NAME 'olcTCPBuffer' "
"DESC 'Custom TCP buffer size' "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "threads", "count", 2, 2, 0,
#ifdef NO_THREADS
ARG_IGNORED, NULL,
......@@ -772,6 +784,7 @@ static ConfigOCs cf_ocs[] = {
"olcSaslAuxprops $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
"olcSecurity $ olcServerID $ olcSizeLimit $ "
"olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ "
"olcTCPBuffer $ "
"olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
"olcTLSCACertificatePath $ olcTLSCertificateFile $ "
"olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
......@@ -2331,6 +2344,337 @@ config_subordinate(ConfigArgs *c)
return rc;
}
/*
* [listener=<listener>] [{read|write}=]<size>
*/
#ifdef LDAP_TCP_BUFFER
static BerVarray tcp_buffer;
int tcp_buffer_num;
#define SLAP_TCP_RMEM (0x1U)
#define SLAP_TCP_WMEM (0x2U)
static int
tcp_buffer_parse( struct berval *val, int argc, char **argv,
int *size, int *rw, Listener **l )
{
int i, rc = LDAP_SUCCESS;
LDAPURLDesc *lud = NULL;
char *ptr;
if ( val != NULL && argv == NULL ) {
char *s = val->bv_val;
argv = ldap_str2charray( s, " \t" );
if ( argv == NULL ) {
return LDAP_OTHER;
}
}
i = 0;
if ( strncasecmp( argv[ i ], "listener=", STRLENOF( "listener=" ) )
== 0 )
{
char *url = argv[ i ] + STRLENOF( "listener=" );
if ( ldap_url_parse( url, &lud ) ) {
rc = LDAP_INVALID_SYNTAX;
goto done;
}
*l = config_check_my_url( url, lud );
if ( *l == NULL ) {
rc = LDAP_NO_SUCH_ATTRIBUTE;
goto done;
}
i++;
}
ptr = argv[ i ];
if ( strncasecmp( ptr, "read=", STRLENOF( "read=" ) ) == 0 ) {
*rw |= SLAP_TCP_RMEM;
ptr += STRLENOF( "read=" );
} else if ( strncasecmp( ptr, "write=", STRLENOF( "write=" ) ) == 0 ) {
*rw |= SLAP_TCP_WMEM;
ptr += STRLENOF( "write=" );
} else {
*rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM );
}
/* accept any base */
if ( lutil_atoix( size, ptr, 0 ) ) {
rc = LDAP_INVALID_SYNTAX;
goto done;
}
done:;
if ( val != NULL && argv != NULL ) {
ldap_charray_free( argv );
}
if ( lud != NULL ) {
ldap_free_urldesc( lud );
}
return rc;
}
static int
tcp_buffer_delete_one( struct berval *val )
{
int rc = 0;
int size = -1, rw = 0;
Listener *l = NULL;
rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l );
if ( rc != 0 ) {
return rc;
}
if ( l != NULL ) {
int i;
Listener **ll = slapd_get_listeners();
for ( i = 0; ll[ i ] != NULL; i++ ) {
if ( ll[ i ] == l ) break;
}
if ( ll[ i ] == NULL ) {
return LDAP_NO_SUCH_ATTRIBUTE;
}
if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1;
if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1;
for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = -1;
if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = -1;
}
} else {
/* NOTE: this affects listeners without a specific setting,
* does not reset all listeners. If a listener without
* specific settings was assigned a buffer because of
* a global setting, it will not be reset. In any case,
* buffer changes will only take place at restart. */
if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1;
if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1;
}
return rc;
}
static int
tcp_buffer_delete( BerVarray vals )
{
int i;
for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
tcp_buffer_delete_one( &vals[ i ] );
}
return 0;
}
static int
tcp_buffer_unparse( int idx, int size, int rw, Listener *l, struct berval *val )
{
char buf[sizeof("2147483648")], *ptr;
/* unparse for later use */
val->bv_len = snprintf( buf, sizeof( buf ), "%d", size );
if ( l != NULL ) {
val->bv_len += STRLENOF( "listener=" " " ) + l->sl_url.bv_len;
}
if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
if ( rw & SLAP_TCP_RMEM ) {
val->bv_len += STRLENOF( "read=" );
} else if ( rw & SLAP_TCP_WMEM ) {
val->bv_len += STRLENOF( "write=" );
}
}
val->bv_val = SLAP_MALLOC( val->bv_len + 1 );
ptr = val->bv_val;
if ( l != NULL ) {
ptr = lutil_strcopy( ptr, "listener=" );
ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len );
*ptr++ = ' ';
}
if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
if ( rw & SLAP_TCP_RMEM ) {
ptr = lutil_strcopy( ptr, "read=" );
} else if ( rw & SLAP_TCP_WMEM ) {
ptr = lutil_strcopy( ptr, "write=" );
}
}
ptr = lutil_strcopy( ptr, buf );
*ptr = '\0';
assert( val->bv_val + val->bv_len == ptr );
return LDAP_SUCCESS;
}
static int
tcp_buffer_add_one( int argc, char **argv, int idx )
{
int rc = 0;
int size = -1, rw = 0;
Listener *l = NULL;
struct berval val;
/* parse */
rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l );
if ( rc != 0 ) {
return rc;
}
/* unparse for later use */
rc = tcp_buffer_unparse( idx, size, rw, l, &val );
if ( rc != LDAP_SUCCESS ) {
return rc;
}
/* use parsed values */
if ( l != NULL ) {
int i;
Listener **ll = slapd_get_listeners();
for ( i = 0; ll[ i ] != NULL; i++ ) {
if ( ll[ i ] == l ) break;
}
if ( ll[ i ] == NULL ) {
return LDAP_NO_SUCH_ATTRIBUTE;
}
/* buffer only applies to TCP listeners;
* we do not do any check here, and delegate them
* to setsockopt(2) */
if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size;
if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size;
for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = size;
if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = size;
}
} else {
/* NOTE: this affects listeners without a specific setting,
* does not set all listeners */
if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size;
if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size;
}
tcp_buffer = SLAP_REALLOC( tcp_buffer, sizeof( struct berval ) * ( tcp_buffer_num + 2 ) );
/* append */
idx = tcp_buffer_num;
tcp_buffer[ idx ] = val;
tcp_buffer_num++;
BER_BVZERO( &tcp_buffer[ tcp_buffer_num ] );
return rc;
}
static int
config_tcp_buffer( ConfigArgs *c )
{
if ( c->op == SLAP_CONFIG_EMIT ) {
if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[ 0 ] ) ) {
return 1;
}
value_add( &c->rvalue_vals, tcp_buffer );
value_add( &c->rvalue_nvals, tcp_buffer );
} else if ( c->op == LDAP_MOD_DELETE ) {
if ( !c->line ) {
tcp_buffer_delete( tcp_buffer );
ber_bvarray_free( tcp_buffer );
tcp_buffer = NULL;
tcp_buffer_num = 0;
} else {
int rc = 0;
int size = -1, rw = 0;
Listener *l = NULL;
struct berval val = BER_BVNULL;
int i;
if ( tcp_buffer_num == 0 ) {
return 1;
}
/* parse */
rc = tcp_buffer_parse( NULL, c->argc - 1, &c->argv[ 1 ], &size, &rw, &l );
if ( rc != 0 ) {
return 1;
}
/* unparse for later use */
rc = tcp_buffer_unparse( tcp_buffer_num, size, rw, l, &val );
if ( rc != LDAP_SUCCESS ) {
return 1;
}
for ( i = 0; !BER_BVISNULL( &tcp_buffer[ i ] ); i++ ) {
if ( bvmatch( &tcp_buffer[ i ], &val ) ) {
break;
}
}
if ( BER_BVISNULL( &tcp_buffer[ i ] ) ) {
/* not found */
rc = 1;
goto done;
}
tcp_buffer_delete_one( &tcp_buffer[ i ] );
ber_memfree( tcp_buffer[ i ].bv_val );
for ( ; i < tcp_buffer_num; i++ ) {
tcp_buffer[ i ] = tcp_buffer[ i + 1 ];
}
tcp_buffer_num--;
done:;
if ( !BER_BVISNULL( &val ) ) {
SLAP_FREE( val.bv_val );
}
}
} else {
int rc;
int idx;
rc = tcp_buffer_add_one( c->argc - 1, &c->argv[ 1 ], idx );
if ( rc ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"<%s> unable to add value #%d",
c->argv[0], idx );
Debug( LDAP_DEBUG_ANY, "%s: %s\n",
c->log, c->cr_msg, 0 );
return 1;
}
}
return 0;
}
#endif /* LDAP_TCP_BUFFER */
static int
config_suffix(ConfigArgs *c)
{
......@@ -3087,7 +3431,7 @@ config_updatedn(ConfigArgs *c) {
}
int
config_shadow( ConfigArgs *c, int flag )
config_shadow( ConfigArgs *c, slap_mask_t flag )
{
char *notallowed = NULL;
......@@ -3106,7 +3450,8 @@ config_shadow( ConfigArgs *c, int flag )
if ( SLAP_SHADOW(c->be) ) {
/* if already shadow, only check consistency */
if ( ( SLAP_DBFLAGS(c->be) & flag ) != flag ) {
Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%x.\n", c->log, flag, 0 );
Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%lx.\n",
c->log, flag, 0 );
return 1;
}
......
......@@ -197,7 +197,7 @@ Entry * config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
ConfigArgs *c, struct berval *rdn, ConfigOCs *main, ConfigOCs *extra );
Listener *config_check_my_url(const char *url, LDAPURLDesc *lud);
int config_shadow( ConfigArgs *c, int flag );
int config_shadow( ConfigArgs *c, slap_mask_t flag );
#define config_slurp_shadow(c) config_shadow((c), SLAP_DBFLAG_SLURP_SHADOW)
#define config_sync_shadow(c) config_shadow((c), SLAP_DBFLAG_SYNC_SHADOW)
......
......@@ -73,6 +73,11 @@ ber_socket_t dtblsize;
slap_ssf_t local_ssf = LDAP_PVT_SASL_LOCAL_SSF;
struct runqueue_s slapd_rq;
#ifdef LDAP_TCP_BUFFER
int slapd_tcp_rmem;
int slapd_tcp_wmem;
#endif /* LDAP_TCP_BUFFER */
Listener **slap_listeners = NULL;
#ifndef SLAPD_LISTEN_BACKLOG
......@@ -1315,6 +1320,11 @@ slap_open_listener(
}
#endif /* HAVE_TLS */
#ifdef LDAP_TCP_BUFFER
l.sl_tcp_rmem = 0;
l.sl_tcp_wmem = 0;
#endif /* LDAP_TCP_BUFFER */
port = (unsigned short) lud->lud_port;
tmp = ldap_pvt_url_scheme2proto(lud->lud_scheme);
......@@ -2081,6 +2091,131 @@ slapd_daemon_task(
continue;
#endif /* LDAP_CONNECTIONLESS */
/* FIXME: TCP-only! */
#ifdef LDAP_TCP_BUFFER
if ( 1 ) {
int origsize, size, realsize, rc;
socklen_t optlen;
char buf[ SLAP_TEXT_BUFLEN ];
size = 0;
if ( slap_listeners[l]->sl_tcp_rmem > 0 ) {
size = slap_listeners[l]->sl_tcp_rmem;
} else if ( slapd_tcp_rmem > 0 ) {
size = slapd_tcp_rmem;
}
if ( size > 0 ) {
optlen = sizeof( origsize );
rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
SOL_SOCKET,
SO_RCVBUF,
(void *)&origsize,
&optlen );
if ( rc ) {
int err = sock_errno();
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: getsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
err, sock_errstr(err), 0 );
}
optlen = sizeof( size );
rc = setsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
SOL_SOCKET,
SO_RCVBUF,
(const void *)&size,
optlen );
if ( rc ) {
int err = sock_errno();
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: setsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
err, sock_errstr(err), 0 );
}
optlen = sizeof( realsize );
rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
SOL_SOCKET,
SO_RCVBUF,
(void *)&realsize,
&optlen );
if ( rc ) {
int err = sock_errno();
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: getsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
err, sock_errstr(err), 0 );
}
snprintf( buf, sizeof( buf ),
"url=%s (#%d) RCVBUF original size=%d requested size=%d real size=%d",
slap_listeners[l]->sl_url.bv_val, l, origsize, size, realsize );
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: %s\n",
buf, 0, 0 );
}
size = 0;
if ( slap_listeners[l]->sl_tcp_wmem > 0 ) {
size = slap_listeners[l]->sl_tcp_wmem;
} else if ( slapd_tcp_wmem > 0 ) {
size = slapd_tcp_wmem;
}
if ( size > 0 ) {
optlen = sizeof( origsize );
rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
SOL_SOCKET,
SO_SNDBUF,
(void *)&origsize,
&optlen );
if ( rc ) {
int err = sock_errno();
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: getsockopt(SO_SNDBUF) failed errno=%d (%s)\n",
err, sock_errstr(err), 0 );
}
optlen = sizeof( size );
rc = setsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
SOL_SOCKET,
SO_SNDBUF,
(const void *)&size,
optlen );
if ( rc ) {
int err = sock_errno();
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: setsockopt(SO_SNDBUF) failed errno=%d (%s)",
err, sock_errstr(err), 0 );
}
optlen = sizeof( realsize );
rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
SOL_SOCKET,
SO_SNDBUF,
(void *)&realsize,
&optlen );
if ( rc ) {
int err = sock_errno();
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: getsockopt(SO_SNDBUF) failed errno=%d (%s)\n",
err, sock_errstr(err), 0 );
}
snprintf( buf, sizeof( buf ),
"url=%s (#%d) SNDBUF original size=%d requested size=%d real size=%d",
slap_listeners[l]->sl_url.bv_val, l, origsize, size, realsize );
Debug( LDAP_DEBUG_ANY,
"slapd_daemon_task: %s\n",
buf, 0, 0 );
}
}
#endif /* LDAP_TCP_BUFFER */
if ( listen( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ), SLAPD_LISTEN_BACKLOG ) == -1 ) {
int err = sock_errno();
......
......@@ -851,6 +851,10 @@ LDAP_SLAPD_V (int) slapd_register_slp;
LDAP_SLAPD_V (const char *) slapd_slp_attrs;
LDAP_SLAPD_V (slap_ssf_t) local_ssf;
LDAP_SLAPD_V (struct runqueue_s) slapd_rq;
#ifdef LDAP_TCP_BUFFER
LDAP_SLAPD_V (int) slapd_tcp_rmem;
LDAP_SLAPD_V (int) slapd_tcp_wmem;
#endif /* LDAP_TCP_BUFFER */
#ifdef HAVE_WINSOCK
LDAP_SLAPD_F (ber_socket_t) slapd_socknew(ber_socket_t s);
......@@ -1775,7 +1779,7 @@ LDAP_SLAPD_F (Filter *) str2filter_x LDAP_P(( Operation *op, const char *str ));
LDAP_SLAPD_F (int) syncrepl_add_glue LDAP_P((
Operation*, Entry* ));
LDAP_SLAPD_F (void) syncrepl_diff_entry LDAP_P((