]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9339 Add syncrepl status to cn=monitor
authorHoward Chu <hyc@openldap.org>
Sun, 6 Sep 2020 15:09:35 +0000 (16:09 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Thu, 10 Sep 2020 02:29:19 +0000 (02:29 +0000)
Shows connection address, refresh/persist state, time of last
connect attempt and received data, and last sent and
received cookies per consumer.

servers/slapd/backend.c
servers/slapd/daemon.c
servers/slapd/proto-slap.h
servers/slapd/slap.h
servers/slapd/syncrepl.c

index f4d9c53b35f972afeb4c5e0afbfd12d5e794d904..f15ee9e8153208a3670c04f47590ed482a431aec 100644 (file)
@@ -78,6 +78,8 @@ backend_init_controls( BackendInfo *bi )
        return 0;
 }
 
+extern int syncrepl_monitor_init(void);
+
 int backend_init(void)
 {
        int rc = -1;
@@ -114,6 +116,9 @@ int backend_init(void)
 
                LDAP_STAILQ_INSERT_TAIL(&backendInfo, bi, bi_next);
        }
+       /* HACK: need schema defined in deterministic order */
+       syncrepl_monitor_init();
+
 
        if ( nBackendInfo > 0) {
                return 0;
index 48d502136e203e9d83bbee6966aa33c123a28c26..dc132754c65a859f5c9b49fe711aab35869cb9b6 100644 (file)
@@ -2121,6 +2121,78 @@ destroy_listeners( void )
        slap_listeners = NULL;
 }
 
+void
+slap_sockaddrstr( Sockaddr *sa, struct berval *addrbuf )
+{
+       char *addr;
+       switch( sa->sa_addr.sa_family ) {
+#ifdef LDAP_PF_LOCAL
+       case AF_LOCAL:
+               addrbuf->bv_len = snprintf( addrbuf->bv_val, addrbuf->bv_len,
+                       "PATH=%s", sa->sa_un_addr.sun_path );
+               break;
+#endif
+#ifdef LDAP_PF_INET6
+       case AF_INET6:
+               strcpy(addrbuf->bv_val, "IP=");
+               if ( IN6_IS_ADDR_V4MAPPED(&sa->sa_in6_addr.sin6_addr) ) {
+#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
+                       addr = inet_ntop( AF_INET,
+                          ((struct in_addr *)&sa->sa_in6_addr.sin6_addr.s6_addr[12]),
+                          addrbuf->bv_val+3, addrbuf->bv_len-3 );
+#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+                       addr = inet_ntoa( *((struct in_addr *)
+                                       &sa->sa_in6_addr.sin6_addr.s6_addr[12]) );
+#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+                       if ( !addr ) addr = SLAP_STRING_UNKNOWN;
+                       if ( addr != addrbuf->bv_val+3 ) {
+                               addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
+                                (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
+                       } else {
+                               int len = strlen( addr );
+                               addrbuf->bv_len = sprintf( addr+len, ":%d",
+                                (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 3;
+                       }
+               } else {
+                       addr = inet_ntop( AF_INET6,
+                                     &sa->sa_in6_addr.sin6_addr,
+                                     addrbuf->bv_val+4, addrbuf->bv_len-4 );
+                       if ( !addr ) addr = SLAP_STRING_UNKNOWN;
+                       if ( addr != addrbuf->bv_val+4 ) {
+                               addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "[%s]:%d", addr,
+                                (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
+                       } else {
+                               int len = strlen( addr );
+                               addrbuf->bv_val[3] = '[';
+                               addrbuf->bv_len = sprintf( addr+len, "]:%d",
+                                (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 4;
+                       }
+               }
+               break;
+#endif /* LDAP_PF_INET6 */
+       case AF_INET:
+               strcpy(addrbuf->bv_val, "IP=");
+#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
+               addr = inet_ntop( AF_INET, &sa->sa_in_addr.sin_addr,
+                          addrbuf->bv_val+3, addrbuf->bv_len-3 );
+#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+               addr = inet_ntoa( sa->sa_in_addr.sin_addr );
+#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+               if ( !addr ) addr = SLAP_STRING_UNKNOWN;
+               if ( addr != addrbuf->bv_val+3 ) {
+                       addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
+                        (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + 3;
+               } else {
+                       int len = strlen( addr );
+                       addrbuf->bv_len = sprintf( addr+len, ":%d",
+                        (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + len + 3;
+               }
+               break;
+       default:
+               addrbuf->bv_val[0] = '\0';
+       }
+}
+
 static int
 slap_listener(
        Listener *sl )
@@ -2139,18 +2211,12 @@ slap_listener(
        char    *dnsname = NULL;
        const char *peeraddr = NULL;
        /* we assume INET6_ADDRSTRLEN > INET_ADDRSTRLEN */
-       char addr[INET6_ADDRSTRLEN];
-#ifdef LDAP_PF_LOCAL
-       char peername[MAXPATHLEN + sizeof("PATH=")];
+       char peername[SLAP_ADDRLEN];
+       struct berval peerbv = BER_BVC(peername);
 #ifdef LDAP_PF_LOCAL_SENDMSG
        char peerbuf[8];
        struct berval peerbv = BER_BVNULL;
 #endif
-#elif defined(LDAP_PF_INET6)
-       char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")];
-#else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */
-       char peername[sizeof("IP=255.255.255.255:65336")];
-#endif /* LDAP_PF_LOCAL */
        int cflag;
        int tid;
 
@@ -2315,40 +2381,10 @@ slap_listener(
 
 #  ifdef LDAP_PF_INET6
        case AF_INET6:
-       if ( IN6_IS_ADDR_V4MAPPED(&from.sa_in6_addr.sin6_addr) ) {
-#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
-               peeraddr = inet_ntop( AF_INET,
-                          ((struct in_addr *)&from.sa_in6_addr.sin6_addr.s6_addr[12]),
-                          addr, sizeof(addr) );
-#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
-               peeraddr = inet_ntoa( *((struct in_addr *)
-                                       &from.sa_in6_addr.sin6_addr.s6_addr[12]) );
-#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
-               if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
-               sprintf( peername, "IP=%s:%d", peeraddr,
-                        (unsigned) ntohs( from.sa_in6_addr.sin6_port ) );
-       } else {
-               peeraddr = inet_ntop( AF_INET6,
-                                     &from.sa_in6_addr.sin6_addr,
-                                     addr, sizeof addr );
-               if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
-               sprintf( peername, "IP=[%s]:%d", peeraddr,
-                        (unsigned) ntohs( from.sa_in6_addr.sin6_port ) );
-       }
-       break;
 #  endif /* LDAP_PF_INET6 */
-
-       case AF_INET: {
-#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
-               peeraddr = inet_ntop( AF_INET, &from.sa_in_addr.sin_addr,
-                          addr, sizeof(addr) );
-#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
-               peeraddr = inet_ntoa( from.sa_in_addr.sin_addr );
-#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
-               if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
-               sprintf( peername, "IP=%s:%d", peeraddr,
-                       (unsigned) ntohs( from.sa_in_addr.sin_port ) );
-               } break;
+       case AF_INET:
+               slap_sockaddrstr( &from, &peerbv );
+               break;
 
        default:
                slapd_close(sfd);
index 470ebf31c581eb5de1d64db5a6e8e9f2f24303e1..cd509ccfa320ce913783a4f9e7e3f7b5dac31ad0 100644 (file)
@@ -893,6 +893,7 @@ LDAP_SLAPD_F (void) slap_resume_listeners LDAP_P((void));
 
 LDAP_SLAPD_F (int) slap_pause_server LDAP_P((void));
 LDAP_SLAPD_F (int) slap_unpause_server LDAP_P((void));
+LDAP_SLAPD_F (void) slap_sockaddrstr LDAP_P((Sockaddr *sa, struct berval *));
 
 LDAP_SLAPD_F (void) slapd_set_write LDAP_P((ber_socket_t s, int wake));
 LDAP_SLAPD_F (void) slapd_clr_write LDAP_P((ber_socket_t s, int wake));
index 69ee0338a509ed507e7be8451985b036ee098f32..73f1ed37b88166fbc6df4093508aa8cb237adec3 100644 (file)
@@ -2858,6 +2858,14 @@ typedef void (SEND_LDAP_INTERMEDIATE)(
 
 typedef struct Listener Listener;
 
+#ifdef LDAP_PF_LOCAL
+#define SLAP_ADDRLEN   (MAXPATHLEN + sizeof("PATH="))
+#elif defined(LDAP_PF_INET6)
+#define SLAP_ADDRLEN   sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")
+#else
+#define SLAP_ADDRLEN   sizeof("IP=255.255.255.255:65336")
+#endif
+
 /*
  * represents a connection from an ldap client
  */
index eb3eb2a07b1bd589b298ab74ceae7f027d26b993..62d345aacd2e2975d27d84c65329918107e956f2 100644 (file)
@@ -32,6 +32,9 @@
 #include "ldap_rq.h"
 
 #include "rewrite.h"
+
+#include "back-monitor/back-monitor.h"
+
 #define SUFFIXM_CTX    "<suffix massage>"
 
 #ifdef LDAP_CONTROL_X_DIRSYNC
@@ -152,8 +155,19 @@ typedef struct syncinfo_s {
 #ifdef LDAP_CONTROL_X_DIRSYNC
        struct berval           si_dirSyncCookie;
 #endif
-       unsigned long   si_prevchange;;
+       unsigned long   si_prevchange;
        unsigned long   si_lastchange;
+
+       /* monitor info */
+       int             si_monitorInited;
+       time_t  si_lastconnect;
+       time_t  si_lastcontact;
+       struct berval   *si_connaddr;
+       struct berval   si_lastCookieRcvd;
+       struct berval   si_lastCookieSent;
+       struct berval   si_monitor_ndn;
+
+       ldap_pvt_thread_mutex_t si_monitor_mutex;
        ldap_pvt_thread_mutex_t si_mutex;
 } syncinfo_t;
 
@@ -912,6 +926,8 @@ do_syncrep1(
        void    *ssl;
 #endif
 
+       si->si_lastconnect = slap_get_time();
+       si->si_refreshDone = 0;
        rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
        if ( rc != LDAP_SUCCESS ) {
                goto done;
@@ -1069,10 +1085,13 @@ do_syncrep1(
 
        }
 
-       si->si_refreshDone = 0;
        Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n",
                si->si_ridtxt, si->si_syncCookie.octet_str.bv_val );
 
+       ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
+       ber_bvreplace( &si->si_lastCookieSent, &si->si_syncCookie.octet_str );
+       ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
+
        rc = ldap_sync_search( si, op->o_tmpmemctx );
 
        if( rc != LDAP_SUCCESS ) {
@@ -1241,6 +1260,7 @@ do_syncrep2(
                        rc = SYNC_SHUTDOWN;
                        goto done;
                }
+               si->si_lastcontact = slap_get_time();
                switch( ldap_msgtype( msg ) ) {
                case LDAP_RES_SEARCH_ENTRY:
 #ifdef LDAP_CONTROL_X_DIRSYNC
@@ -1357,6 +1377,10 @@ do_syncrep2(
                                if ( !BER_BVISNULL( &cookie ) ) {
                                        ch_free( syncCookie.octet_str.bv_val );
                                        ber_dupbv( &syncCookie.octet_str, &cookie );
+
+                                       ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
+                                       ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
+                                       ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
                                }
                                if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                {
@@ -1571,6 +1595,10 @@ logerr:
                                        if ( !BER_BVISNULL( &cookie ) ) {
                                                ch_free( syncCookie.octet_str.bv_val );
                                                ber_dupbv( &syncCookie.octet_str, &cookie);
+
+                                               ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
+                                               ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
+                                               ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
                                        }
                                        if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                        {
@@ -1656,6 +1684,10 @@ logerr:
                                        if ( !BER_BVISNULL( &cookie ) ) {
                                                ch_free( syncCookie.octet_str.bv_val );
                                                ber_dupbv( &syncCookie.octet_str, &cookie );
+
+                                               ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
+                                               ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
+                                               ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
                                        }
                                        if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
                                                slap_parse_sync_cookie( &syncCookie, NULL );
@@ -1687,6 +1719,10 @@ logerr:
                                                if ( !BER_BVISNULL( &cookie ) ) {
                                                        ch_free( syncCookie.octet_str.bv_val );
                                                        ber_dupbv( &syncCookie.octet_str, &cookie );
+
+                                                       ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
+                                                       ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
+                                                       ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
                                                }
                                                if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                                {
@@ -1728,6 +1764,10 @@ logerr:
                                                if ( !BER_BVISNULL( &cookie ) ) {
                                                        ch_free( syncCookie.octet_str.bv_val );
                                                        ber_dupbv( &syncCookie.octet_str, &cookie );
+
+                                                       ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
+                                                       ber_bvreplace( &si->si_lastCookieRcvd, &cookie );
+                                                       ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
                                                }
                                                if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                                {
@@ -1868,6 +1908,12 @@ done:
        return rc;
 }
 
+static int
+syncrepl_monitor_add( syncinfo_t *si );
+
+static int
+syncrepl_monitor_del( syncinfo_t *si );
+
 static void *
 do_syncrepl(
        void    *ctx,
@@ -1889,6 +1935,11 @@ do_syncrepl(
        if ( slapd_shutdown )
                return NULL;
 
+       if ( !si->si_monitorInited ) {
+               syncrepl_monitor_add( si );
+               si->si_monitorInited = 1;
+       }
+
        Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt );
 
        /* Don't get stuck here while a pause is initiated */
@@ -1994,6 +2045,15 @@ reload:
        if ( rc == LDAP_SUCCESS ) {
                ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
 
+               if ( si->si_connaddr ) {
+                       Sockaddr addr;
+                       socklen_t len = sizeof( addr );
+                       if ( !getsockname( s, &addr.sa_addr, &len )) {
+                               si->si_connaddr->bv_len = SLAP_ADDRLEN;
+                               slap_sockaddrstr( &addr, si->si_connaddr );
+                       }
+               }
+
                /* use current DB */
                op->o_bd = be;
                op->o_dn = op->o_bd->be_rootdn;
@@ -5673,6 +5733,10 @@ syncinfo_free( syncinfo_t *sie, int free_all )
        do {
                si_next = sie->si_next;
 
+               if ( !BER_BVISEMPTY( &sie->si_monitor_ndn )) {
+                       syncrepl_monitor_del( sie );
+               }
+
                if ( sie->si_ld ) {
                        if ( sie->si_conn ) {
                                connection_client_stop( sie->si_conn );
@@ -5693,6 +5757,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                }
 
                ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
+               ldap_pvt_thread_mutex_destroy( &sie->si_monitor_mutex );
 
                bindconf_free( &sie->si_bindconf );
 
@@ -6462,6 +6527,402 @@ parse_syncrepl_line(
        return 0;
 }
 
+/* monitor entry contains:
+       provider URLs
+       timestamp of last contact
+       cookievals
+       */
+
+static ObjectClass     *oc_olmSyncRepl;
+static AttributeDescription    *ad_olmProviderURIList,
+       *ad_olmConnection, *ad_olmSyncPhase,
+       *ad_olmNextConnect, *ad_olmLastConnect, *ad_olmLastContact,
+       *ad_olmLastCookieRcvd, *ad_olmLastCookieSent;
+
+static struct {
+       char *name;
+       char *oid;
+} s_oid[] = {
+       { "olmSyncReplAttributes",      "olmOverlayAttributes:1" },
+       { "olmSyncReplObjectClasses", "olmOverlayObjectClasses:1" },
+       { NULL }
+};
+
+static struct {
+       char *desc;
+       AttributeDescription **ad;
+} s_at[] = {
+       { "( olmSyncReplAttributes:1 "
+               "NAME ( 'olmSRProviderURIList' ) "
+               "DESC 'List of provider URIs for this consumer instance' "
+               "SUP monitoredInfo "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmProviderURIList },
+       { "( olmSyncReplAttributes:2 "
+               "NAME ( 'olmSRConnection' ) "
+               "DESC 'Local address:port of connection to provider' "
+               "SUP monitoredInfo "
+               "SINGLE-VALUE "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmConnection },
+       { "( olmSyncReplAttributes:3 "
+               "NAME ( 'olmSRSyncPhase' ) "
+               "DESC 'Current syncrepl mode' "
+               "SUP monitoredInfo "
+               "SINGLE-VALUE "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmSyncPhase },
+       { "( olmSyncReplAttributes:4 "
+               "NAME ( 'olmSRNextConnect' ) "
+               "DESC 'Scheduled time of next connection attempt' "
+               "SUP monitorTimestamp "
+               "SINGLE-VALUE "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmNextConnect },
+       { "( olmSyncReplAttributes:5 "
+               "NAME ( 'olmSRLastConnect' ) "
+               "DESC 'Time last connected to provider' "
+               "SUP monitorTimestamp "
+               "SINGLE-VALUE "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmLastConnect },
+       { "( olmSyncReplAttributes:6 "
+               "NAME ( 'olmSRLastContact' ) "
+               "DESC 'Time last message received from provider' "
+               "SUP monitorTimestamp "
+               "SINGLE-VALUE "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmLastContact },
+       { "( olmSyncReplAttributes:7 "
+               "NAME ( 'olmSRLastCookieRcvd' ) "
+               "DESC 'Last sync cookie received from provider' "
+               "SUP monitoredInfo "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmLastCookieRcvd },
+       { "( olmSyncReplAttributes:8 "
+               "NAME ( 'olmSRLastCookieSent' ) "
+               "DESC 'Last sync cookie sent to provider' "
+               "SUP monitoredInfo "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )",
+               &ad_olmLastCookieSent },
+       { NULL }
+};
+
+static struct {
+       char *desc;
+       ObjectClass **oc;
+} s_oc[] = {
+       { "( olmSyncReplObjectClasses:1 "
+               "NAME ( 'olmSyncReplInstance' ) "
+               "SUP monitoredObject STRUCTURAL "
+               "MAY ( "
+                       "olmSRProviderURIList "
+                       "$ olmSRConnection "
+                       "$ olmSRSyncPhase "
+                       "$ olmSRNextConnect "
+                       "$ olmSRLastConnect "
+                       "$ olmSRLastContact "
+                       "$ olmSRLastCookieRcvd "
+                       "$ olmSRLastCookieSent "
+                       ") )",
+               &oc_olmSyncRepl },
+       { NULL }
+};
+
+static int
+syncrepl_monitor_initialized;
+
+int
+syncrepl_monitor_init( void )
+{
+       int i, code;
+
+       if ( syncrepl_monitor_initialized )
+               return 0;
+
+       if ( backend_info( "monitor" ) == NULL )
+               return -1;
+
+       {
+               ConfigArgs c;
+               char *argv[3];
+
+               argv[ 0 ] = "syncrepl monitor";
+               c.argv = argv;
+               c.argc = 2;
+               c.fname = argv[0];
+               for ( i=0; s_oid[i].name; i++ ) {
+                       argv[1] = s_oid[i].name;
+                       argv[2] = s_oid[i].oid;
+                       if ( parse_oidm( &c, 0, NULL )) {
+                               Debug( LDAP_DEBUG_ANY,
+                                       "syncrepl_monitor_init: unable to add "
+                                       "objectIdentifier \"%s=%s\"\n",
+                                       s_oid[i].name, s_oid[i].oid );
+                                       return 2;
+                       }
+               }
+       }
+
+       for ( i=0; s_at[i].desc != NULL; i++ ) {
+               code = register_at( s_at[i].desc, s_at[i].ad, 1 );
+               if ( code != LDAP_SUCCESS ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "syncrepl_monitor_init: register_at failed for attributeType (%s)\n",
+                               s_at[i].desc );
+                       return 3;
+               } else {
+                       (*s_at[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
+               }
+       }
+
+       for ( i=0; s_oc[i].desc != NULL; i++ ) {
+               code = register_oc( s_oc[i].desc, s_oc[i].oc, 1 );
+               if ( code != LDAP_SUCCESS ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "syncrepl_monitor_init: register_oc failed for objectClass (%s)\n",
+                               s_oc[i].desc );
+                       return 4;
+               } else {
+                       (*s_oc[i].oc)->soc_flags |= SLAP_OC_HIDE;
+               }
+       }
+       syncrepl_monitor_initialized = 1;
+
+       return 0;
+}
+
+static const struct berval zerotime = BER_BVC("00000101000000Z");
+
+static int
+syncrepl_monitor_update(
+       Operation *op,
+       SlapReply *rs,
+       Entry *e,
+       void *priv )
+{
+       syncinfo_t *si = (syncinfo_t *)priv;
+       Attribute *a;
+       int isConnected = 0;
+
+       a = attr_find( e->e_attrs, ad_olmConnection );
+       if ( !a )
+               return SLAP_CB_CONTINUE;
+       if ( si->si_ld ) {
+               isConnected = 1;
+       } else {
+               a->a_vals[0].bv_val[0] = '\0';
+               a->a_vals[0].bv_len = 0;
+       }
+
+       a = a->a_next;
+       if ( a->a_desc != ad_olmSyncPhase )
+               return SLAP_CB_CONTINUE;
+
+       if ( si->si_refreshDone ) {
+               struct berval bv = BER_BVC("Persist");
+               ber_bvreplace( &a->a_vals[0], &bv );
+       } else {
+               if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
+                       struct berval bv = BER_BVC("Fallback Refresh");
+                       ber_bvreplace( &a->a_vals[0], &bv );
+               } else {
+                       struct berval bv = BER_BVC("Refresh");
+                       ber_bvreplace( &a->a_vals[0], &bv );
+               }
+       }
+
+       {
+               struct tm tm;
+               char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+               ber_len_t len;
+
+               a = a->a_next;
+               if ( a->a_desc != ad_olmNextConnect )
+                       return SLAP_CB_CONTINUE;
+
+               if ( !isConnected && si->si_re && si->si_re->next_sched.tv_sec ) {
+                       time_t next_sched = si->si_re->next_sched.tv_sec;
+                       ldap_pvt_gmtime( &next_sched, &tm );
+                       lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
+                       len = strlen( tmbuf );
+                       assert( len == a->a_vals[0].bv_len );
+                       AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
+               } else {
+                       AC_MEMCPY( a->a_vals[0].bv_val, zerotime.bv_val, zerotime.bv_len );
+               }
+
+               a = a->a_next;
+               if ( a->a_desc != ad_olmLastConnect )
+                       return SLAP_CB_CONTINUE;
+
+               if ( si->si_lastconnect ) {
+                       ldap_pvt_gmtime( &si->si_lastconnect, &tm );
+                       lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
+                       len = strlen( tmbuf );
+                       assert( len == a->a_vals[0].bv_len );
+                       AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
+               }
+
+               a = a->a_next;
+               if ( a->a_desc != ad_olmLastContact )
+                       return SLAP_CB_CONTINUE;
+
+               if ( si->si_lastcontact ) {
+                       ldap_pvt_gmtime( &si->si_lastcontact, &tm );
+                       lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );
+                       len = strlen( tmbuf );
+                       assert( len == a->a_vals[0].bv_len );
+                       AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len );
+               }
+       }
+
+       a = a->a_next;
+       if ( a->a_desc != ad_olmLastCookieRcvd )
+               return SLAP_CB_CONTINUE;
+
+       ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex );
+       if ( !BER_BVISEMPTY( &si->si_lastCookieRcvd ) &&
+               !bvmatch( &a->a_vals[0], &si->si_lastCookieRcvd ))
+               ber_bvreplace( &a->a_vals[0], &si->si_lastCookieRcvd );
+
+       a = a->a_next;
+       if ( a->a_desc != ad_olmLastCookieSent ) {
+               ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
+               return SLAP_CB_CONTINUE;
+       }
+
+       if ( !BER_BVISEMPTY( &si->si_lastCookieSent ) &&
+               !bvmatch( &a->a_vals[0], &si->si_lastCookieSent ))
+               ber_bvreplace( &a->a_vals[0], &si->si_lastCookieSent );
+       ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex );
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+syncrepl_monitor_add(
+       syncinfo_t *si
+)
+{
+       BackendInfo *mi;
+       monitor_extra_t *mbe;
+       struct berval pndn, pdn, rdn, bv;
+       char rdnbuf[sizeof("cn=Consumer 999")];
+       Entry *e, *p;
+       int rc;
+
+       if ( !syncrepl_monitor_initialized )
+               return -1;
+
+       mi = backend_info( "monitor" );
+       if ( !mi || !mi->bi_extra ) {
+               SLAP_DBFLAGS( si->si_be ) ^= SLAP_DBFLAG_MONITORING;
+               return 0;
+       }
+       mbe = mi->bi_extra;
+
+       if ( !mbe->is_configured() ) {
+               return 0;
+       }
+
+       rc = mbe->register_database( si->si_be, &pndn );
+       if ( rc ) {
+               Debug( LDAP_DEBUG_ANY, "syncrepl_monitor_add: "
+                       "failed to register the database with back-monitor\n" );
+               return rc;
+       }
+       rdn.bv_len = sprintf(rdnbuf, "cn=Consumer %03d", si->si_rid );
+       rdn.bv_val = rdnbuf;
+       p = mbe->entry_get_unlocked( &pndn );
+       if ( p ) {
+               pdn = p->e_name;
+       } else {
+               pdn = pndn;
+       }
+
+       e = mbe->entry_stub( &pdn, &pndn, &rdn,
+               oc_olmSyncRepl, NULL, NULL );
+       if ( e == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "syncrepl_monitor_add: "
+                       "unable to create entry \"%s,%s\"\n",
+                       rdn.bv_val, pndn.bv_val );
+               return -1;
+       }
+
+       attr_merge_normalize_one( e, ad_olmProviderURIList,
+               &si->si_bindconf.sb_uri, NULL );
+
+       {
+               char addrbuf[SLAP_ADDRLEN];
+               struct berval bv = BER_BVC(addrbuf);
+               addrbuf[0] = '\0';
+               attr_merge_normalize_one( e, ad_olmConnection, &bv, NULL );
+       }
+       {
+               struct berval bv = BER_BVC("Refresh");
+               attr_merge_normalize_one( e, ad_olmSyncPhase, &bv, NULL );
+       }
+       {
+               attr_merge_normalize_one( e, ad_olmNextConnect, (struct berval *)&zerotime, NULL );
+               attr_merge_normalize_one( e, ad_olmLastConnect, (struct berval *)&zerotime, NULL );
+               attr_merge_normalize_one( e, ad_olmLastContact, (struct berval *)&zerotime, NULL );
+       }
+       {
+               struct berval bv = BER_BVC("");
+               attr_merge_normalize_one( e, ad_olmLastCookieRcvd, &bv, NULL );
+               attr_merge_normalize_one( e, ad_olmLastCookieSent, &bv, NULL );
+       }
+       {
+               monitor_callback_t *cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
+               cb->mc_update = syncrepl_monitor_update;
+               cb->mc_private = si;
+               rc = mbe->register_entry( e, cb, NULL, 0 );
+       }
+
+       p = mbe->entry_get_unlocked( &e->e_nname );
+       if ( p ) {
+               Attribute *a = attr_find( p->e_attrs, ad_olmConnection );
+               if ( a ) {
+                       si->si_connaddr = &a->a_vals[0];
+                       a->a_vals[0].bv_len = 0;
+               }
+       }
+
+       si->si_monitor_ndn = e->e_nname;
+       BER_BVZERO( &e->e_nname );
+       entry_free( e );
+
+       return rc;
+}
+
+static int
+syncrepl_monitor_del(
+       syncinfo_t *si
+)
+{
+       BackendInfo *mi;
+
+       mi = backend_info( "monitor" );
+       if ( mi && mi->bi_extra ) {
+               monitor_extra_t *mbe = mi->bi_extra;
+               mbe->unregister_entry( &si->si_monitor_ndn );
+       }
+       ch_free( si->si_lastCookieSent.bv_val );
+       ch_free( si->si_lastCookieRcvd.bv_val );
+       ch_free( si->si_monitor_ndn.bv_val );
+       return 0;
+}
+
 static int
 add_syncrepl(
        ConfigArgs *c )
@@ -6512,6 +6973,7 @@ add_syncrepl(
 
        si->si_presentlist = NULL;
        LDAP_LIST_INIT( &si->si_nonpresentlist );
+       ldap_pvt_thread_mutex_init( &si->si_monitor_mutex );
        ldap_pvt_thread_mutex_init( &si->si_mutex );
 
        rc = parse_syncrepl_line( c, si );