snmp_collator.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <sys/ipc.h>
  17. #include <sys/msg.h>
  18. #include <dirent.h>
  19. #include <semaphore.h>
  20. #include <time.h>
  21. #include <signal.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include "agtmmap.h"
  25. #include "slap.h"
  26. #include "prthread.h"
  27. #include "prlock.h"
  28. #include "prerror.h"
  29. #include "prcvar.h"
  30. #include "plstr.h"
  31. #ifdef HPUX
  32. /* HP-UX doesn't define SEM_FAILED like other platforms, so
  33. * we define it ourselves. */
  34. #define SEM_FAILED ((sem_t *)(-1))
  35. #endif
  36. #define SNMP_NUM_SEM_WAITS 10
  37. #include "snmp_collator.h"
  38. /* stevross: safe to assume port should be at most 5 digits ? */
  39. #define PORT_LEN 5
  40. /* strlen of url portions ie "ldap://:/" */
  41. #define URL_CHARS_LEN 9
  42. static char *make_ds_url(char *host, int port);
  43. #ifdef DEBUG_SNMP_INTERACTION
  44. static void print_snmp_interaction_table();
  45. #endif /* DEBUG_SNMP_INTERACTION */
  46. static int search_interaction_table(char *dsURL, int *isnew);
  47. static void loadConfigStats(void);
  48. static Slapi_Entry *getConfigEntry( Slapi_Entry **e );
  49. static void freeConfigEntry( Slapi_Entry **e );
  50. static void snmp_update_ops_table(void);
  51. static void snmp_update_entries_table(void);
  52. static void snmp_update_interactions_table(void);
  53. static void snmp_update_cache_stats(void);
  54. static void snmp_collator_create_semaphore(void);
  55. static void snmp_collator_sem_wait(void);
  56. /* snmp stats stuff */
  57. struct agt_stats_t *stats=NULL;
  58. /* mmap stuff */
  59. static int hdl;
  60. /* collator stuff */
  61. static char *tmpstatsfile = AGT_STATS_FILE;
  62. static char szStatsFile[_MAX_PATH];
  63. static char stats_sem_name[_MAX_PATH];
  64. static Slapi_Eq_Context snmp_eq_ctx;
  65. static int snmp_collator_stopped = 0;
  66. /* synchronization stuff */
  67. static Slapi_Mutex *interaction_table_mutex = NULL;
  68. static sem_t *stats_sem = NULL;
  69. /***********************************************************************************
  70. *
  71. * int snmp_collator_init()
  72. *
  73. * initializes the global variables used by snmp
  74. *
  75. ************************************************************************************/
  76. static int
  77. snmp_collator_init(void)
  78. {
  79. int i;
  80. /*
  81. * Create the global SNMP counters
  82. */
  83. g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds = slapi_counter_new();
  84. g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds = slapi_counter_new();
  85. g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds = slapi_counter_new();
  86. g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds = slapi_counter_new();
  87. g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors = slapi_counter_new();
  88. g_get_global_snmp_vars()->ops_tbl.dsInOps = slapi_counter_new();
  89. g_get_global_snmp_vars()->ops_tbl.dsReadOps = slapi_counter_new();
  90. g_get_global_snmp_vars()->ops_tbl.dsCompareOps = slapi_counter_new();
  91. g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps = slapi_counter_new();
  92. g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps = slapi_counter_new();
  93. g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps = slapi_counter_new();
  94. g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps = slapi_counter_new();
  95. g_get_global_snmp_vars()->ops_tbl.dsListOps = slapi_counter_new();
  96. g_get_global_snmp_vars()->ops_tbl.dsSearchOps = slapi_counter_new();
  97. g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps = slapi_counter_new();
  98. g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps = slapi_counter_new();
  99. g_get_global_snmp_vars()->ops_tbl.dsReferrals = slapi_counter_new();
  100. g_get_global_snmp_vars()->ops_tbl.dsChainings = slapi_counter_new();
  101. g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors = slapi_counter_new();
  102. g_get_global_snmp_vars()->ops_tbl.dsErrors = slapi_counter_new();
  103. g_get_global_snmp_vars()->ops_tbl.dsConnections = slapi_counter_new();
  104. g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq = slapi_counter_new();
  105. g_get_global_snmp_vars()->ops_tbl.dsBytesRecv = slapi_counter_new();
  106. g_get_global_snmp_vars()->ops_tbl.dsBytesSent = slapi_counter_new();
  107. g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned = slapi_counter_new();
  108. g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned = slapi_counter_new();
  109. g_get_global_snmp_vars()->ops_tbl.dsConnectionsInMaxThreads = slapi_counter_new();
  110. g_get_global_snmp_vars()->ops_tbl.dsMaxThreadsHit = slapi_counter_new();
  111. g_get_global_snmp_vars()->entries_tbl.dsMasterEntries = slapi_counter_new();
  112. g_get_global_snmp_vars()->entries_tbl.dsCopyEntries = slapi_counter_new();
  113. g_get_global_snmp_vars()->entries_tbl.dsCacheEntries = slapi_counter_new();
  114. g_get_global_snmp_vars()->entries_tbl.dsCacheHits = slapi_counter_new();
  115. g_get_global_snmp_vars()->entries_tbl.dsSlaveHits = slapi_counter_new();
  116. /* Initialize the global interaction table */
  117. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
  118. {
  119. g_get_global_snmp_vars()->int_tbl[i].dsIntIndex = i + 1;
  120. strncpy(g_get_global_snmp_vars()->int_tbl[i].dsName, "Not Available",
  121. sizeof(g_get_global_snmp_vars()->int_tbl[i].dsName));
  122. g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation = 0;
  123. g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt = 0;
  124. g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess = 0;
  125. g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess = 0;
  126. g_get_global_snmp_vars()->int_tbl[i].dsFailures = 0;
  127. g_get_global_snmp_vars()->int_tbl[i].dsSuccesses = 0;
  128. strncpy(g_get_global_snmp_vars()->int_tbl[i].dsURL, "Not Available",
  129. sizeof(g_get_global_snmp_vars()->int_tbl[i].dsURL));
  130. }
  131. /* Get the semaphore */
  132. snmp_collator_sem_wait();
  133. /* Initialize the mmap structure */
  134. memset((void *) stats, 0, sizeof(*stats));
  135. /* Load header stats table */
  136. strncpy(stats->hdr_stats.dsVersion, SLAPD_VERSION_STR,
  137. (sizeof(stats->hdr_stats.dsVersion)/sizeof(char)) - 1);
  138. stats->hdr_stats.restarted = 0;
  139. stats->hdr_stats.startTime = time(0); /* This is a bit off, hope it's ok */
  140. loadConfigStats();
  141. /* update the mmap'd tables */
  142. snmp_update_ops_table();
  143. snmp_update_entries_table();
  144. snmp_update_interactions_table();
  145. /* Release the semaphore */
  146. sem_post(stats_sem);
  147. /* create lock for interaction table */
  148. if (!interaction_table_mutex) {
  149. interaction_table_mutex = slapi_new_mutex();
  150. }
  151. return 0;
  152. }
  153. /***********************************************************************************
  154. * given the name, whether or not it was successful and the URL updates snmp
  155. * interaction table appropriately
  156. *
  157. *
  158. ************************************************************************************/
  159. void set_snmp_interaction_row(char *host, int port, int error)
  160. {
  161. int index;
  162. int isnew = 0;
  163. char *dsName;
  164. char *dsURL;
  165. /* stevross: our servers don't have a concept of dsName as a distinguished name
  166. as specified in the MIB. Make this "Not Available" for now waiting for
  167. sometime in the future when we do
  168. */
  169. dsName = "Not Available";
  170. dsURL= make_ds_url(host, port);
  171. /* lock around here to avoid race condition of two threads trying to update table at same time */
  172. slapi_lock_mutex(interaction_table_mutex);
  173. index = search_interaction_table(dsURL, &isnew);
  174. if(isnew){
  175. /* fillin the new row from scratch*/
  176. g_get_global_snmp_vars()->int_tbl[index].dsIntIndex = index;
  177. strncpy(g_get_global_snmp_vars()->int_tbl[index].dsName, dsName,
  178. sizeof(g_get_global_snmp_vars()->int_tbl[index].dsName));
  179. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfCreation = time(0);
  180. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastAttempt = time(0);
  181. if(error == 0){
  182. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess = time(0);
  183. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess = 0;
  184. g_get_global_snmp_vars()->int_tbl[index].dsFailures = 0;
  185. g_get_global_snmp_vars()->int_tbl[index].dsSuccesses = 1;
  186. } else {
  187. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess = 0;
  188. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess = 1;
  189. g_get_global_snmp_vars()->int_tbl[index].dsFailures = 1;
  190. g_get_global_snmp_vars()->int_tbl[index].dsSuccesses = 0;
  191. }
  192. strncpy(g_get_global_snmp_vars()->int_tbl[index].dsURL, dsURL,
  193. sizeof(g_get_global_snmp_vars()->int_tbl[index].dsURL));
  194. } else {
  195. /* just update the appropriate fields */
  196. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastAttempt = time(0);
  197. if(error == 0){
  198. g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess = time(0);
  199. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess = 0;
  200. g_get_global_snmp_vars()->int_tbl[index].dsSuccesses += 1;
  201. }else{
  202. g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess +=1;
  203. g_get_global_snmp_vars()->int_tbl[index].dsFailures +=1;
  204. }
  205. }
  206. slapi_unlock_mutex(interaction_table_mutex);
  207. /* free the memory allocated for dsURL in call to ds_make_url */
  208. if(dsURL != NULL){
  209. slapi_ch_free( (void**)&dsURL );
  210. }
  211. }
  212. /***********************************************************************************
  213. * Given: host and port
  214. * Returns: ldapUrl in form of
  215. * ldap://host.mcom.com:port/
  216. *
  217. * this should point to root DSE
  218. ************************************************************************************/
  219. static char *make_ds_url(char *host, int port)
  220. {
  221. char *url;
  222. url = slapi_ch_smprintf("ldap://%s:%d/",host, port);
  223. return url;
  224. }
  225. /***********************************************************************************
  226. * search_interaction_table is not used.
  227. * searches the table for the url specified
  228. * If there, returns index to update stats
  229. * if, not there returns index of oldest interaction, and isnew flag is set
  230. * so caller can rewrite this row
  231. ************************************************************************************/
  232. static int search_interaction_table(char *dsURL, int *isnew)
  233. {
  234. int i;
  235. int index = 0;
  236. time_t oldestattempt;
  237. time_t currentattempt;
  238. oldestattempt = g_get_global_snmp_vars()->int_tbl[0].dsTimeOfLastAttempt;
  239. *isnew = 1;
  240. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++){
  241. if(!strcmp(g_get_global_snmp_vars()->int_tbl[i].dsURL, "Not Available"))
  242. {
  243. /* found it -- this is new, first time for this row */
  244. index = i;
  245. break;
  246. } else if(!strcmp(g_get_global_snmp_vars()->int_tbl[i].dsURL, dsURL)){
  247. /* found it -- it was already there*/
  248. *isnew = 0;
  249. index = i;
  250. break;
  251. } else {
  252. /* not found so figure out oldest row */
  253. currentattempt = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt;
  254. if(currentattempt <= oldestattempt){
  255. index=i;
  256. oldestattempt = currentattempt;
  257. }
  258. }
  259. }
  260. return index;
  261. }
  262. #ifdef DEBUG_SNMP_INTERACTION
  263. /* for debuging until subagent part working, print contents of interaction table */
  264. static void print_snmp_interaction_table()
  265. {
  266. int i;
  267. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
  268. {
  269. fprintf(stderr, " dsIntIndex: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsIntIndex);
  270. fprintf(stderr, " dsName: %s \n", g_get_global_snmp_vars()->int_tbl[i].dsName);
  271. fprintf(stderr, " dsTimeOfCreation: %ld \n", g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation);
  272. fprintf(stderr, " dsTimeOfLastAttempt: %ld \n", g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt);
  273. fprintf(stderr, " dsTimeOfLastSuccess: %ld \n", g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess);
  274. fprintf(stderr, "dsFailuresSinceLastSuccess: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess);
  275. fprintf(stderr, " dsFailures: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsFailures);
  276. fprintf(stderr, " dsSuccesses: %d \n", g_get_global_snmp_vars()->int_tbl[i].dsSuccesses);
  277. fprintf(stderr, " dsURL: %s \n", g_get_global_snmp_vars()->int_tbl[i].dsURL);
  278. fprintf(stderr, "\n");
  279. }
  280. }
  281. #endif /* DEBUG_SNMP_INTERACTION */
  282. /***********************************************************************************
  283. *
  284. * int snmp_collator_start()
  285. *
  286. * open the memory map and initialize the variables
  287. * initializes the global variables used by snmp
  288. *
  289. * starts the collator thread
  290. ************************************************************************************/
  291. int snmp_collator_start()
  292. {
  293. int err;
  294. char *statspath = config_get_rundir();
  295. char *instdir = config_get_configdir();
  296. char *instname = NULL;
  297. /*
  298. * Get directory for our stats file
  299. */
  300. if (NULL == statspath) {
  301. statspath = slapi_ch_strdup("/tmp");
  302. }
  303. instname = PL_strrstr(instdir, "slapd-");
  304. if (!instname) {
  305. instname = PL_strrstr(instdir, "/");
  306. if (instname) {
  307. instname++;
  308. }
  309. }
  310. PR_snprintf(szStatsFile, sizeof(szStatsFile), "%s/%s%s",
  311. statspath, instname, AGT_STATS_EXTENSION);
  312. PR_snprintf(stats_sem_name, sizeof(stats_sem_name), "/%s%s",
  313. instname, AGT_STATS_EXTENSION);
  314. tmpstatsfile = szStatsFile;
  315. slapi_ch_free_string(&statspath);
  316. slapi_ch_free_string(&instdir);
  317. /* open the memory map */
  318. if ((err = agt_mopen_stats(tmpstatsfile, O_RDWR, &hdl) != 0))
  319. {
  320. if (err != EEXIST) /* Ignore if file already exists */
  321. {
  322. slapi_log_err(SLAPI_LOG_EMERG, "snmp collator", "Failed to open stats file (%s) "
  323. "(error %d): %s.\n", szStatsFile, err, slapd_system_strerror(err));
  324. exit(1);
  325. }
  326. }
  327. /* Create semaphore for stats file access */
  328. snmp_collator_create_semaphore();
  329. /* point stats struct at mmap data */
  330. stats = (struct agt_stats_t *) mmap_tbl [hdl].fp;
  331. /* initialize stats data */
  332. snmp_collator_init();
  333. /* Arrange to be called back periodically to update the mmap'd stats file. */
  334. snmp_eq_ctx = slapi_eq_repeat(snmp_collator_update, NULL, (time_t)0,
  335. SLAPD_SNMP_UPDATE_INTERVAL);
  336. return 0;
  337. }
  338. /***********************************************************************************
  339. *
  340. * int snmp_collator_stop()
  341. *
  342. * stops the collator thread
  343. * closes the memory map
  344. * cleans up any needed memory
  345. *
  346. ************************************************************************************/
  347. int snmp_collator_stop()
  348. {
  349. int err;
  350. if (snmp_collator_stopped) {
  351. return 0;
  352. }
  353. /* Abort any pending events */
  354. slapi_eq_cancel(snmp_eq_ctx);
  355. snmp_collator_stopped = 1;
  356. /* acquire the semaphore */
  357. snmp_collator_sem_wait();
  358. /* close the memory map */
  359. if ((err = agt_mclose_stats(hdl)) != 0)
  360. {
  361. fprintf(stderr, "Failed to close stats file (%s) (error = %d).",
  362. AGT_STATS_FILE, err);
  363. }
  364. if (remove(tmpstatsfile) != 0)
  365. {
  366. fprintf(stderr, "Failed to remove (%s) (error = %d).\n",
  367. tmpstatsfile, errno);
  368. }
  369. /* close and delete semaphore */
  370. sem_close(stats_sem);
  371. sem_unlink(stats_sem_name);
  372. /* delete lock */
  373. slapi_destroy_mutex(interaction_table_mutex);
  374. /* stevross: I probably need to free stats too... make sure to add that later */
  375. return 0;
  376. }
  377. /*
  378. * snmp_collator_create_semaphore()
  379. *
  380. * Create a semaphore to synchronize access to the stats file with
  381. * the SNMP sub-agent. NSPR doesn't support a trywait function
  382. * for semaphores, so we just use POSIX semaphores directly.
  383. */
  384. static void
  385. snmp_collator_create_semaphore(void)
  386. {
  387. /* First just try to create the semaphore. This should usually just work. */
  388. if ((stats_sem = sem_open(stats_sem_name, O_CREAT | O_EXCL, SLAPD_DEFAULT_FILE_MODE, 1)) == SEM_FAILED) {
  389. if (errno == EEXIST) {
  390. /* It appears that we didn't exit cleanly last time and left the semaphore
  391. * around. Recreate it since we don't know what state it is in. */
  392. if (sem_unlink(stats_sem_name) != 0) {
  393. slapi_log_err(SLAPI_LOG_EMERG, "snmp_collator_create_semaphore",
  394. "Failed to delete old semaphore for stats file (%s). "
  395. "Error %d (%s).\n", szStatsFile, errno, slapd_system_strerror(errno) );
  396. exit(1);
  397. }
  398. if ((stats_sem = sem_open(stats_sem_name, O_CREAT | O_EXCL, SLAPD_DEFAULT_FILE_MODE, 1)) == SEM_FAILED) {
  399. /* No dice */
  400. slapi_log_err(SLAPI_LOG_EMERG, "snmp_collator_create_semaphore",
  401. "Failed to create semaphore for stats file (%s). Error %d (%s).\n",
  402. szStatsFile, errno, slapd_system_strerror(errno) );
  403. exit(1);
  404. }
  405. } else {
  406. /* Some other problem occurred creating the semaphore. */
  407. slapi_log_err(SLAPI_LOG_EMERG, "snmp_collator_create_semaphore",
  408. "Failed to create semaphore for stats file (%s). Error %d.(%s)\n",
  409. szStatsFile, errno, slapd_system_strerror(errno) );
  410. exit(1);
  411. }
  412. }
  413. /* If we've reached this point, everything should be good. */
  414. return;
  415. }
  416. /*
  417. * snmp_collator_sem_wait()
  418. *
  419. * A wrapper used to get the semaphore. We don't want to block,
  420. * but we want to retry a specified number of times in case the
  421. * semaphore is help by the sub-agent.
  422. */
  423. static void
  424. snmp_collator_sem_wait(void)
  425. {
  426. int i = 0;
  427. int got_sem = 0;
  428. if (SEM_FAILED == stats_sem) {
  429. slapi_log_err(SLAPI_LOG_ERR,
  430. "snmp_collator_sem_wait", "semaphore for stats file (%s) is not available.\n", szStatsFile);
  431. return;
  432. }
  433. for (i=0; i < SNMP_NUM_SEM_WAITS; i++) {
  434. if (sem_trywait(stats_sem) == 0) {
  435. got_sem = 1;
  436. break;
  437. }
  438. PR_Sleep(PR_SecondsToInterval(1));
  439. }
  440. if (!got_sem) {
  441. /* If we've been unable to get the semaphore, there's
  442. * something wrong (likely the sub-agent went out to
  443. * lunch). We remove the old semaphore and recreate
  444. * a new one to avoid hanging up the server. */
  445. sem_close(stats_sem);
  446. sem_unlink(stats_sem_name);
  447. snmp_collator_create_semaphore();
  448. }
  449. }
  450. /***********************************************************************************
  451. *
  452. * int snmp_collator_update()
  453. *
  454. * Event callback function that updates the mmap'd stats file
  455. * for the SNMP sub-agent. This will use a semaphore while
  456. * updating the stats file to prevent the SNMP sub-agent from
  457. * reading it in the middle of an update.
  458. *
  459. ************************************************************************************/
  460. void
  461. snmp_collator_update(time_t start_time, void *arg)
  462. {
  463. if (snmp_collator_stopped) {
  464. return;
  465. }
  466. /* force an update of the backend cache stats. */
  467. snmp_update_cache_stats();
  468. /* get the semaphore */
  469. snmp_collator_sem_wait();
  470. /* just update the update time in the header */
  471. if( stats != NULL){
  472. stats->hdr_stats.updateTime = time(0);
  473. }
  474. /* update the mmap'd tables */
  475. snmp_update_ops_table();
  476. snmp_update_entries_table();
  477. snmp_update_interactions_table();
  478. /* release the semaphore */
  479. sem_post(stats_sem);
  480. }
  481. /*
  482. * snmp_update_ops_table()
  483. *
  484. * Updates the mmap'd operations table. The semaphore
  485. * should be acquired before you call this.
  486. */
  487. static void
  488. snmp_update_ops_table(void)
  489. {
  490. stats->ops_stats.dsAnonymousBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
  491. stats->ops_stats.dsUnAuthBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
  492. stats->ops_stats.dsSimpleAuthBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds);
  493. stats->ops_stats.dsStrongAuthBinds = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds);
  494. stats->ops_stats.dsBindSecurityErrors = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
  495. stats->ops_stats.dsInOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsInOps);
  496. stats->ops_stats.dsReadOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReadOps);
  497. stats->ops_stats.dsCompareOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsCompareOps);
  498. stats->ops_stats.dsAddEntryOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps);
  499. stats->ops_stats.dsRemoveEntryOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps);
  500. stats->ops_stats.dsModifyEntryOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps);
  501. stats->ops_stats.dsModifyRDNOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps);
  502. stats->ops_stats.dsListOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsListOps);
  503. stats->ops_stats.dsSearchOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSearchOps);
  504. stats->ops_stats.dsOneLevelSearchOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps);
  505. stats->ops_stats.dsWholeSubtreeSearchOps = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps);
  506. stats->ops_stats.dsReferrals = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferrals);
  507. stats->ops_stats.dsChainings = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsChainings);
  508. stats->ops_stats.dsSecurityErrors = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors);
  509. stats->ops_stats.dsErrors = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsErrors);
  510. stats->ops_stats.dsConnections = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnections);
  511. stats->ops_stats.dsConnectionSeq = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq);
  512. stats->ops_stats.dsConnectionsInMaxThreads = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionsInMaxThreads);
  513. stats->ops_stats.dsMaxThreadsHit = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsMaxThreadsHit);
  514. stats->ops_stats.dsBytesRecv = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesRecv);
  515. stats->ops_stats.dsBytesSent = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesSent);
  516. stats->ops_stats.dsEntriesReturned = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned);
  517. stats->ops_stats.dsReferralsReturned = slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned);
  518. }
  519. /*
  520. * snmp_update_entries_table()
  521. *
  522. * Updated the mmap'd entries table. The semaphore should
  523. * be acquired before you call this.
  524. */
  525. static void
  526. snmp_update_entries_table(void)
  527. {
  528. stats->entries_stats.dsMasterEntries = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsMasterEntries);
  529. stats->entries_stats.dsCopyEntries = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCopyEntries);
  530. stats->entries_stats.dsCacheEntries = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries);
  531. stats->entries_stats.dsCacheHits = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheHits);
  532. stats->entries_stats.dsSlaveHits = slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsSlaveHits);
  533. }
  534. /*
  535. * snmp_update_interactions_table()
  536. *
  537. * Updates the mmap'd interactions table. The semaphore should
  538. * be acquired before you call this.
  539. */
  540. static void
  541. snmp_update_interactions_table(void)
  542. {
  543. int i;
  544. for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++) {
  545. stats->int_stats[i].dsIntIndex = i;
  546. strncpy(stats->int_stats[i].dsName, g_get_global_snmp_vars()->int_tbl[i].dsName,
  547. sizeof(stats->int_stats[i].dsName));
  548. stats->int_stats[i].dsTimeOfCreation = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation;
  549. stats->int_stats[i].dsTimeOfLastAttempt = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt;
  550. stats->int_stats[i].dsTimeOfLastSuccess = g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess;
  551. stats->int_stats[i].dsFailuresSinceLastSuccess = g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess;
  552. stats->int_stats[i].dsFailures = g_get_global_snmp_vars()->int_tbl[i].dsFailures;
  553. stats->int_stats[i].dsSuccesses = g_get_global_snmp_vars()->int_tbl[i].dsSuccesses;
  554. strncpy(stats->int_stats[i].dsURL, g_get_global_snmp_vars()->int_tbl[i].dsURL,
  555. sizeof(stats->int_stats[i].dsURL));
  556. }
  557. }
  558. /*
  559. * snmp_update_cache_stats()
  560. *
  561. * Reads the backend cache stats from the backend monitor entry and
  562. * updates the global counter used by the SNMP sub-agent as well as
  563. * the SNMP monitor entry.
  564. */
  565. static void
  566. snmp_update_cache_stats(void)
  567. {
  568. Slapi_Backend *be, *be_next;
  569. char *cookie = NULL;
  570. Slapi_PBlock *search_result_pb = NULL;
  571. Slapi_Entry **search_entries;
  572. int search_result;
  573. /* set the cache hits/cache entries info */
  574. be = slapi_get_first_backend(&cookie);
  575. if (!be){
  576. slapi_ch_free ((void **) &cookie);
  577. return;
  578. }
  579. be_next = slapi_get_next_backend(cookie);
  580. slapi_ch_free ((void **) &cookie);
  581. /* for now, only do it if there is only 1 backend, otherwise don't know
  582. * which backend to pick */
  583. if(be_next == NULL)
  584. {
  585. Slapi_DN monitordn;
  586. slapi_sdn_init(&monitordn);
  587. be_getmonitordn(be,&monitordn);
  588. /* do a search on the monitor dn to get info */
  589. search_result_pb = slapi_search_internal( slapi_sdn_get_dn(&monitordn),
  590. LDAP_SCOPE_BASE,
  591. "objectclass=*",
  592. NULL,
  593. NULL,
  594. 0);
  595. slapi_sdn_done(&monitordn);
  596. slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
  597. if(search_result == 0)
  598. {
  599. slapi_pblock_get( search_result_pb,SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  600. &search_entries);
  601. /* set the entrycachehits */
  602. slapi_counter_set_value(g_get_global_snmp_vars()->entries_tbl.dsCacheHits,
  603. slapi_entry_attr_get_ulonglong(search_entries[0], "entrycachehits"));
  604. /* set the currententrycachesize */
  605. slapi_counter_set_value(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries,
  606. slapi_entry_attr_get_ulonglong(search_entries[0], "currententrycachesize"));
  607. }
  608. slapi_free_search_results_internal(search_result_pb);
  609. slapi_pblock_destroy(search_result_pb);
  610. }
  611. }
  612. static void
  613. add_counter_to_value(Slapi_Entry *e, const char *type, PRUint64 countervalue)
  614. {
  615. char value[40];
  616. PR_snprintf(value,sizeof(value),"%" NSPRIu64, countervalue);
  617. slapi_entry_attr_set_charptr( e, type, value);
  618. }
  619. void
  620. snmp_as_entry(Slapi_Entry *e)
  621. {
  622. add_counter_to_value(e,"AnonymousBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds));
  623. add_counter_to_value(e,"UnAuthBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds));
  624. add_counter_to_value(e,"SimpleAuthBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds));
  625. add_counter_to_value(e,"StrongAuthBinds", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds));
  626. add_counter_to_value(e,"BindSecurityErrors", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors));
  627. add_counter_to_value(e,"InOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsInOps));
  628. add_counter_to_value(e,"ReadOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReadOps));
  629. add_counter_to_value(e,"CompareOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsCompareOps));
  630. add_counter_to_value(e,"AddEntryOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps));
  631. add_counter_to_value(e,"RemoveEntryOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps));
  632. add_counter_to_value(e,"ModifyEntryOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps));
  633. add_counter_to_value(e,"ModifyRDNOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps));
  634. add_counter_to_value(e,"ListOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsListOps));
  635. add_counter_to_value(e,"SearchOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSearchOps));
  636. add_counter_to_value(e,"OneLevelSearchOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps));
  637. add_counter_to_value(e,"WholeSubtreeSearchOps", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps));
  638. add_counter_to_value(e,"Referrals", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferrals));
  639. add_counter_to_value(e,"Chainings", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsChainings));
  640. add_counter_to_value(e,"SecurityErrors", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors));
  641. add_counter_to_value(e,"Errors", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsErrors));
  642. add_counter_to_value(e,"Connections", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnections));
  643. add_counter_to_value(e,"ConnectionSeq", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq));
  644. add_counter_to_value(e,"ConnectionsInMaxThreads", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsConnectionsInMaxThreads));
  645. add_counter_to_value(e,"ConnectionsMaxThreadsCount", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsMaxThreadsHit));
  646. add_counter_to_value(e,"BytesRecv", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesRecv));
  647. add_counter_to_value(e,"BytesSent", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsBytesSent));
  648. add_counter_to_value(e,"EntriesReturned", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned));
  649. add_counter_to_value(e,"ReferralsReturned", slapi_counter_get_value(g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned));
  650. add_counter_to_value(e,"MasterEntries", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsMasterEntries));
  651. add_counter_to_value(e,"CopyEntries", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCopyEntries));
  652. add_counter_to_value(e,"CacheEntries", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries));
  653. add_counter_to_value(e,"CacheHits", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsCacheHits));
  654. add_counter_to_value(e,"SlaveHits", slapi_counter_get_value(g_get_global_snmp_vars()->entries_tbl.dsSlaveHits));
  655. }
  656. /*
  657. * loadConfigStats()
  658. *
  659. * Reads the header table SNMP settings and sets them in the mmap'd stats
  660. * file. This should be done only when the semaphore is held.
  661. */
  662. static void
  663. loadConfigStats(void) {
  664. Slapi_Entry *entry = NULL;
  665. char *name = NULL;
  666. char *desc = NULL;
  667. char *org = NULL;
  668. char *loc = NULL;
  669. char *contact = NULL;
  670. /* Read attributes from SNMP config entry */
  671. getConfigEntry( &entry );
  672. if ( entry != NULL ) {
  673. name = slapi_entry_attr_get_charptr( entry, SNMP_NAME_ATTR );
  674. desc = slapi_entry_attr_get_charptr( entry, SNMP_DESC_ATTR );
  675. org = slapi_entry_attr_get_charptr( entry, SNMP_ORG_ATTR );
  676. loc = slapi_entry_attr_get_charptr( entry, SNMP_LOC_ATTR );
  677. contact = slapi_entry_attr_get_charptr( entry, SNMP_CONTACT_ATTR );
  678. freeConfigEntry( &entry );
  679. }
  680. /* Load stats into table */
  681. if ( name != NULL) {
  682. PL_strncpyz(stats->hdr_stats.dsName, name, SNMP_FIELD_LENGTH);
  683. }
  684. if ( desc != NULL) {
  685. PL_strncpyz(stats->hdr_stats.dsDescription, desc, SNMP_FIELD_LENGTH);
  686. }
  687. if ( org != NULL) {
  688. PL_strncpyz(stats->hdr_stats.dsOrganization, org, SNMP_FIELD_LENGTH);
  689. }
  690. if ( loc != NULL) {
  691. PL_strncpyz(stats->hdr_stats.dsLocation, loc, SNMP_FIELD_LENGTH);
  692. }
  693. if ( contact != NULL) {
  694. PL_strncpyz(stats->hdr_stats.dsContact, contact, SNMP_FIELD_LENGTH);
  695. }
  696. /* Free strings */
  697. slapi_ch_free((void **) &name);
  698. slapi_ch_free((void **) &desc);
  699. slapi_ch_free((void **) &org);
  700. slapi_ch_free((void **) &loc);
  701. slapi_ch_free((void **) &contact);
  702. }
  703. static Slapi_Entry *
  704. getConfigEntry( Slapi_Entry **e ) {
  705. Slapi_DN sdn;
  706. /* SNMP_CONFIG_DN: no need to be normalized */
  707. slapi_sdn_init_normdn_byref( &sdn, SNMP_CONFIG_DN );
  708. slapi_search_internal_get_entry( &sdn, NULL, e,
  709. plugin_get_default_component_id());
  710. slapi_sdn_done( &sdn );
  711. return *e;
  712. }
  713. static void
  714. freeConfigEntry( Slapi_Entry **e ) {
  715. if ( (e != NULL) && (*e != NULL) ) {
  716. slapi_entry_free( *e );
  717. *e = NULL;
  718. }
  719. }