2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
12 * Implementation of the client side of the AFS Cache Manager
13 * extended statistics facility.
15 *------------------------------------------------------------------------*/
17 #include <afsconfig.h>
18 #include <afs/param.h>
22 #include "xstat_cm.h" /*Interface for this module*/
23 #include <lwp.h> /*Lightweight process package*/
33 #define LWP_STACK_SIZE (16 * 1024)
36 * Routines we need that don't have explicit include file definitions.
38 extern char *hostutil_GetNameByINet(); /*Host parsing utility*/
43 int xstat_cm_numServers; /*Num connected servers*/
44 struct xstat_cm_ConnectionInfo
45 *xstat_cm_ConnInfo; /*Ptr to connection array*/
46 int numCollections; /*Number of data collections*/
47 struct xstat_cm_ProbeResults xstat_cm_Results; /*Latest probe results*/
48 char terminationEvent; /*One-shot termination event*/
50 afs_int32 xstat_cmData[AFSCB_MAX_XSTAT_LONGS]; /*Buffer for collected data*/
55 static int xstat_cm_ProbeFreqInSecs; /*Probe freq. in seconds*/
56 static int xstat_cm_initflag = 0; /*Was init routine called?*/
57 static int xstat_cm_debug = 0; /*Debugging output enabled?*/
58 static int xstat_cm_oneShot = 0; /*One-shot operation?*/
59 static int (*xstat_cm_Handler)(); /*Probe handler routine*/
60 static PROCESS probeLWP_ID; /*Probe LWP process ID*/
61 static int xstat_cm_numCollections; /*Number of desired collections*/
62 static afs_int32 *xstat_cm_collIDP; /*Ptr to collection IDs desired*/
65 /*------------------------------------------------------------------------
66 * [private] xstat_cm_CleanupInit
69 * Set up for recovery after an error in initialization (i.e.,
70 * during a call to xstat_cm_Init.
77 * Error value otherwise.
80 * This routine is private to the module.
83 * Zeros out basic data structures.
84 *------------------------------------------------------------------------*/
86 static int xstat_cm_CleanupInit()
88 { /*xstat_cm_CleanupInit*/
90 xstat_cm_ConnInfo = (struct xstat_cm_ConnectionInfo *)0;
91 xstat_cm_Results.probeNum = 0;
92 xstat_cm_Results.probeTime = 0;
93 xstat_cm_Results.connP = (struct xstat_cm_ConnectionInfo *)0;
94 xstat_cm_Results.collectionNumber = 0;
95 xstat_cm_Results.data.AFSCB_CollData_len = AFSCB_MAX_XSTAT_LONGS;
96 xstat_cm_Results.data.AFSCB_CollData_val = (afs_int32 *)xstat_cmData;
97 xstat_cm_Results.probeOK = 0;
101 } /*xstat_cm_CleanupInit*/
104 /*------------------------------------------------------------------------
105 * [exported] xstat_cm_Cleanup
108 * Clean up our memory and connection state.
111 * int a_releaseMem : Should we free up malloc'ed areas?
114 * 0 on total success,
115 * -1 if the module was never initialized, or there was a problem
116 * with the xstat_cm connection array.
119 * xstat_cm_numServers should be properly set. We don't do anything
120 * unless xstat_cm_Init() has already been called.
123 * Shuts down Rx connections gracefully, frees allocated space
125 *------------------------------------------------------------------------*/
127 int xstat_cm_Cleanup(a_releaseMem)
130 { /*xstat_cm_Cleanup*/
132 static char rn[] = "xstat_cm_Cleanup"; /*Routine name*/
133 int code; /*Return code*/
134 int conn_idx; /*Current connection index*/
135 struct xstat_cm_ConnectionInfo *curr_conn; /*Ptr to xstat_cm connection*/
138 * Assume the best, but check the worst.
140 if (!xstat_cm_initflag) {
141 fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
148 * Take care of all Rx connections first. Check to see that the
149 * server count is a legal value.
151 if (xstat_cm_numServers <= 0) {
153 "[%s] Illegal number of servers (xstat_cm_numServers = %d)\n",
154 rn, xstat_cm_numServers);
158 if (xstat_cm_ConnInfo != (struct xstat_cm_ConnectionInfo *)0) {
160 * The xstat_cm connection structure array exists. Go through
161 * it and close up any Rx connections it holds.
163 curr_conn = xstat_cm_ConnInfo;
164 for (conn_idx = 0; conn_idx < xstat_cm_numServers; conn_idx++) {
165 if (curr_conn->rxconn != (struct rx_connection *)0) {
166 rx_DestroyConnection(curr_conn->rxconn);
167 curr_conn->rxconn = (struct rx_connection *)0;
170 } /*for each xstat_cm connection*/
171 } /*xstat_cm connection structure exists*/
172 } /*Legal number of servers*/
175 * If asked to, release the space we've allocated.
178 if (xstat_cm_ConnInfo != (struct xstat_cm_ConnectionInfo *)0)
179 free(xstat_cm_ConnInfo);
183 * Return the news, whatever it is.
187 } /*xstat_cm_Cleanup*/
190 /*------------------------------------------------------------------------
191 * [private] xstat_cm_LWP
194 * This LWP iterates over the server connections and gathers up
195 * the desired statistics from each one on a regular basis, for
196 * all known data collections. The associated handler function
197 * is called each time a new data collection is received.
206 * Started by xstat_cm_Init(), uses global structures and the
207 * global private xstat_cm_oneShot variable.
211 *------------------------------------------------------------------------*/
213 static void xstat_cm_LWP()
217 static char rn[] = "xstat_cm_LWP"; /*Routine name*/
218 register afs_int32 code; /*Results of calls*/
219 int oneShotCode; /*Result of one-shot signal*/
220 struct timeval tv; /*Time structure*/
221 int conn_idx; /*Connection index*/
222 struct xstat_cm_ConnectionInfo *curr_conn; /*Current connection*/
223 afs_int32 srvVersionNumber; /*Xstat version #*/
224 afs_int32 clientVersionNumber; /*Client xstat version*/
225 afs_int32 numColls; /*Number of collections to get*/
226 afs_int32 *currCollIDP; /*Curr collection ID desired*/
229 * Set up some numbers we'll need.
231 clientVersionNumber = AFSCB_XSTAT_VERSION;
233 while (1) { /*Service loop*/
235 * Iterate through the server connections, gathering data.
236 * Don't forget to bump the probe count and zero the statistics
237 * areas before calling the servers.
240 printf("[%s] Waking up, getting data from %d server(s)\n",
241 rn, xstat_cm_numServers);
242 curr_conn = xstat_cm_ConnInfo;
243 xstat_cm_Results.probeNum++;
245 for (conn_idx = 0; conn_idx < xstat_cm_numServers; conn_idx++) {
247 * Grab the statistics for the current Cache Manager, if the
248 * connection is valid.
251 printf("[%s] Getting collections from Cache Manager '%s'\n",
252 rn, curr_conn->hostName);
253 if (curr_conn->rxconn != (struct rx_connection *)0) {
255 printf("[%s] Connection OK, calling RXAFSCB_GetXStats\n",
259 * Probe the given CM for each desired collection.
261 currCollIDP = xstat_cm_collIDP;
263 numColls < xstat_cm_numCollections;
264 numColls++, currCollIDP++) {
266 * Initialize the per-probe values.
269 printf("[%s] Asking for data collection %d\n",
271 xstat_cm_Results.collectionNumber = *currCollIDP;
272 xstat_cm_Results.data.AFSCB_CollData_len =
273 AFSCB_MAX_XSTAT_LONGS;
274 memset(xstat_cm_Results.data.AFSCB_CollData_val, 0, AFSCB_MAX_XSTAT_LONGS * 4);
276 xstat_cm_Results.connP = curr_conn;
278 if (xstat_cm_debug) {
279 printf("%s: Calling RXAFSCB_GetXStats, conn=0x%x, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%x, timeP=0x%x, dataP=0x%x\n",
280 rn, curr_conn->rxconn,
284 &(xstat_cm_Results.probeTime),
285 &(xstat_cm_Results.data));
286 printf("%s: [bufflen=%d, buffer at 0x%x]\n",
288 xstat_cm_Results.data.AFSCB_CollData_len,
289 xstat_cm_Results.data.AFSCB_CollData_val);
292 xstat_cm_Results.probeOK =
293 RXAFSCB_GetXStats(curr_conn->rxconn,
297 &(xstat_cm_Results.probeTime),
298 &(xstat_cm_Results.data));
301 * Now that we (may) have the data for this connection,
302 * call the associated handler function. The handler
303 * does not take any explicit parameters, but rather
304 * gets to the goodies via some of the objects exported
308 printf("[%s] Calling handler routine.\n",
310 code = xstat_cm_Handler();
313 "[%s] Handler routine got error code %d\n",
315 } /*For each collection*/
316 } /*Valid Rx connection*/
319 * Advance the xstat_cm connection pointer.
323 } /*For each xstat_cm connection*/
326 * All (valid) connections have been probed. Fall asleep for the
327 * prescribed number of seconds, unless we're a one-shot. In
328 * that case, we need to signal our caller that we're done.
331 printf("[%s] Polling complete for probe round %d.\n",
332 rn, xstat_cm_Results.probeNum);
334 if (xstat_cm_oneShot) {
336 * One-shot execution desired. Signal our main procedure
337 * that we've finished our collection round.
340 printf("[%s] Signalling main process at 0x%x\n",
341 rn, &terminationEvent);
342 oneShotCode = LWP_SignalProcess(&terminationEvent);
345 "[%s] Error %d from LWP_SignalProcess()",
347 break; /*from the perpetual while loop*/
348 } /*One-shot execution*/
351 * Continuous execution desired. Sleep for the required
354 tv.tv_sec = xstat_cm_ProbeFreqInSecs;
357 printf("[%s] Falling asleep for %d seconds\n",
358 rn, xstat_cm_ProbeFreqInSecs);
359 code = IOMGR_Select(0, /*Num fids*/
360 0, /*Descs ready for reading*/
361 0, /*Descs ready for writing*/
362 0, /*Descs w/exceptional conditions*/
363 &tv); /*Ptr to timeout structure*/
366 "[%s] IOMGR_Select returned code %d\n",
368 } /*Continuous execution*/
374 /*------------------------------------------------------------------------
375 * [exported] xstat_cm_Init
378 * Initialize the xstat_cm module: set up Rx connections to the
379 * given set of Cache Managers, start up the probe LWP, and
380 * associate the routine to be called when a probe completes.
381 * Also, let it know which collections you're interested in.
384 * int a_numServers : Num. servers to connect to.
385 * struct sockaddr_in *a_socketArray : Array of server sockets.
386 * int a_ProbeFreqInSecs : Probe frequency in seconds.
387 * int (*a_ProbeHandler)() : Ptr to probe handler fcn.
388 * int a_flags; : Various flags.
389 * int a_numCollections : Number of collections desired.
390 * afs_int32 *a_collIDP : Ptr to collection IDs.
394 * -2 for (at least one) connection error,
395 * LWP process creation code, if it failed,
396 * -1 for other fatal errors.
399 * *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
402 * Sets up just about everything.
403 *------------------------------------------------------------------------*/
405 int xstat_cm_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs,
406 a_ProbeHandler, a_flags, a_numCollections, a_collIDP)
408 struct sockaddr_in *a_socketArray;
409 int a_ProbeFreqInSecs;
410 int (*a_ProbeHandler)();
412 int a_numCollections;
413 afs_int32 *a_collIDP;
417 static char rn[] = "xstat_cm_Init"; /*Routine name*/
418 register afs_int32 code; /*Return value*/
419 struct rx_securityClass *secobj; /*Client security object*/
420 int arg_errfound; /*Argument error found?*/
421 int curr_srv; /*Current server idx*/
422 struct xstat_cm_ConnectionInfo *curr_conn; /*Ptr to current conn*/
423 char *hostNameFound; /*Ptr to returned host name*/
424 int conn_err; /*Connection error?*/
425 int collIDBytes; /*Num bytes in coll ID array*/
428 * If we've already been called, snicker at the bozo, gently
429 * remind him of his doubtful heritage, and return success.
431 if (xstat_cm_initflag) {
432 fprintf(stderr, "[%s] Called multiple times!\n", rn);
436 xstat_cm_initflag = 1;
439 * Check the parameters for bogosities.
442 if (a_numServers <= 0) {
443 fprintf(stderr, "[%s] Illegal number of servers: %d\n",
447 if (a_socketArray == (struct sockaddr_in *)0) {
448 fprintf(stderr, "[%s] Null server socket array argument\n", rn);
451 if (a_ProbeFreqInSecs <= 0) {
452 fprintf(stderr, "[%s] Illegal probe frequency: %d\n",
453 rn, a_ProbeFreqInSecs);
456 if (a_ProbeHandler == (int (*)())0) {
457 fprintf(stderr, "[%s] Null probe handler function argument\n",
461 if (a_numCollections <= 0) {
462 fprintf(stderr, "[%s] Illegal collection count argument: %d\n",
466 if (a_collIDP == NULL) {
467 fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
474 * Record our passed-in info.
476 xstat_cm_debug = (a_flags & XSTAT_CM_INITFLAG_DEBUGGING);
477 xstat_cm_oneShot = (a_flags & XSTAT_CM_INITFLAG_ONE_SHOT);
478 xstat_cm_numServers = a_numServers;
479 xstat_cm_Handler = a_ProbeHandler;
480 xstat_cm_ProbeFreqInSecs = a_ProbeFreqInSecs;
481 xstat_cm_numCollections = a_numCollections;
482 collIDBytes = xstat_cm_numCollections * sizeof(afs_int32);
483 xstat_cm_collIDP = (afs_int32 *)(malloc(collIDBytes));
484 memcpy(xstat_cm_collIDP, a_collIDP, collIDBytes);
485 if (xstat_cm_debug) {
486 printf("[%s] Asking for %d collection(s): ", rn, xstat_cm_numCollections);
487 for (curr_srv = 0; curr_srv < xstat_cm_numCollections; curr_srv++)
488 printf("%d ", *(xstat_cm_collIDP+curr_srv));
493 * Get ready in case we have to do a cleanup - basically, zero
496 code = xstat_cm_CleanupInit();
501 * Allocate the necessary data structures and initialize everything
505 (struct xstat_cm_ConnectionInfo *)
506 malloc(a_numServers * sizeof(struct xstat_cm_ConnectionInfo));
507 if (xstat_cm_ConnInfo == (struct xstat_cm_ConnectionInfo *)0) {
509 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
511 (a_numServers * sizeof(struct xstat_cm_ConnectionInfo)));
512 return(-1); /*No cleanup needs to be done yet*/
516 * Initialize the Rx subsystem, just in case nobody's done it.
519 printf("[%s] Initializing Rx on port 0\n", rn);
520 code = rx_Init(htons(0));
522 fprintf(stderr, "[%s] Fatal error in rx_Init(), error=%d\n",
528 printf("[%s] Rx initialized on port 0\n", rn);
531 * Create a null Rx client security object, to be used by the
534 secobj = rxnull_NewClientSecurityObject();
535 if (secobj == (struct rx_securityClass *)0) {
537 "[%s] Can't create probe LWP client security object.\n",
539 xstat_cm_Cleanup(1); /*Delete already-malloc'ed areas*/
543 printf("[%s] Probe LWP client security object created\n",
546 curr_conn = xstat_cm_ConnInfo;
548 for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
550 * Copy in the socket info for the current server, resolve its
551 * printable name if possible.
553 if (xstat_cm_debug) {
554 printf("[%s] Copying in the following socket info:\n",
556 printf("[%s] IP addr 0x%lx, port %d\n", rn,
557 (a_socketArray + curr_srv)->sin_addr.s_addr,
558 (a_socketArray + curr_srv)->sin_port);
560 memcpy(&(curr_conn->skt), a_socketArray + curr_srv, sizeof(struct sockaddr_in));
563 hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
564 if (hostNameFound == NULL) {
566 "[%s] Can't map Internet address %lu to a string name\n",
567 rn, curr_conn->skt.sin_addr.s_addr);
568 curr_conn->hostName[0] = '\0';
571 strcpy(curr_conn->hostName, hostNameFound);
573 printf("[%s] Host name for server index %d is %s\n",
574 rn, curr_srv, curr_conn->hostName);
578 * Make an Rx connection to the current server.
581 printf("[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
582 rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
583 curr_conn->skt.sin_port);
585 rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr*/
586 curr_conn->skt.sin_port, /*Server port*/
588 secobj, /*Security obj*/
590 if (curr_conn->rxconn == (struct rx_connection *)0) {
592 "[%s] Can't create Rx connection to server '%s' (%lu)\n",
593 rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
597 printf("[%s] New connection at 0x%lx\n",
598 rn, curr_conn->rxconn);
601 * Bump the current xstat_cm connection to set up.
608 * Start up the probe LWP.
611 printf("[%s] Creating the probe LWP\n", rn);
613 LWP_CreateProcess(xstat_cm_LWP, /*Function to start up*/
614 LWP_STACK_SIZE, /*Stack size in bytes*/
617 "xstat_cm Worker", /*Name to use*/
618 &probeLWP_ID); /*Returned LWP process ID*/
621 "[%s] Can't create xstat_cm LWP! Error is %d\n",
623 xstat_cm_Cleanup(1); /*Delete already-malloc'ed areas*/
627 printf("[%s] Probe LWP process structure located at 0x%x\n",
631 * Return the final results.
641 /*------------------------------------------------------------------------
642 * [exported] xstat_cm_ForceProbeNow
645 * Wake up the probe LWP, forcing it to execute a probe immediately.
652 * Error value otherwise.
655 * The module must have been initialized.
659 *------------------------------------------------------------------------*/
661 int xstat_cm_ForceProbeNow()
663 { /*xstat_cm_ForceProbeNow*/
665 static char rn[] = "xstat_cm_ForceProbeNow"; /*Routine name*/
668 * There isn't a prayer unless we've been initialized.
670 if (!xstat_cm_initflag) {
671 fprintf(stderr, "[%s] Must call xstat_cm_Init first!\n", rn);
676 * Kick the sucker in the side.
678 IOMGR_Cancel(probeLWP_ID);
681 * We did it, so report the happy news.
685 } /*xstat_cm_ForceProbeNow*/