Home | History | Annotate | Line # | Download | only in lloadd
      1 /*	$NetBSD: monitor.c,v 1.3 2025/09/05 21:16:24 christos Exp $	*/
      2 
      3 /* init.c - initialize various things */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
     19  * All rights reserved.
     20  *
     21  * Redistribution and use in source and binary forms are permitted
     22  * provided that this notice is preserved and that due credit is given
     23  * to the University of Michigan at Ann Arbor. The name of the University
     24  * may not be used to endorse or promote products derived from this
     25  * software without specific prior written permission. This software
     26  * is provided ``as is'' without express or implied warranty.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __RCSID("$NetBSD: monitor.c,v 1.3 2025/09/05 21:16:24 christos Exp $");
     31 
     32 #include "portable.h"
     33 
     34 #include <stdio.h>
     35 
     36 #include <ac/socket.h>
     37 #include <ac/string.h>
     38 #include <ac/time.h>
     39 
     40 #include "lload.h"
     41 #include "lber_pvt.h"
     42 #include "lutil.h"
     43 
     44 #include "ldap_rq.h"
     45 #include "lload-config.h"
     46 #include "../slapd/back-monitor/back-monitor.h"
     47 
     48 #define LLOAD_MONITOR_BALANCER_NAME "Load Balancer"
     49 #define LLOAD_MONITOR_BALANCER_RDN \
     50     SLAPD_MONITOR_AT "=" LLOAD_MONITOR_BALANCER_NAME
     51 #define LLOAD_MONITOR_BALANCER_DN \
     52     LLOAD_MONITOR_BALANCER_RDN "," SLAPD_MONITOR_BACKEND_DN
     53 
     54 #define LLOAD_MONITOR_INCOMING_NAME "Incoming Connections"
     55 #define LLOAD_MONITOR_INCOMING_RDN \
     56     SLAPD_MONITOR_AT "=" LLOAD_MONITOR_INCOMING_NAME
     57 #define LLOAD_MONITOR_INCOMING_DN \
     58     LLOAD_MONITOR_INCOMING_RDN "," LLOAD_MONITOR_BALANCER_DN
     59 
     60 #define LLOAD_MONITOR_OPERATIONS_NAME "Operations"
     61 #define LLOAD_MONITOR_OPERATIONS_RDN \
     62     SLAPD_MONITOR_AT "=" LLOAD_MONITOR_OPERATIONS_NAME
     63 #define LLOAD_MONITOR_OPERATIONS_DN \
     64     LLOAD_MONITOR_OPERATIONS_RDN "," LLOAD_MONITOR_BALANCER_DN
     65 
     66 #define LLOAD_MONITOR_TIERS_NAME "Backend Tiers"
     67 #define LLOAD_MONITOR_TIERS_RDN SLAPD_MONITOR_AT "=" LLOAD_MONITOR_TIERS_NAME
     68 #define LLOAD_MONITOR_TIERS_DN \
     69     LLOAD_MONITOR_TIERS_RDN "," LLOAD_MONITOR_BALANCER_DN
     70 
     71 struct lload_monitor_ops_t {
     72     struct berval rdn;
     73 } lload_monitor_op[] = {
     74     { BER_BVC("cn=Bind") },
     75     { BER_BVC("cn=Other") },
     76 
     77     { BER_BVNULL }
     78 };
     79 
     80 static ObjectClass *oc_olmBalancer;
     81 static ObjectClass *oc_olmBalancerServer;
     82 static ObjectClass *oc_olmBalancerConnection;
     83 static ObjectClass *oc_olmBalancerOperation;
     84 
     85 static ObjectClass *oc_monitorContainer;
     86 static ObjectClass *oc_monitorCounterObject;
     87 
     88 static AttributeDescription *ad_olmServerURI;
     89 static AttributeDescription *ad_olmReceivedOps;
     90 static AttributeDescription *ad_olmForwardedOps;
     91 static AttributeDescription *ad_olmRejectedOps;
     92 static AttributeDescription *ad_olmCompletedOps;
     93 static AttributeDescription *ad_olmFailedOps;
     94 static AttributeDescription *ad_olmConnectionType;
     95 static AttributeDescription *ad_olmConnectionState;
     96 static AttributeDescription *ad_olmPendingOps;
     97 static AttributeDescription *ad_olmPendingConnections;
     98 static AttributeDescription *ad_olmActiveConnections;
     99 static AttributeDescription *ad_olmIncomingConnections;
    100 static AttributeDescription *ad_olmOutgoingConnections;
    101 
    102 monitor_subsys_t *lload_monitor_client_subsys;
    103 
    104 static struct {
    105     char *name;
    106     char *oid;
    107 } s_oid[] = {
    108     { "olmBalancerAttributes", "olmModuleAttributes:1" },
    109     { "olmBalancerObjectClasses", "olmModuleObjectClasses:1" },
    110 
    111     { NULL }
    112 };
    113 
    114 static struct {
    115     char *desc;
    116     AttributeDescription **ad;
    117 } s_at[] = {
    118     { "( olmBalancerAttributes:1 "
    119       "NAME ( 'olmServerURI' ) "
    120       "DESC 'URI of a backend server' "
    121       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
    122       "EQUALITY caseIgnoreMatch "
    123       "NO-USER-MODIFICATION "
    124       "USAGE dSAOperation )",
    125         &ad_olmServerURI },
    126     { "( olmBalancerAttributes:2 "
    127       "NAME ( 'olmReceivedOps' ) "
    128       "DESC 'monitor received operations' "
    129       "SUP monitorCounter "
    130       "NO-USER-MODIFICATION "
    131       "USAGE dSAOperation )",
    132         &ad_olmReceivedOps },
    133     { "( olmBalancerAttributes:3 "
    134       "NAME ( 'olmForwardedOps' ) "
    135       "DESC 'monitor forwarded operations' "
    136       "SUP monitorCounter "
    137       "NO-USER-MODIFICATION "
    138       "USAGE dSAOperation )",
    139         &ad_olmForwardedOps },
    140     { "( olmBalancerAttributes:4 "
    141       "NAME ( 'olmRejectedOps' ) "
    142       "DESC 'monitor rejected operations' "
    143       "SUP monitorCounter "
    144       "NO-USER-MODIFICATION "
    145       "USAGE dSAOperation )",
    146         &ad_olmRejectedOps },
    147     { "( olmBalancerAttributes:5 "
    148       "NAME ( 'olmCompletedOps' ) "
    149       "DESC 'monitor completed operations' "
    150       "SUP monitorCounter "
    151       "NO-USER-MODIFICATION "
    152       "USAGE dSAOperation )",
    153         &ad_olmCompletedOps },
    154     { "( olmBalancerAttributes:6 "
    155       "NAME ( 'olmFailedOps' ) "
    156       "DESC 'monitor failed operations' "
    157       "SUP monitorCounter "
    158       "NO-USER-MODIFICATION "
    159       "USAGE dSAOperation )",
    160         &ad_olmFailedOps },
    161     { "( olmBalancerAttributes:7 "
    162       "NAME ( 'olmPendingOps' ) "
    163       "DESC 'monitor number of pending operations' "
    164       "EQUALITY integerMatch "
    165       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
    166       "NO-USER-MODIFICATION "
    167       "USAGE dSAOperation )",
    168         &ad_olmPendingOps },
    169     { "( olmBalancerAttributes:8 "
    170       "NAME ( 'olmPendingConnections' ) "
    171       "DESC 'monitor number of pending connections' "
    172       "EQUALITY integerMatch "
    173       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
    174       "NO-USER-MODIFICATION "
    175       "USAGE dSAOperation )",
    176         &ad_olmPendingConnections },
    177     { "( olmBalancerAttributes:9 "
    178       "NAME ( 'olmActiveConnections' ) "
    179       "DESC 'monitor number of active connections' "
    180       "EQUALITY integerMatch "
    181       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
    182       "NO-USER-MODIFICATION "
    183       "USAGE dSAOperation )",
    184         &ad_olmActiveConnections },
    185     { "( olmBalancerAttributes:10 "
    186       "NAME ( 'olmConnectionType' ) "
    187       "DESC 'Connection type' "
    188       "EQUALITY caseIgnoreMatch "
    189       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
    190       "NO-USER-MODIFICATION "
    191       "USAGE dSAOperation )",
    192         &ad_olmConnectionType },
    193     { "( olmBalancerAttributes:11 "
    194       "NAME ( 'olmIncomingConnections' ) "
    195       "DESC 'monitor number of incoming connections' "
    196       "EQUALITY integerMatch "
    197       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
    198       "NO-USER-MODIFICATION "
    199       "USAGE dSAOperation )",
    200         &ad_olmIncomingConnections },
    201     { "( olmBalancerAttributes:12 "
    202       "NAME ( 'olmOutgoingConnections' ) "
    203       "DESC 'monitor number of active connections' "
    204       "EQUALITY integerMatch "
    205       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
    206       "NO-USER-MODIFICATION "
    207       "USAGE dSAOperation )",
    208         &ad_olmOutgoingConnections },
    209     { "( olmBalancerAttributes:13 "
    210       "NAME ( 'olmConnectionState' ) "
    211       "DESC 'Connection state' "
    212       "EQUALITY caseIgnoreMatch "
    213       "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
    214       "USAGE dSAOperation )",
    215         &ad_olmConnectionState },
    216 
    217     { NULL }
    218 };
    219 
    220 static struct {
    221     char *name;
    222     ObjectClass **oc;
    223 } s_moc[] = {
    224     { "monitorContainer", &oc_monitorContainer },
    225     { "monitorCounterObject", &oc_monitorCounterObject },
    226 
    227     { NULL }
    228 };
    229 
    230 static struct {
    231     char *desc;
    232     ObjectClass **oc;
    233 } s_oc[] = {
    234     { "( olmBalancerObjectClasses:1 "
    235       "NAME ( 'olmBalancer' ) "
    236       "SUP top STRUCTURAL "
    237       "MAY ( "
    238       "olmIncomingConnections "
    239       "$ olmOutgoingConnections "
    240       ") )",
    241         &oc_olmBalancer },
    242     { "( olmBalancerObjectClasses:2 "
    243       "NAME ( 'olmBalancerServer' ) "
    244       "SUP top STRUCTURAL "
    245       "MAY ( "
    246       "olmServerURI "
    247       "$ olmActiveConnections "
    248       "$ olmPendingConnections "
    249       "$ olmPendingOps"
    250       "$ olmReceivedOps "
    251       "$ olmCompletedOps "
    252       "$ olmFailedOps "
    253       ") )",
    254         &oc_olmBalancerServer },
    255 
    256     { "( olmBalancerObjectClasses:3 "
    257       "NAME ( 'olmBalancerOperation' ) "
    258       "SUP top STRUCTURAL "
    259       "MAY ( "
    260       "olmReceivedOps "
    261       "$ olmForwardedOps "
    262       "$ olmRejectedOps "
    263       "$ olmCompletedOps "
    264       "$ olmFailedOps "
    265       ") )",
    266         &oc_olmBalancerOperation },
    267     { "( olmBalancerObjectClasses:4 "
    268       "NAME ( 'olmBalancerConnection' ) "
    269       "SUP top STRUCTURAL "
    270       "MAY ( "
    271       "olmConnectionType "
    272       "$ olmConnectionState "
    273       "$ olmPendingOps "
    274       "$ olmReceivedOps "
    275       "$ olmCompletedOps "
    276       "$ olmFailedOps "
    277       ") )",
    278         &oc_olmBalancerConnection },
    279     { NULL }
    280 };
    281 
    282 static int
    283 lload_monitor_subsystem_destroy( BackendDB *be, monitor_subsys_t *ms )
    284 {
    285     ch_free( ms->mss_dn.bv_val );
    286     ch_free( ms->mss_ndn.bv_val );
    287     return LDAP_SUCCESS;
    288 }
    289 
    290 static int
    291 lload_monitor_subsystem_free( BackendDB *be, monitor_subsys_t *ms )
    292 {
    293     lload_monitor_subsystem_destroy( be, ms );
    294     ch_free( ms );
    295     return LDAP_SUCCESS;
    296 }
    297 
    298 static int
    299 lload_monitor_backend_destroy( BackendDB *be, monitor_subsys_t *ms )
    300 {
    301     LloadBackend *b = ms->mss_private;
    302     monitor_extra_t *mbe;
    303     int rc = LDAP_SUCCESS;
    304 
    305     ms->mss_destroy = lload_monitor_subsystem_free;
    306 
    307     mbe = (monitor_extra_t *)be->bd_info->bi_extra;
    308     if ( b->b_monitor ) {
    309         assert( b->b_monitor == ms );
    310         b->b_monitor = NULL;
    311 
    312         rc = mbe->unregister_entry( &ms->mss_ndn );
    313     }
    314 
    315     return rc;
    316 }
    317 
    318 static int
    319 lload_monitor_tier_destroy( BackendDB *be, monitor_subsys_t *ms )
    320 {
    321     LloadTier *tier = ms->mss_private;
    322 
    323     assert( slapd_shutdown || ( tier && tier->t_monitor == ms ) );
    324 
    325     ms->mss_destroy = lload_monitor_subsystem_free;
    326 
    327     if ( !slapd_shutdown ) {
    328         monitor_extra_t *mbe;
    329 
    330         tier->t_monitor = NULL;
    331 
    332         mbe = (monitor_extra_t *)be->bd_info->bi_extra;
    333         return mbe->unregister_entry( &ms->mss_ndn );
    334     }
    335 
    336     return ms->mss_destroy( be, ms );
    337 }
    338 
    339 static void
    340 lload_monitor_balancer_dispose( void **priv )
    341 {
    342     return;
    343 }
    344 
    345 static int
    346 lload_monitor_balancer_free( Entry *e, void **priv )
    347 {
    348     return LDAP_SUCCESS;
    349 }
    350 
    351 static int
    352 lload_monitor_balancer_update(
    353         Operation *op,
    354         SlapReply *rs,
    355         Entry *e,
    356         void *priv )
    357 {
    358     Attribute *a;
    359 
    360     a = attr_find( e->e_attrs, ad_olmIncomingConnections );
    361     assert( a != NULL );
    362 
    363     UI2BV( &a->a_vals[0], lload_stats.global_incoming );
    364 
    365     a = attr_find( e->e_attrs, ad_olmOutgoingConnections );
    366     assert( a != NULL );
    367 
    368     UI2BV( &a->a_vals[0], lload_stats.global_outgoing );
    369     return SLAP_CB_CONTINUE;
    370 }
    371 
    372 static int
    373 lload_monitor_ops_update( Operation *op, SlapReply *rs, Entry *e, void *priv )
    374 {
    375     Attribute *a;
    376     lload_counters_t *counters = (lload_counters_t *)priv;
    377 
    378     a = attr_find( e->e_attrs, ad_olmReceivedOps );
    379     assert( a != NULL );
    380     UI2BV( &a->a_vals[0], counters->lc_ops_received );
    381 
    382     a = attr_find( e->e_attrs, ad_olmForwardedOps );
    383     assert( a != NULL );
    384     UI2BV( &a->a_vals[0], counters->lc_ops_forwarded );
    385 
    386     a = attr_find( e->e_attrs, ad_olmRejectedOps );
    387     assert( a != NULL );
    388     UI2BV( &a->a_vals[0], counters->lc_ops_rejected );
    389 
    390     a = attr_find( e->e_attrs, ad_olmCompletedOps );
    391     assert( a != NULL );
    392     UI2BV( &a->a_vals[0], counters->lc_ops_completed );
    393 
    394     a = attr_find( e->e_attrs, ad_olmFailedOps );
    395     assert( a != NULL );
    396     UI2BV( &a->a_vals[0], counters->lc_ops_failed );
    397 
    398     return SLAP_CB_CONTINUE;
    399 }
    400 
    401 static void
    402 lload_monitor_ops_dispose( void **priv )
    403 {
    404     return;
    405 }
    406 
    407 static int
    408 lload_monitor_ops_free( Entry *e, void **priv )
    409 {
    410     return LDAP_SUCCESS;
    411 }
    412 
    413 static int
    414 lload_monitor_balancer_init( BackendDB *be, monitor_subsys_t *ms )
    415 {
    416     monitor_extra_t *mbe;
    417     Entry *e;
    418     int rc;
    419     monitor_callback_t *cb;
    420     struct berval value = BER_BVC("0");
    421 
    422     assert( be != NULL );
    423 
    424     mbe = (monitor_extra_t *)be->bd_info->bi_extra;
    425 
    426     dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL );
    427 
    428     e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn,
    429             oc_olmBalancer, NULL, NULL );
    430     if ( e == NULL ) {
    431         Debug( LDAP_DEBUG_ANY, "lload_monitor_balancer_init: "
    432                 "unable to create entry \"%s,%s\"\n",
    433                 ms->mss_rdn.bv_val, ms->mss_ndn.bv_val );
    434         return -1;
    435     }
    436 
    437     ch_free( ms->mss_ndn.bv_val );
    438     ber_dupbv( &ms->mss_dn, &e->e_name );
    439     ber_dupbv( &ms->mss_ndn, &e->e_nname );
    440 
    441     cb = ch_calloc( sizeof(monitor_callback_t), 1 );
    442     cb->mc_update = lload_monitor_balancer_update;
    443     cb->mc_free = lload_monitor_balancer_free;
    444     cb->mc_dispose = lload_monitor_balancer_dispose;
    445     cb->mc_private = NULL;
    446 
    447     attr_merge_normalize_one( e, ad_olmIncomingConnections, &value, NULL );
    448     attr_merge_normalize_one( e, ad_olmOutgoingConnections, &value, NULL );
    449 
    450     rc = mbe->register_entry( e, cb, ms, 0 );
    451     if ( rc != LDAP_SUCCESS ) {
    452         Debug( LDAP_DEBUG_ANY, "lload_monitor_balancer_init: "
    453                 "unable to register entry \"%s\" for monitoring\n",
    454                 e->e_name.bv_val );
    455         goto done;
    456     }
    457 
    458 done:
    459     entry_free( e );
    460 
    461     return rc;
    462 }
    463 
    464 static int
    465 lload_monitor_ops_init( BackendDB *be, monitor_subsys_t *ms )
    466 {
    467     monitor_extra_t *mbe;
    468     Entry *e, *parent;
    469     int rc;
    470     int i;
    471     struct berval value = BER_BVC("0");
    472 
    473     assert( be != NULL );
    474 
    475     mbe = (monitor_extra_t *)be->bd_info->bi_extra;
    476 
    477     dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL );
    478     ms->mss_destroy = lload_monitor_subsystem_destroy;
    479 
    480     parent = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn,
    481             oc_monitorContainer, NULL, NULL );
    482     if ( parent == NULL ) {
    483         Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: "
    484                 "unable to create entry \"%s,%s\"\n",
    485                 ms->mss_rdn.bv_val, ms->mss_ndn.bv_val );
    486         return -1;
    487     }
    488     ch_free( ms->mss_ndn.bv_val );
    489     ber_dupbv( &ms->mss_dn, &parent->e_name );
    490     ber_dupbv( &ms->mss_ndn, &parent->e_nname );
    491 
    492     rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH );
    493     if ( rc != LDAP_SUCCESS ) {
    494         Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: "
    495                 "unable to register entry \"%s\" for monitoring\n",
    496                 parent->e_name.bv_val );
    497         goto done;
    498     }
    499 
    500     for ( i = 0; lload_monitor_op[i].rdn.bv_val != NULL; i++ ) {
    501         monitor_callback_t *cb;
    502         e = mbe->entry_stub( &parent->e_name, &parent->e_nname,
    503                 &lload_monitor_op[i].rdn, oc_olmBalancerOperation, NULL, NULL );
    504         if ( e == NULL ) {
    505             Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: "
    506                     "unable to create entry \"%s,%s\"\n",
    507                     lload_monitor_op[i].rdn.bv_val, parent->e_nname.bv_val );
    508             return -1;
    509         }
    510 
    511         /* attr_merge_normalize_one( e, ad_olmDbOperations, &value, NULL ); */
    512 
    513         /*
    514          * We cannot share a single callback between entries.
    515          *
    516          * monitor_cache_destroy() tries to free all callbacks and it's called
    517          * before mss_destroy() so we have no chance of handling it ourselves
    518          */
    519         cb = ch_calloc( sizeof(monitor_callback_t), 1 );
    520         cb->mc_update = lload_monitor_ops_update;
    521         cb->mc_free = lload_monitor_ops_free;
    522         cb->mc_dispose = lload_monitor_ops_dispose;
    523         cb->mc_private = &lload_stats.counters[i];
    524 
    525         attr_merge_normalize_one( e, ad_olmReceivedOps, &value, NULL );
    526         attr_merge_normalize_one( e, ad_olmForwardedOps, &value, NULL );
    527         attr_merge_normalize_one( e, ad_olmRejectedOps, &value, NULL );
    528         attr_merge_normalize_one( e, ad_olmCompletedOps, &value, NULL );
    529         attr_merge_normalize_one( e, ad_olmFailedOps, &value, NULL );
    530 
    531         rc = mbe->register_entry( e, cb, ms, 0 );
    532 
    533         entry_free( e );
    534 
    535         if ( rc != LDAP_SUCCESS ) {
    536             Debug( LDAP_DEBUG_ANY, "lload_monitor_ops_init: "
    537                     "unable to register entry \"%s\" for monitoring\n",
    538                     e->e_name.bv_val );
    539             ch_free( cb );
    540             break;
    541         }
    542     }
    543 
    544 done:
    545     entry_free( parent );
    546     return rc;
    547 }
    548 
    549 static void *
    550 lload_monitor_release_conn( void *ctx, void *arg )
    551 {
    552     LloadConnection *c = arg;
    553     epoch_t epoch = epoch_join();
    554 
    555     RELEASE_REF( c, c_refcnt, c->c_destroy );
    556     epoch_leave( epoch );
    557     return NULL;
    558 }
    559 
    560 static int
    561 lload_monitor_conn_modify( Operation *op, SlapReply *rs, Entry *e, void *priv )
    562 {
    563     Modifications *m;
    564     LloadConnection *c = priv;
    565     int rc = SLAP_CB_CONTINUE;
    566     epoch_t epoch;
    567 
    568     if ( !acquire_ref( &c->c_refcnt ) ) {
    569         /* Shutting down, pretend it's already happened */
    570         return LDAP_NO_SUCH_OBJECT;
    571     }
    572     epoch = epoch_join();
    573 
    574     for ( m = op->orm_modlist; m; m = m->sml_next ) {
    575         struct berval closing = BER_BVC("closing");
    576         int gentle = 1;
    577 
    578         if ( m->sml_flags & SLAP_MOD_INTERNAL ) continue;
    579 
    580         if ( m->sml_desc != ad_olmConnectionState ||
    581                 m->sml_op != LDAP_MOD_REPLACE || m->sml_numvals != 1 ||
    582                 ber_bvcmp( &m->sml_nvalues[0], &closing ) ) {
    583             rc = LDAP_CONSTRAINT_VIOLATION;
    584             goto done;
    585         }
    586 
    587         if ( lload_connection_close( c, &gentle ) ) {
    588             rc = LDAP_OTHER;
    589             goto done;
    590         }
    591     }
    592 
    593 done:
    594     epoch_leave( epoch );
    595     /*
    596      * The connection might have been ready to disappear in epoch_leave(), that
    597      * involves deleting this monitor entry. Make sure that doesn't happen
    598      * punting the decref into a separate task that's not holding any locks and
    599      * finishes after we did.
    600      *
    601      * FIXME: It would probably be cleaner to defer the entry deletion into a
    602      * separate task instead but the entry holds a pointer to this connection
    603      * that might not be safe to manipulate.
    604      */
    605     ldap_pvt_thread_pool_submit(
    606             &connection_pool, lload_monitor_release_conn, c );
    607     return rc;
    608 }
    609 
    610 /*
    611  * Monitor cache is locked, the connection cannot be unlinked and freed under us.
    612  * That also means we need to unlock and finish as soon as possible.
    613  */
    614 static int
    615 lload_monitor_conn_update( Operation *op, SlapReply *rs, Entry *e, void *priv )
    616 {
    617     Attribute *a;
    618     LloadConnection *c = priv;
    619     struct berval bv_type, bv_state;
    620     ldap_pvt_mp_t active, pending, received, completed, failed;
    621 
    622     CONNECTION_LOCK(c);
    623 
    624     pending = (ldap_pvt_mp_t)c->c_n_ops_executing;
    625     received = c->c_counters.lc_ops_received;
    626     completed = c->c_counters.lc_ops_completed;
    627     failed = c->c_counters.lc_ops_failed;
    628 
    629     switch ( c->c_type ) {
    630         case LLOAD_C_OPEN: {
    631             struct berval bv = BER_BVC("regular");
    632             bv_type = bv;
    633         } break;
    634         case LLOAD_C_PREPARING: {
    635             struct berval bv = BER_BVC("preparing");
    636             bv_type = bv;
    637         } break;
    638         case LLOAD_C_BIND: {
    639             struct berval bv = BER_BVC("bind");
    640             bv_type = bv;
    641         } break;
    642         case LLOAD_C_PRIVILEGED: {
    643             struct berval bv = BER_BVC("privileged");
    644             bv_type = bv;
    645         } break;
    646         default: {
    647             struct berval bv = BER_BVC("unknown");
    648             bv_type = bv;
    649         } break;
    650     }
    651 
    652     switch ( c->c_state ) {
    653         case LLOAD_C_INVALID: {
    654             /* *_destroy removes the entry from list before setting c_state to
    655              * INVALID */
    656             assert(0);
    657         } break;
    658         case LLOAD_C_READY: {
    659             struct berval bv = BER_BVC("ready");
    660             bv_state = bv;
    661         } break;
    662         case LLOAD_C_CLOSING: {
    663             struct berval bv = BER_BVC("closing");
    664             bv_state = bv;
    665         } break;
    666         case LLOAD_C_ACTIVE: {
    667             struct berval bv = BER_BVC("active");
    668             bv_state = bv;
    669         } break;
    670         case LLOAD_C_BINDING: {
    671             struct berval bv = BER_BVC("binding");
    672             bv_state = bv;
    673         } break;
    674         case LLOAD_C_DYING: {
    675             /* I guess we got it before it was unlinked? */
    676             struct berval bv = BER_BVC("dying");
    677             bv_state = bv;
    678         } break;
    679         default: {
    680             struct berval bv = BER_BVC("unknown");
    681             bv_state = bv;
    682         } break;
    683     }
    684 
    685     CONNECTION_UNLOCK(c);
    686 
    687     a = attr_find( e->e_attrs, ad_olmConnectionType );
    688     assert( a != NULL );
    689     if ( !(a->a_flags & SLAP_ATTR_DONT_FREE_DATA) ) {
    690         ber_memfree( a->a_vals[0].bv_val );
    691         a->a_flags |= SLAP_ATTR_DONT_FREE_DATA;
    692     }
    693     a->a_vals[0] = bv_type;
    694 
    695     a = attr_find( e->e_attrs, ad_olmConnectionState );
    696     assert( a != NULL );
    697     if ( !(a->a_flags & SLAP_ATTR_DONT_FREE_DATA) ) {
    698         ber_memfree( a->a_vals[0].bv_val );
    699         a->a_flags |= SLAP_ATTR_DONT_FREE_DATA;
    700     }
    701     a->a_vals[0] = bv_state;
    702 
    703     a = attr_find( e->e_attrs, ad_olmPendingOps );
    704     assert( a != NULL );
    705     UI2BV( &a->a_vals[0], pending );
    706 
    707     a = attr_find( e->e_attrs, ad_olmReceivedOps );
    708     assert( a != NULL );
    709     UI2BV( &a->a_vals[0], received );
    710 
    711     a = attr_find( e->e_attrs, ad_olmCompletedOps );
    712     assert( a != NULL );
    713     UI2BV( &a->a_vals[0], completed );
    714 
    715     a = attr_find( e->e_attrs, ad_olmFailedOps );
    716     assert( a != NULL );
    717     UI2BV( &a->a_vals[0], failed );
    718 
    719     return SLAP_CB_CONTINUE;
    720 }
    721 
    722 int
    723 lload_monitor_conn_unlink( LloadConnection *c )
    724 {
    725     BackendInfo *mi = backend_info( "monitor" );
    726     monitor_extra_t *mbe = mi->bi_extra;
    727 
    728     assert( mbe && mbe->is_configured() );
    729 
    730     CONNECTION_ASSERT_LOCKED(c);
    731     assert( !BER_BVISNULL( &c->c_monitor_dn ) );
    732 
    733     /*
    734      * Avoid a lock inversion with threads holding monitor cache locks in turn
    735      * waiting on CONNECTION_LOCK(c)
    736      */
    737     CONNECTION_UNLOCK(c);
    738     mbe->unregister_entry( &c->c_monitor_dn );
    739     CONNECTION_LOCK(c);
    740 
    741     ber_memfree( c->c_monitor_dn.bv_val );
    742     BER_BVZERO( &c->c_monitor_dn );
    743 
    744     return 0;
    745 }
    746 
    747 int
    748 lload_monitor_conn_entry_create( LloadConnection *c, monitor_subsys_t *ms )
    749 {
    750     char buf[SLAP_TEXT_BUFLEN];
    751     char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE];
    752     struct tm tm;
    753     struct berval bv_rdn, bv_timestamp, zero = BER_BVC("0"),
    754                                         value = BER_BVC("unknown");
    755     monitor_entry_t *mp;
    756     monitor_callback_t *cb;
    757     Entry *e;
    758     Attribute *a;
    759     BackendInfo *mi = backend_info( "monitor" );
    760     monitor_extra_t *mbe = mi->bi_extra;
    761 
    762     assert( mbe && mbe->is_configured() );
    763 
    764     CONNECTION_ASSERT_LOCKED(c);
    765     assert( BER_BVISNULL( &c->c_monitor_dn ) );
    766 
    767     bv_rdn.bv_val = buf;
    768     bv_rdn.bv_len = snprintf(
    769             bv_rdn.bv_val, SLAP_TEXT_BUFLEN, "cn=Connection %lu", c->c_connid );
    770 
    771     ldap_pvt_gmtime( &c->c_activitytime, &tm );
    772     bv_timestamp.bv_len = lutil_gentime( timebuf, sizeof(timebuf), &tm );
    773     bv_timestamp.bv_val = timebuf;
    774 
    775     e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv_rdn,
    776             oc_olmBalancerConnection, &bv_timestamp, &bv_timestamp );
    777 
    778     cb = ch_calloc( sizeof(monitor_callback_t), 1 );
    779     cb->mc_update = lload_monitor_conn_update;
    780     cb->mc_modify = lload_monitor_conn_modify;
    781     cb->mc_private = c;
    782 
    783     attr_merge_one( e, ad_olmConnectionType, &value, NULL );
    784     attr_merge_one( e, ad_olmConnectionState, &value, NULL );
    785     attr_merge_one( e, ad_olmPendingOps, &zero, NULL );
    786     attr_merge_one( e, ad_olmReceivedOps, &zero, NULL );
    787     attr_merge_one( e, ad_olmCompletedOps, &zero, NULL );
    788     attr_merge_one( e, ad_olmFailedOps, &zero, NULL );
    789 
    790     if ( mbe->register_entry( e, cb, NULL, 0 ) ) {
    791         Debug( LDAP_DEBUG_ANY, "lload_monitor_conn_entry_create: "
    792                 "failed to register monitor entry for connid=%lu\n",
    793                 c->c_connid );
    794 
    795         ch_free( cb );
    796         entry_free( e );
    797         return -1;
    798     }
    799 
    800     ber_dupbv( &c->c_monitor_dn, &e->e_nname );
    801     entry_free( e );
    802 
    803     return 0;
    804 }
    805 
    806 static int
    807 lload_monitor_incoming_conn_init( BackendDB *be, monitor_subsys_t *ms )
    808 {
    809     monitor_extra_t *mbe;
    810     Entry *e;
    811     int rc;
    812 
    813     assert( be != NULL );
    814     mbe = (monitor_extra_t *)be->bd_info->bi_extra;
    815 
    816     ms->mss_destroy = lload_monitor_subsystem_destroy;
    817 
    818     dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL );
    819 
    820     e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn,
    821             oc_monitorContainer, NULL, NULL );
    822     if ( e == NULL ) {
    823         Debug( LDAP_DEBUG_ANY, "lload_monitor_incoming_conn_init: "
    824                 "unable to create entry \"%s,%s\"\n",
    825                 ms->mss_rdn.bv_val, ms->mss_ndn.bv_val );
    826         return -1;
    827     }
    828     ch_free( ms->mss_ndn.bv_val );
    829     ber_dupbv( &ms->mss_dn, &e->e_name );
    830     ber_dupbv( &ms->mss_ndn, &e->e_nname );
    831 
    832     rc = mbe->register_entry( e, NULL, ms, 0 );
    833 
    834     if ( rc != LDAP_SUCCESS ) {
    835         Debug( LDAP_DEBUG_ANY, "lload_monitor_incoming_conn_init: "
    836                 "unable to register entry \"%s\" for monitoring\n",
    837                 e->e_name.bv_val );
    838         goto done;
    839     }
    840 
    841     lload_monitor_client_subsys = ms;
    842 
    843 done:
    844     entry_free( e );
    845 
    846     return rc;
    847 }
    848 
    849 static int
    850 lload_monitor_server_update(
    851         Operation *op,
    852         SlapReply *rs,
    853         Entry *e,
    854         void *priv )
    855 {
    856     Attribute *a;
    857     LloadBackend *b = priv;
    858     LloadConnection *c;
    859     LloadPendingConnection *pc;
    860     ldap_pvt_mp_t active = 0, pending = 0, received = 0, completed = 0,
    861                   failed = 0;
    862     int i;
    863 
    864     checked_lock( &b->b_mutex );
    865     active = b->b_active + b->b_bindavail;
    866 
    867     LDAP_CIRCLEQ_FOREACH ( c, &b->b_preparing, c_next ) {
    868         pending++;
    869     }
    870 
    871     LDAP_LIST_FOREACH( pc, &b->b_connecting, next ) {
    872         pending++;
    873     }
    874 
    875     for ( i = 0; i < LLOAD_STATS_OPS_LAST; i++ ) {
    876         received += b->b_counters[i].lc_ops_received;
    877         completed += b->b_counters[i].lc_ops_completed;
    878         failed += b->b_counters[i].lc_ops_failed;
    879     }
    880 
    881     a = attr_find( e->e_attrs, ad_olmPendingOps );
    882     assert( a != NULL );
    883     UI2BV( &a->a_vals[0], (long long unsigned int)b->b_n_ops_executing );
    884 
    885     checked_unlock( &b->b_mutex );
    886 
    887     /* Right now, there is no way to retrieve the entry from monitor's
    888      * cache to replace URI at the moment it is modified */
    889     a = attr_find( e->e_attrs, ad_olmServerURI );
    890     assert( a != NULL );
    891     ber_bvreplace( &a->a_vals[0], &b->b_uri );
    892 
    893     a = attr_find( e->e_attrs, ad_olmActiveConnections );
    894     assert( a != NULL );
    895     UI2BV( &a->a_vals[0], active );
    896 
    897     a = attr_find( e->e_attrs, ad_olmPendingConnections );
    898     assert( a != NULL );
    899     UI2BV( &a->a_vals[0], pending );
    900 
    901     a = attr_find( e->e_attrs, ad_olmReceivedOps );
    902     assert( a != NULL );
    903     UI2BV( &a->a_vals[0], received );
    904 
    905     a = attr_find( e->e_attrs, ad_olmCompletedOps );
    906     assert( a != NULL );
    907     UI2BV( &a->a_vals[0], completed );
    908 
    909     a = attr_find( e->e_attrs, ad_olmFailedOps );
    910     assert( a != NULL );
    911     UI2BV( &a->a_vals[0], failed );
    912 
    913     return SLAP_CB_CONTINUE;
    914 }
    915 
    916 static int
    917 lload_monitor_backend_open( BackendDB *be, monitor_subsys_t *ms )
    918 {
    919     Entry *e;
    920     struct berval value = BER_BVC("0");
    921     monitor_extra_t *mbe;
    922     monitor_callback_t *cb;
    923     LloadBackend *b = ms->mss_private;
    924     LloadTier *tier = b->b_tier;
    925     int rc;
    926 
    927     assert( be != NULL );
    928     mbe = (monitor_extra_t *)be->bd_info->bi_extra;
    929 
    930     e = mbe->entry_stub( &tier->t_monitor->mss_dn, &tier->t_monitor->mss_ndn,
    931             &ms->mss_rdn, oc_olmBalancerServer, NULL, NULL );
    932     if ( e == NULL ) {
    933         Debug( LDAP_DEBUG_ANY, "lload_monitor_backend_open: "
    934                 "unable to create entry \"%s,%s\"\n",
    935                 ms->mss_rdn.bv_val, tier->t_monitor->mss_dn.bv_val );
    936         return -1;
    937     }
    938 
    939     ber_dupbv( &ms->mss_dn, &e->e_name );
    940     ber_dupbv( &ms->mss_ndn, &e->e_nname );
    941 
    942     cb = ch_calloc( sizeof(monitor_callback_t), 1 );
    943     cb->mc_update = lload_monitor_server_update;
    944     cb->mc_free = NULL;
    945     cb->mc_dispose = NULL;
    946     cb->mc_private = b;
    947 
    948     attr_merge_normalize_one( e, ad_olmServerURI, &b->b_uri, NULL );
    949     attr_merge_normalize_one( e, ad_olmActiveConnections, &value, NULL );
    950     attr_merge_normalize_one( e, ad_olmPendingConnections, &value, NULL );
    951     attr_merge_normalize_one( e, ad_olmPendingOps, &value, NULL );
    952     attr_merge_normalize_one( e, ad_olmReceivedOps, &value, NULL );
    953     attr_merge_normalize_one( e, ad_olmCompletedOps, &value, NULL );
    954     attr_merge_normalize_one( e, ad_olmFailedOps, &value, NULL );
    955 
    956     rc = mbe->register_entry( e, cb, ms, 0 );
    957 
    958     if ( rc != LDAP_SUCCESS ) {
    959         Debug( LDAP_DEBUG_ANY, "lload_monitor_backend_open: "
    960                 "unable to register entry \"%s\" for monitoring\n",
    961                 e->e_name.bv_val );
    962         goto done;
    963     }
    964 
    965     ms->mss_destroy = lload_monitor_backend_destroy;
    966 
    967 done:
    968     entry_free( e );
    969     return rc;
    970 }
    971 
    972 int
    973 lload_monitor_backend_init(
    974         BackendInfo *bi,
    975         monitor_subsys_t *ms,
    976         LloadBackend *b )
    977 {
    978     monitor_extra_t *mbe = bi->bi_extra;
    979     monitor_subsys_t *bk_mss;
    980 
    981     /* FIXME: With back-monitor as it works now, there is no way to know when
    982      * this can be safely freed so we leak it on shutdown */
    983     bk_mss = ch_calloc( 1, sizeof(monitor_subsys_t) );
    984     bk_mss->mss_rdn.bv_len = sizeof("cn=") + b->b_name.bv_len;
    985     bk_mss->mss_rdn.bv_val = ch_malloc( bk_mss->mss_rdn.bv_len );
    986     bk_mss->mss_rdn.bv_len = snprintf( bk_mss->mss_rdn.bv_val,
    987             bk_mss->mss_rdn.bv_len, "cn=%s", b->b_name.bv_val );
    988 
    989     bk_mss->mss_name = b->b_name.bv_val;
    990     bk_mss->mss_flags = MONITOR_F_NONE;
    991     bk_mss->mss_open = lload_monitor_backend_open;
    992     bk_mss->mss_destroy = lload_monitor_subsystem_destroy;
    993     bk_mss->mss_update = NULL;
    994     bk_mss->mss_private = b;
    995 
    996     if ( mbe->register_subsys_late( bk_mss ) ) {
    997         Debug( LDAP_DEBUG_ANY, "lload_monitor_backend_init: "
    998                 "failed to register backend %s\n",
    999                 bk_mss->mss_name );
   1000         ch_free( bk_mss );
   1001         return -1;
   1002     }
   1003 
   1004     b->b_monitor = bk_mss;
   1005     return LDAP_SUCCESS;
   1006 }
   1007 
   1008 static int
   1009 lload_monitor_tier_open( BackendDB *be, monitor_subsys_t *ms )
   1010 {
   1011     Entry *e;
   1012     monitor_extra_t *mbe;
   1013     LloadTier *tier = ms->mss_private;
   1014     int rc;
   1015 
   1016     assert( be != NULL );
   1017     mbe = (monitor_extra_t *)be->bd_info->bi_extra;
   1018 
   1019     dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL );
   1020     e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn,
   1021             oc_monitorContainer, NULL, NULL );
   1022     if ( e == NULL ) {
   1023         Debug( LDAP_DEBUG_ANY, "lload_monitor_tier_open: "
   1024                 "unable to create entry \"%s,%s\"\n",
   1025                 ms->mss_rdn.bv_val, ms->mss_ndn.bv_val );
   1026         return -1;
   1027     }
   1028 
   1029     ch_free( ms->mss_ndn.bv_val );
   1030     ber_dupbv( &ms->mss_dn, &e->e_name );
   1031     ber_dupbv( &ms->mss_ndn, &e->e_nname );
   1032 
   1033     rc = mbe->register_entry( e, NULL, ms, MONITOR_F_PERSISTENT_CH );
   1034 
   1035     if ( rc != LDAP_SUCCESS ) {
   1036         Debug( LDAP_DEBUG_ANY, "lload_monitor_tier_open: "
   1037                 "unable to register entry \"%s\" for monitoring\n",
   1038                 e->e_name.bv_val );
   1039         goto done;
   1040     }
   1041 
   1042     tier->t_monitor = ms;
   1043     ms->mss_destroy = lload_monitor_tier_destroy;
   1044 
   1045 done:
   1046     entry_free( e );
   1047     return rc;
   1048 }
   1049 
   1050 int
   1051 lload_monitor_tier_init( BackendInfo *bi, LloadTier *tier )
   1052 {
   1053     monitor_extra_t *mbe;
   1054     monitor_subsys_t *mss;
   1055     LloadBackend *b;
   1056 
   1057     mbe = (monitor_extra_t *)bi->bi_extra;
   1058 
   1059     mss = ch_calloc( 1, sizeof(monitor_subsys_t) );
   1060     mss->mss_rdn.bv_len = sizeof("cn=") + tier->t_name.bv_len;
   1061     mss->mss_rdn.bv_val = ch_malloc( mss->mss_rdn.bv_len );
   1062     mss->mss_rdn.bv_len = snprintf( mss->mss_rdn.bv_val, mss->mss_rdn.bv_len,
   1063             "cn=%s", tier->t_name.bv_val );
   1064 
   1065     ber_str2bv( LLOAD_MONITOR_TIERS_DN, 0, 0, &mss->mss_dn );
   1066     mss->mss_name = tier->t_name.bv_val;
   1067     mss->mss_open = lload_monitor_tier_open;
   1068     mss->mss_destroy = lload_monitor_subsystem_destroy;
   1069     mss->mss_update = NULL;
   1070     mss->mss_private = tier;
   1071 
   1072     if ( mbe->register_subsys_late( mss ) ) {
   1073         Debug( LDAP_DEBUG_ANY, "lload_monitor_tier_init: "
   1074                 "failed to register backend %s\n",
   1075                 mss->mss_name );
   1076         return -1;
   1077     }
   1078 
   1079     LDAP_CIRCLEQ_FOREACH ( b, &tier->t_backends, b_next ) {
   1080         if ( lload_monitor_backend_init( bi, mss, b ) ) {
   1081             return -1;
   1082         }
   1083     }
   1084 
   1085     return LDAP_SUCCESS;
   1086 }
   1087 
   1088 int
   1089 lload_monitor_tiers_init( BackendDB *be, monitor_subsys_t *ms )
   1090 {
   1091     monitor_extra_t *mbe;
   1092     LloadTier *tier;
   1093     Entry *e;
   1094     int rc;
   1095 
   1096     assert( be != NULL );
   1097     mbe = (monitor_extra_t *)be->bd_info->bi_extra;
   1098 
   1099     dnNormalize( 0, NULL, NULL, &ms->mss_dn, &ms->mss_ndn, NULL );
   1100 
   1101     e = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn, &ms->mss_rdn,
   1102             oc_monitorContainer, NULL, NULL );
   1103     if ( e == NULL ) {
   1104         Debug( LDAP_DEBUG_ANY, "lload_monitor_tiers_init: "
   1105                 "unable to create entry \"%s,%s\"\n",
   1106                 ms->mss_rdn.bv_val, ms->mss_ndn.bv_val );
   1107         return -1;
   1108     }
   1109     ch_free( ms->mss_ndn.bv_val );
   1110     ber_dupbv( &ms->mss_dn, &e->e_name );
   1111     ber_dupbv( &ms->mss_ndn, &e->e_nname );
   1112 
   1113     rc = mbe->register_entry( e, NULL, ms, MONITOR_F_PERSISTENT_CH );
   1114 
   1115     if ( rc != LDAP_SUCCESS ) {
   1116         Debug( LDAP_DEBUG_ANY, "lload_monitor_tiers_init: "
   1117                 "unable to register entry \"%s\" for monitoring\n",
   1118                 e->e_name.bv_val );
   1119         goto done;
   1120     }
   1121 
   1122     LDAP_STAILQ_FOREACH ( tier, &tiers, t_next ) {
   1123         if ( (rc = lload_monitor_tier_init( be->bd_info, tier )) ) {
   1124             break;
   1125         }
   1126     }
   1127 done:
   1128     entry_free( e );
   1129 
   1130     return rc;
   1131 }
   1132 
   1133 static int
   1134 lload_monitor_incoming_count( LloadConnection *conn, void *argv )
   1135 {
   1136     lload_global_stats_t *tmp_stats = argv;
   1137     tmp_stats->global_incoming++;
   1138     return 0;
   1139 }
   1140 
   1141 /*
   1142  * Update all global statistics other than rejected and received,
   1143  * which are updated in real time
   1144  */
   1145 void *
   1146 lload_monitor_update_global_stats( void *ctx, void *arg )
   1147 {
   1148     struct re_s *rtask = arg;
   1149     lload_global_stats_t tmp_stats = {};
   1150     LloadTier *tier;
   1151     int i;
   1152 
   1153     Debug( LDAP_DEBUG_TRACE, "lload_monitor_update_global_stats: "
   1154             "updating stats\n" );
   1155 
   1156     /* count incoming connections */
   1157     checked_lock( &clients_mutex );
   1158     connections_walk( &clients_mutex, &clients, lload_monitor_incoming_count,
   1159             &tmp_stats );
   1160     checked_unlock( &clients_mutex );
   1161 
   1162     LDAP_STAILQ_FOREACH ( tier, &tiers, t_next ) {
   1163         LloadBackend *b;
   1164 
   1165         LDAP_CIRCLEQ_FOREACH ( b, &tier->t_backends, b_next ) {
   1166             checked_lock( &b->b_mutex );
   1167             tmp_stats.global_outgoing += b->b_active + b->b_bindavail;
   1168 
   1169             /* merge completed and failed stats */
   1170             for ( i = 0; i < LLOAD_STATS_OPS_LAST; i++ ) {
   1171                 tmp_stats.counters[i].lc_ops_completed +=
   1172                         b->b_counters[i].lc_ops_completed;
   1173                 tmp_stats.counters[i].lc_ops_failed +=
   1174                         b->b_counters[i].lc_ops_failed;
   1175             }
   1176             checked_unlock( &b->b_mutex );
   1177         }
   1178     }
   1179 
   1180     /* update lload_stats */
   1181     lload_stats.global_outgoing = tmp_stats.global_outgoing;
   1182     lload_stats.global_incoming = tmp_stats.global_incoming;
   1183     for ( i = 0; i < LLOAD_STATS_OPS_LAST; i++ ) {
   1184         lload_stats.counters[i].lc_ops_completed =
   1185                 tmp_stats.counters[i].lc_ops_completed;
   1186         lload_stats.counters[i].lc_ops_failed =
   1187                 tmp_stats.counters[i].lc_ops_failed;
   1188     }
   1189 
   1190     /* reschedule */
   1191     checked_lock( &slapd_rq.rq_mutex );
   1192     ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
   1193     checked_unlock( &slapd_rq.rq_mutex );
   1194     return NULL;
   1195 }
   1196 
   1197 static char *lload_subsys_rdn[] = {
   1198     LLOAD_MONITOR_BALANCER_RDN,
   1199     LLOAD_MONITOR_INCOMING_RDN,
   1200     LLOAD_MONITOR_OPERATIONS_RDN,
   1201     LLOAD_MONITOR_TIERS_RDN,
   1202     NULL
   1203 };
   1204 
   1205 static struct monitor_subsys_t balancer_subsys[] = {
   1206     {
   1207         LLOAD_MONITOR_BALANCER_NAME,
   1208         BER_BVNULL,
   1209         BER_BVC(SLAPD_MONITOR_BACKEND_DN),
   1210         BER_BVNULL,
   1211         { BER_BVC("Load Balancer information"),
   1212           BER_BVNULL },
   1213         MONITOR_F_PERSISTENT_CH,
   1214         lload_monitor_balancer_init,
   1215         lload_monitor_subsystem_destroy, /* destroy */
   1216         NULL,   /* update */
   1217         NULL,   /* create */
   1218         NULL    /* modify */
   1219     },
   1220     {
   1221         LLOAD_MONITOR_INCOMING_NAME,
   1222         BER_BVNULL,
   1223         BER_BVC(LLOAD_MONITOR_BALANCER_DN),
   1224         BER_BVNULL,
   1225         { BER_BVC("Load Balancer incoming connections"),
   1226           BER_BVNULL },
   1227         MONITOR_F_NONE,
   1228         lload_monitor_incoming_conn_init,
   1229         lload_monitor_subsystem_destroy, /* destroy */
   1230         NULL,   /* update */
   1231         NULL,   /* create */
   1232         NULL    /* modify */
   1233     },
   1234     {
   1235         LLOAD_MONITOR_OPERATIONS_NAME,
   1236         BER_BVNULL,
   1237         BER_BVC(LLOAD_MONITOR_BALANCER_DN),
   1238         BER_BVNULL,
   1239         { BER_BVC("Load Balancer global operation statistics"),
   1240           BER_BVNULL },
   1241         MONITOR_F_PERSISTENT_CH,
   1242         lload_monitor_ops_init,
   1243         lload_monitor_subsystem_destroy, /* destroy */
   1244         NULL,   /* update */
   1245         NULL,   /* create */
   1246         NULL    /* modify */
   1247     },
   1248     {
   1249         LLOAD_MONITOR_TIERS_NAME,
   1250         BER_BVNULL,
   1251         BER_BVC(LLOAD_MONITOR_BALANCER_DN),
   1252         BER_BVNULL,
   1253         { BER_BVC("Load Balancer Backends information"),
   1254           BER_BVNULL },
   1255         MONITOR_F_PERSISTENT_CH,
   1256         lload_monitor_tiers_init,
   1257         lload_monitor_subsystem_destroy, /* destroy */
   1258         NULL,   /* update */
   1259         NULL,   /* create */
   1260         NULL    /* modify */
   1261     },
   1262     { NULL }
   1263 };
   1264 
   1265 int
   1266 lload_monitor_open( void )
   1267 {
   1268     static int lload_monitor_initialized_failure = 1;
   1269     static int lload_monitor_initialized = 0;
   1270     BackendInfo *mi;
   1271     monitor_extra_t *mbe;
   1272     monitor_subsys_t *mss;
   1273     ConfigArgs c;
   1274     char *argv[3], **rdn;
   1275     int i, rc;
   1276 
   1277     /* check if monitor is configured and usable */
   1278     mi = backend_info( "monitor" );
   1279     if ( !mi || !mi->bi_extra ) {
   1280         Debug( LDAP_DEBUG_CONFIG, "lload_monitor_open: "
   1281                 "monitor backend not available, monitoring disabled\n" );
   1282         return 0;
   1283     }
   1284     mbe = mi->bi_extra;
   1285 
   1286     /* don't bother if monitor is not configured */
   1287     if ( !mbe->is_configured() ) {
   1288         static int warning = 0;
   1289 
   1290         if ( warning++ == 0 ) {
   1291             Debug( LDAP_DEBUG_CONFIG, "lload_monitor_open: "
   1292                     "monitoring disabled; "
   1293                     "configure monitor database to enable\n" );
   1294         }
   1295 
   1296         return 0;
   1297     }
   1298 
   1299     if ( lload_monitor_initialized++ ) {
   1300         return lload_monitor_initialized_failure;
   1301     }
   1302 
   1303     argv[0] = "lload monitor";
   1304     c.argv = argv;
   1305     c.argc = 3;
   1306     c.fname = argv[0];
   1307     for ( i = 0; s_oid[i].name; i++ ) {
   1308         argv[1] = s_oid[i].name;
   1309         argv[2] = s_oid[i].oid;
   1310 
   1311         if ( parse_oidm( &c, 0, NULL ) != 0 ) {
   1312             Debug( LDAP_DEBUG_ANY, "lload_monitor_open: "
   1313                     "unable to add objectIdentifier \"%s=%s\"\n",
   1314                     s_oid[i].name, s_oid[i].oid );
   1315             return 2;
   1316         }
   1317     }
   1318 
   1319     for ( i = 0; s_at[i].desc != NULL; i++ ) {
   1320         rc = register_at( s_at[i].desc, s_at[i].ad, 1 );
   1321         if ( rc != LDAP_SUCCESS ) {
   1322             Debug( LDAP_DEBUG_ANY, "lload_monitor_open: "
   1323                     "register_at failed for attributeType (%s)\n",
   1324                     s_at[i].desc );
   1325             return 3;
   1326 
   1327         } else {
   1328             (*s_at[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
   1329         }
   1330     }
   1331 
   1332     for ( i = 0; s_oc[i].desc != NULL; i++ ) {
   1333         rc = register_oc( s_oc[i].desc, s_oc[i].oc, 1 );
   1334         if ( rc != LDAP_SUCCESS ) {
   1335             Debug( LDAP_DEBUG_ANY, "lload_monitor_open: "
   1336                     "register_oc failed for objectClass (%s)\n",
   1337                     s_oc[i].desc );
   1338             return 4;
   1339 
   1340         } else {
   1341             (*s_oc[i].oc)->soc_flags |= SLAP_OC_HIDE;
   1342         }
   1343     }
   1344 
   1345     for ( i = 0; s_moc[i].name != NULL; i++ ) {
   1346         *s_moc[i].oc = oc_find( s_moc[i].name );
   1347         if ( !*s_moc[i].oc ) {
   1348             Debug( LDAP_DEBUG_ANY, "lload_monitor_open: "
   1349                     "failed to find objectClass (%s)\n",
   1350                     s_moc[i].name );
   1351             return 5;
   1352         }
   1353     }
   1354 
   1355     /* register the subsystems - Servers are registered in backends_init */
   1356     for ( mss = balancer_subsys, rdn = lload_subsys_rdn; mss->mss_name;
   1357             mss++, rdn++ ) {
   1358         ber_str2bv( *rdn, 0, 1, &mss->mss_rdn );
   1359         if ( mbe->register_subsys_late( mss ) ) {
   1360             Debug( LDAP_DEBUG_ANY, "lload_monitor_open: "
   1361                     "failed to register %s subsystem\n",
   1362                     mss->mss_name );
   1363             return -1;
   1364         }
   1365     }
   1366 
   1367     checked_lock( &slapd_rq.rq_mutex );
   1368     ldap_pvt_runqueue_insert( &slapd_rq, 1, lload_monitor_update_global_stats,
   1369             NULL, "lload_monitor_update_global_stats", "lloadd" );
   1370     checked_unlock( &slapd_rq.rq_mutex );
   1371 
   1372     return (lload_monitor_initialized_failure = LDAP_SUCCESS);
   1373 }
   1374