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 * afs_MarkServerUpOrDown
20 * afsi_SetServerIPRank
32 #include <afsconfig.h>
33 #include "afs/param.h"
37 #include "afs/sysincludes.h" /* Standard vendor system headers */
40 # if !defined(AFS_LINUX_ENV)
43 # include <netinet/in.h>
46 # include "h/hashing.h"
48 # if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX_ENV) && !defined(AFS_DARWIN_ENV)
49 # include <netinet/in_var.h>
50 # endif /* AFS_HPUX110_ENV */
51 # ifdef AFS_DARWIN_ENV
52 # include <net/if_var.h>
54 #endif /* !defined(UKERNEL) */
56 #include "afsincludes.h" /* Afs-based standard headers */
57 #include "afs/afs_stats.h" /* afs statistics */
58 #include "rx/rx_multi.h"
60 #if defined(AFS_SUN5_ENV)
61 # include <inet/led.h>
62 # include <inet/common.h>
63 # include <netinet/ip6.h>
64 # define ipif_local_addr ipif_lcl_addr
65 # ifndef V4_PART_OF_V6
66 # define V4_PART_OF_V6(v6) v6.s6_addr32[3]
71 /* Exported variables */
72 afs_rwlock_t afs_xserver; /* allocation lock for servers */
73 struct server *afs_servers[NSERVERS]; /* Hashed by server`s uuid & 1st ip */
74 afs_rwlock_t afs_xsrvAddr; /* allocation lock for srvAddrs */
75 struct srvAddr *afs_srvAddrs[NSERVERS]; /* Hashed by server's ip */
78 /* debugging aids - number of alloc'd server and srvAddr structs. */
79 int afs_reuseServers = 0;
80 int afs_reuseSrvAddrs = 0;
81 int afs_totalServers = 0;
82 int afs_totalSrvAddrs = 0;
86 static struct afs_stats_SrvUpDownInfo *
87 GetUpDownStats(struct server *srv)
89 struct afs_stats_SrvUpDownInfo *upDownP;
90 u_short fsport = AFS_FSPORT;
93 fsport = srv->cell->fsport;
95 if (srv->addr->sa_portal == fsport)
96 upDownP = afs_stats_cmperf.fs_UpDown;
98 upDownP = afs_stats_cmperf.vl_UpDown;
100 if (srv->cell && afs_IsPrimaryCell(srv->cell))
101 return &upDownP[AFS_STATS_UPDOWN_IDX_SAME_CELL];
103 return &upDownP[AFS_STATS_UPDOWN_IDX_DIFF_CELL];
107 /*------------------------------------------------------------------------
108 * afs_MarkServerUpOrDown
111 * Mark the given server up or down, and track its uptime stats.
114 * a_serverP : Ptr to server record to fiddle with.
115 * a_isDown : Is the server is to be marked down?
121 * The CM server structures must be write-locked.
125 *------------------------------------------------------------------------*/
128 afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
130 struct server *a_serverP = sa->server;
132 osi_timeval32_t currTime, *currTimeP; /*Current time */
133 afs_int32 downTime; /*Computed downtime, in seconds */
134 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record */
137 * If the server record is marked the same as the new status we've
138 * been fed, then there isn't much to be done.
140 if ((a_isDown && (sa->sa_flags & SRVADDR_ISDOWN))
141 || (!a_isDown && !(sa->sa_flags & SRVADDR_ISDOWN)))
145 sa->sa_flags |= SRVADDR_ISDOWN;
146 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
147 if (!(sap->sa_flags & SRVADDR_ISDOWN)) {
148 /* Not all ips are up so don't bother with the
149 * server's up/down stats */
154 * All ips are down we treat the whole server down
156 a_serverP->flags |= SRVR_ISDOWN;
158 sa->sa_flags &= ~SRVADDR_ISDOWN;
159 /* If any ips are up, the server is also marked up */
160 a_serverP->flags &= ~SRVR_ISDOWN;
161 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
162 if (sap->sa_flags & SRVADDR_ISDOWN) {
163 /* Not all ips are up so don't bother with the
164 * server's up/down stats */
171 * Compute the current time and which overall stats record is to be
172 * updated; we'll need them one way or another.
174 currTimeP = &currTime;
175 osi_GetTime(currTimeP);
177 upDownP = GetUpDownStats(a_serverP);
181 * Server going up -> down; remember the beginning of this
184 a_serverP->lastDowntimeStart = currTime.tv_sec;
186 (upDownP->numDownRecords)++;
187 (upDownP->numUpRecords)--;
188 } /*Server being marked down */
191 * Server going down -> up; remember everything about this
192 * newly-completed downtime incident.
194 downTime = currTime.tv_sec - a_serverP->lastDowntimeStart;
195 (a_serverP->numDowntimeIncidents)++;
196 a_serverP->sumOfDowntimes += downTime;
198 (upDownP->numUpRecords)++;
199 (upDownP->numDownRecords)--;
200 (upDownP->numDowntimeIncidents)++;
201 if (a_serverP->numDowntimeIncidents == 1)
202 (upDownP->numRecordsNeverDown)--;
203 upDownP->sumOfDowntimes += downTime;
204 if ((upDownP->shortestDowntime == 0)
205 || (downTime < upDownP->shortestDowntime))
206 upDownP->shortestDowntime = downTime;
207 if ((upDownP->longestDowntime == 0)
208 || (downTime > upDownP->longestDowntime))
209 upDownP->longestDowntime = downTime;
212 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET0)
213 (upDownP->downDurations[0])++;
214 else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET1)
215 (upDownP->downDurations[1])++;
216 else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET2)
217 (upDownP->downDurations[2])++;
218 else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET3)
219 (upDownP->downDurations[3])++;
220 else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET4)
221 (upDownP->downDurations[4])++;
222 else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET5)
223 (upDownP->downDurations[5])++;
225 (upDownP->downDurations[6])++;
227 } /*Server being marked up */
229 } /*MarkServerUpOrDown */
233 afs_ServerDown(struct srvAddr *sa, int code, struct rx_connection *rxconn)
235 struct server *aserver = sa->server;
237 AFS_STATCNT(ServerDown);
238 if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
240 afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
241 if (sa->sa_portal == aserver->cell->vlport)
242 print_internet_address("afs: Lost contact with volume location server ",
243 sa, "", 1, code, rxconn);
245 print_internet_address("afs: Lost contact with file server ", sa, "",
251 /* return true if we have any callback promises from this server */
253 afs_HaveCallBacksFrom(struct server *aserver)
259 AFS_STATCNT(HaveCallBacksFrom);
260 now = osi_Time(); /* for checking for expired callbacks */
261 for (i = 0; i < VCSIZE; i++) { /* for all guys in the hash table */
262 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
264 * Check to see if this entry has an unexpired callback promise
265 * from the required host
267 if (aserver == tvc->callback && tvc->cbExpires >= now
268 && ((tvc->f.states & CRO) == 0))
274 } /*HaveCallBacksFrom */
278 CheckVLServer(struct srvAddr *sa, struct vrequest *areq)
280 struct server *aserver = sa->server;
283 struct rx_connection *rxconn;
285 AFS_STATCNT(CheckVLServer);
286 /* Ping dead servers to see if they're back */
287 if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN))
288 || (aserver->flags & SRVR_ISGONE))
291 return; /* can't do much */
293 tc = afs_ConnByHost(aserver, aserver->cell->vlport,
294 aserver->cell->cellNum, areq, 1, SHARED_LOCK, 0,
298 rx_SetConnDeadTime(rxconn, 3);
301 code = VL_ProbeServer(rxconn);
303 rx_SetConnDeadTime(rxconn, afs_rx_deadtime);
305 * If probe worked, or probe call not yet defined (for compatibility
306 * with old vlsevers), then we treat this server as running again
308 if (code == 0 || (code <= -450 && code >= -470)) {
309 if (tc->parent->srvr == sa) {
310 afs_MarkServerUpOrDown(sa, 0);
311 print_internet_address("afs: volume location server ", sa,
312 " is back up", 2, code, rxconn);
315 afs_PutConn(tc, rxconn, SHARED_LOCK);
320 #ifndef AFS_MINCHANGE /* So that some can increase it in param.h */
321 # define AFS_MINCHANGE 2 /* min change we'll bother with */
323 #ifndef AFS_MAXCHANGEBACK
324 # define AFS_MAXCHANGEBACK 10 /* max seconds we'll set a clock back at once */
328 /*------------------------------------------------------------------------
329 * EXPORTED afs_CountServers
332 * Originally meant to count the number of servers and determining
333 * up/down info, this routine will now simply sum up all of the
334 * server record ages. All other up/down information is kept on the
344 * This routine locks afs_xserver for write for the duration.
347 * Set CM perf stats field sumOfRecordAges for all server record
349 *------------------------------------------------------------------------*/
352 afs_CountServers(void)
354 int currIdx; /*Curr idx into srv table */
355 struct server *currSrvP; /*Ptr to curr server record */
356 afs_int32 currChainLen; /*Length of curr hash chain */
357 osi_timeval32_t currTime; /*Current time */
358 osi_timeval32_t *currTimeP; /*Ptr to above */
359 afs_int32 srvRecordAge; /*Age of server record, in secs */
360 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to current up/down
361 * info being manipulated */
364 * Write-lock the server table so we don't get any interference.
366 ObtainReadLock(&afs_xserver);
369 * Iterate over each hash index in the server table, walking down each
370 * chain and tallying what we haven't computed from the records there on
371 * the fly. First, though, initialize the tallies that will change.
373 afs_stats_cmperf.srvMaxChainLength = 0;
375 afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
376 afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
377 afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
378 memset(afs_stats_cmperf.fs_UpDown[0].downIncidents, 0,
379 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
381 afs_stats_cmperf.fs_UpDown[1].sumOfRecordAges = 0;
382 afs_stats_cmperf.fs_UpDown[1].ageOfYoungestRecord = 0;
383 afs_stats_cmperf.fs_UpDown[1].ageOfOldestRecord = 0;
384 memset(afs_stats_cmperf.fs_UpDown[1].downIncidents, 0,
385 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
387 afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges = 0;
388 afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
389 afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord = 0;
390 memset(afs_stats_cmperf.vl_UpDown[0].downIncidents, 0,
391 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
393 afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges = 0;
394 afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
395 afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord = 0;
396 memset(afs_stats_cmperf.vl_UpDown[1].downIncidents, 0,
397 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
400 * Compute the current time, used to figure out server record ages.
402 currTimeP = &currTime;
403 osi_GetTime(currTimeP);
406 * Sweep the server hash table, tallying all we need to know.
408 for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
410 for (currSrvP = afs_servers[currIdx]; currSrvP;
411 currSrvP = currSrvP->next) {
413 * Bump the current chain length.
418 * Any further tallying for this record will only be done if it has
421 if ((currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED)
422 && currSrvP->addr && currSrvP->cell) {
425 * Compute the current server record's age, then remember it
426 * in the appropriate places.
428 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
429 upDownP = GetUpDownStats(currSrvP);
430 upDownP->sumOfRecordAges += srvRecordAge;
431 if ((upDownP->ageOfYoungestRecord == 0)
432 || (srvRecordAge < upDownP->ageOfYoungestRecord))
433 upDownP->ageOfYoungestRecord = srvRecordAge;
434 if ((upDownP->ageOfOldestRecord == 0)
435 || (srvRecordAge > upDownP->ageOfOldestRecord))
436 upDownP->ageOfOldestRecord = srvRecordAge;
438 if (currSrvP->numDowntimeIncidents <=
439 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
440 (upDownP->downIncidents[0])++;
441 else if (currSrvP->numDowntimeIncidents <=
442 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
443 (upDownP->downIncidents[1])++;
444 else if (currSrvP->numDowntimeIncidents <=
445 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
446 (upDownP->downIncidents[2])++;
447 else if (currSrvP->numDowntimeIncidents <=
448 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
449 (upDownP->downIncidents[3])++;
450 else if (currSrvP->numDowntimeIncidents <=
451 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
452 (upDownP->downIncidents[4])++;
454 (upDownP->downIncidents[5])++;
457 } /*Current server has been active */
458 } /*Walk this chain */
461 * Before advancing to the next chain, remember facts about this one.
463 if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
465 * We beat out the former champion (which was initially set to 0
466 * here). Mark down the new winner, and also remember if it's an
469 afs_stats_cmperf.srvMaxChainLength = currChainLen;
470 if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
471 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
472 } /*Update chain length maximum */
473 } /*For each hash chain */
476 * We're done. Unlock the server table before returning to our caller.
478 ReleaseReadLock(&afs_xserver);
480 } /*afs_CountServers */
484 ForceAllNewConnections(void)
487 struct srvAddr **addrs;
491 ObtainReadLock(&afs_xserver); /* Necessary? */
492 ObtainReadLock(&afs_xsrvAddr);
495 for (i = 0; i < NSERVERS; i++) {
496 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
501 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
502 osi_Assert(addrs != NULL);
504 for (i = 0; i < NSERVERS; i++) {
505 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
506 if (j >= srvAddrCount)
512 ReleaseReadLock(&afs_xsrvAddr);
513 ReleaseReadLock(&afs_xserver);
514 for (i = 0; i < j; i++) {
516 ForceNewConnections(sa);
519 afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
523 CkSrv_MarkUpDown(struct afs_conn **conns, struct rx_connection **rxconns,
524 int nconns, afs_int32 *results)
530 for(i = 0; i < nconns; i++){
532 sa = tc->parent->srvr;
534 if (( results[i] >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) &&
535 (tc->parent->srvr == sa)) {
537 print_internet_address("afs: file server ", sa, " is back up", 2,
538 results[i], rxconns[i]);
540 ObtainWriteLock(&afs_xserver, 244);
541 ObtainWriteLock(&afs_xsrvAddr, 245);
542 afs_MarkServerUpOrDown(sa, 0);
543 ReleaseWriteLock(&afs_xsrvAddr);
544 ReleaseWriteLock(&afs_xserver);
546 if (afs_waitForeverCount) {
547 afs_osi_Wakeup(&afs_waitForever);
550 if (results[i] < 0) {
552 afs_ServerDown(sa, results[i], rxconns[i]);
553 ForceNewConnections(sa); /* multi homed clients */
560 CkSrv_GetCaps(int nconns, struct rx_connection **rxconns,
561 struct afs_conn **conns)
568 caps = afs_osi_Alloc(nconns * sizeof (Capabilities));
569 osi_Assert(caps != NULL);
570 memset(caps, 0, nconns * sizeof(Capabilities));
572 results = afs_osi_Alloc(nconns * sizeof (afs_int32));
573 osi_Assert(results != NULL);
576 multi_Rx(rxconns,nconns)
578 multi_RXAFS_GetCapabilities(&caps[multi_i]);
579 results[multi_i] = multi_error;
583 for ( i = 0 ; i < nconns ; i++ ) {
584 ts = conns[i]->parent->srvr->server;
587 ts->capabilities = 0;
588 ts->flags |= SCAPS_KNOWN;
589 if ( results[i] == RXGEN_OPCODE ) {
590 /* Mark server as up - it responded */
594 if ( results[i] >= 0 )
595 /* we currently handle 32-bits of capabilities */
596 if (caps[i].Capabilities_len > 0) {
597 ts->capabilities = caps[i].Capabilities_val[0];
598 xdr_free((xdrproc_t)xdr_Capabilities, &caps[i]);
599 caps[i].Capabilities_val = NULL;
600 caps[i].Capabilities_len = 0;
603 CkSrv_MarkUpDown(conns, rxconns, nconns, results);
605 afs_osi_Free(caps, nconns * sizeof(Capabilities));
606 afs_osi_Free(results, nconns * sizeof(afs_int32));
609 /* check down servers (if adown), or running servers (if !adown) */
611 afs_CheckServers(int adown, struct cell *acellp)
613 afs_LoopServers(adown?AFS_LS_DOWN:AFS_LS_UP, acellp, 1, CkSrv_GetCaps, NULL);
616 /* adown: AFS_LS_UP - check only up
617 * AFS_LS_DOWN - check only down.
618 * AFS_LS_ALL - check all */
620 afs_LoopServers(int adown, struct cell *acellp, int vlalso,
621 void (*func1) (int nservers, struct rx_connection **rxconns,
622 struct afs_conn **conns),
623 void (*func2) (int nservers, struct rx_connection **rxconns,
624 struct afs_conn **conns))
626 struct vrequest *treq = NULL;
629 struct afs_conn *tc = NULL;
634 struct srvAddr **addrs;
635 struct afs_conn **conns;
637 struct rx_connection **rxconns;
638 afs_int32 *conntimer;
640 AFS_STATCNT(afs_CheckServers);
643 * No sense in doing the server checks if we are running in disconnected
646 if (AFS_IS_DISCONNECTED)
649 if ((code = afs_CreateReq(&treq, afs_osi_credp)))
651 ObtainReadLock(&afs_xserver); /* Necessary? */
652 ObtainReadLock(&afs_xsrvAddr);
655 for (i = 0; i < NSERVERS; i++) {
656 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
661 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
662 osi_Assert(addrs != NULL);
664 for (i = 0; i < NSERVERS; i++) {
665 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
666 if (j >= srvAddrCount)
672 ReleaseReadLock(&afs_xsrvAddr);
673 ReleaseReadLock(&afs_xserver);
675 conns = afs_osi_Alloc(j * sizeof(struct afs_conn *));
676 osi_Assert(conns != NULL);
677 rxconns = afs_osi_Alloc(j * sizeof(struct rx_connection *));
678 osi_Assert(rxconns != NULL);
679 conntimer = afs_osi_Alloc(j * sizeof (afs_int32));
680 osi_Assert(conntimer != NULL);
683 for (i = 0; i < j; i++) {
684 struct rx_connection *rxconn;
690 /* See if a cell to check was specified. If it is spec'd and not
691 * this server's cell, just skip the server.
693 if (acellp && acellp != ts->cell)
696 if (((adown==AFS_LS_DOWN) && !(sa->sa_flags & SRVADDR_ISDOWN))
697 || ((adown==AFS_LS_UP) && (sa->sa_flags & SRVADDR_ISDOWN)))
700 /* check vlserver with special code */
701 if (sa->sa_portal == AFS_VLPORT) {
703 CheckVLServer(sa, treq);
707 if (!ts->cell) /* not really an active server, anyway, it must */
708 continue; /* have just been added by setsprefs */
710 if ((sa->sa_flags & SRVADDR_ISDOWN) == 0 && !afs_HaveCallBacksFrom(sa->server)) {
711 /* Server is up, and we have no active callbacks from it. */
715 /* get a connection, even if host is down; bumps conn ref count */
716 tu = afs_GetUser(treq->uid, ts->cell->cellNum, SHARED_LOCK);
717 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
718 1 /*force */ , 1 /*create */ , SHARED_LOCK, 0,
720 afs_PutUser(tu, SHARED_LOCK);
725 rxconns[nconns]=rxconn;
726 if (sa->sa_flags & SRVADDR_ISDOWN) {
727 rx_SetConnDeadTime(rxconn, 3);
734 } /* Outer loop over addrs */
736 afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
739 (*func1)(nconns, rxconns, conns);
742 (*func2)(nconns, rxconns, conns);
745 for (i = 0; i < nconns; i++) {
746 if (conntimer[i] == 1)
747 rx_SetConnDeadTime(rxconns[i], afs_rx_deadtime);
748 afs_PutConn(conns[i], rxconns[i], SHARED_LOCK); /* done with it now */
751 afs_osi_Free(conns, j * sizeof(struct afs_conn *));
752 afs_osi_Free(rxconns, j * sizeof(struct rx_connection *));
753 afs_osi_Free(conntimer, j * sizeof(afs_int32));
754 afs_DestroyReq(treq);
756 } /*afs_CheckServers*/
759 /* find a server structure given the host address */
761 afs_FindServer(afs_int32 aserver, afs_uint16 aport, afsUUID * uuidp,
768 AFS_STATCNT(afs_FindServer);
770 i = afs_uuid_hash(uuidp) % NSERVERS;
771 for (ts = afs_servers[i]; ts; ts = ts->next) {
772 if ((ts->flags & SRVR_MULTIHOMED)
774 (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp))
775 == 0) && (!ts->addr || (ts->addr->sa_portal == aport)))
780 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
781 if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
788 } /*afs_FindServer */
791 /* some code for creating new server structs and setting preferences follows
792 * in the next few lines...
795 #define MAXDEFRANK 60000
796 #define DEFRANK 40000
798 /* Random number generator and constants from KnuthV2 2d ed, p170 */
804 a is 0.73m should be 0.01m .. 0.99m
805 c is more or less immaterial. 1 or a is suggested.
807 NB: LOW ORDER BITS are not very random. To get small random numbers,
808 treat result as <1, with implied binary point, and multiply by
810 NB: Has to be unsigned, since shifts on signed quantities may preserve
813 /* added rxi_getaddr() to try to get as much initial randomness as
814 possible, since at least one customer reboots ALL their clients
815 simultaneously -- so osi_Time is bound to be the same on some of the
816 clients. This is probably OK, but I don't want to see too much of it.
819 #define ranstage(x) (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
824 static afs_int32 state = 0;
827 AFS_STATCNT(afs_random);
832 * Clear the low nybble of tv_usec in a size-independent manner before adding
833 * in the rest of the state.
836 state ^= (state & 0x0f);
837 state += rxi_getaddr() & 0xff;
838 state += (t.tv_sec & 0xff);
839 for (i = 0; i < 30; i++) {
849 /* returns int 0..14 using the high bits of a pseudo-random number instead of
850 the low bits, as the low bits are "less random" than the high ones...
851 slight roundoff error exists, an excercise for the reader.
852 need to multiply by something with lots of ones in it, so multiply by
853 8 or 16 is right out.
856 afs_randomMod15(void)
860 temp = afs_random() >> 4;
861 temp = (temp * 15) >> 28;
867 afs_randomMod127(void)
871 temp = afs_random() >> 7;
872 temp = (temp * 127) >> 25;
877 /* afs_SortOneServer()
878 * Sort all of the srvAddrs, of a server struct, by rank from low to high.
881 afs_SortOneServer(struct server *asp)
883 struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
886 for (rootsa = &(asp->addr); *rootsa; rootsa = &(lowsa->next_sa)) {
888 lowsa = *rootsa; /* lowest sa is the first one */
889 lowrank = lowsa->sa_iprank;
891 for (tsa = *rootsa; tsa->next_sa; tsa = tsa->next_sa) {
892 rank = tsa->next_sa->sa_iprank;
893 if (rank < lowrank) {
895 lowsa = tsa->next_sa;
896 lowrank = lowsa->sa_iprank;
899 if (lowprev) { /* found one lower, so rearrange them */
900 lowprev->next_sa = lowsa->next_sa;
901 lowsa->next_sa = *rootsa;
908 * Sort the pointer to servers by the server's rank (its lowest rank).
909 * It is assumed that the server already has its IP addrs sorted (the
910 * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
913 afs_SortServers(struct server *aservers[], int count)
918 AFS_STATCNT(afs_SortServers);
920 for (i = 0; i < count; i++) {
923 for (low = i, j = i + 1; j <= count; j++) {
924 if ((!aservers[j]) || (!aservers[j]->addr))
926 if ((!aservers[low]) || (!aservers[low]->addr))
928 if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
934 aservers[i] = aservers[low];
938 } /*afs_SortServers */
940 /* afs_SetServerPrefs is rather system-dependent. It pokes around in kernel
941 data structures to determine what the local IP addresses and subnet masks
942 are in order to choose which server(s) are on the local subnet.
944 As I see it, there are several cases:
945 1. The server address is one of this host's local addresses. In this case
946 this server is to be preferred over all others.
947 2. The server is on the same subnet as one of the this host's local
948 addresses. (ie, an odd-sized subnet, not class A,B,orC)
949 3. The server is on the same net as this host (class A,B or C)
950 4. The server is on a different logical subnet or net than this host, but
951 this host is a 'metric 0 gateway' to it. Ie, two address-spaces share
953 5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
955 6. This host and the server are disjoint.
957 That is a rough order of preference. If a point-to-point link has a high
958 metric, I'm assuming that it is a very slow link, and putting it at the
959 bottom of the list (at least until RX works better over slow links). If
960 its metric is 1, I'm assuming that it's relatively fast (T1) and putting
962 It's not easy to check for case #4, so I'm ignoring it for the time being.
964 BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
965 That could be used to prefer certain servers fairly easily. Maybe some
968 NOTE: this code is very system-dependent, and very dependent on the TCP/IP
969 protocols (well, addresses that are stored in uint32s, at any rate).
972 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
973 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
975 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
976 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
981 #define PPWEIGHT 4096
985 #ifdef AFS_USERSPACE_IP_ADDR
987 # define afs_min(A,B) ((A)<(B)) ? (A) : (B)
990 * The IP addresses and ranks are determined by afsd (in user space) and
991 * passed into the kernel at startup time through the AFSOP_ADVISEADDR
992 * system call. These are stored in the data structure
993 * called 'afs_cb_interface'.
995 * struct srvAddr *sa; remote server
996 * afs_int32 addr; one of my local addr in net order
997 * afs_uint32 subnetmask; subnet mask of local addr in net order
1001 afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr,
1002 afs_uint32 subnetmask)
1004 afs_uint32 myAddr, myNet, mySubnet, netMask;
1005 afs_uint32 serverAddr;
1007 myAddr = ntohl(addr); /* one of my IP addr in host order */
1008 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
1009 subnetmask = ntohl(subnetmask); /* subnet mask in host order */
1011 if (IN_CLASSA(myAddr))
1012 netMask = IN_CLASSA_NET;
1013 else if (IN_CLASSB(myAddr))
1014 netMask = IN_CLASSB_NET;
1015 else if (IN_CLASSC(myAddr))
1016 netMask = IN_CLASSC_NET;
1020 myNet = myAddr & netMask;
1021 mySubnet = myAddr & subnetmask;
1023 if ((serverAddr & netMask) == myNet) {
1024 if ((serverAddr & subnetmask) == mySubnet) {
1025 if (serverAddr == myAddr) { /* same machine */
1026 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1027 } else { /* same subnet */
1028 sa->sa_iprank = afs_min(sa->sa_iprank, HI);
1030 } else { /* same net */
1031 sa->sa_iprank = afs_min(sa->sa_iprank, MED);
1037 #else /* AFS_USERSPACE_IP_ADDR */
1039 # if !defined(AFS_SUN5_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_OBSD47_ENV) && !defined(AFS_FBSD_ENV) && defined(USEIFADDR)
1041 afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
1043 struct sockaddr_in *sin;
1046 if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1047 if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1049 if (SA2ULONG(sin) == ntohl(sa->sa_ip)) { /* ie, ME!!! */
1050 sa->sa_iprank = TOPR;
1052 t = HI + ifa->ia_ifp->if_metric; /* case #2 */
1053 if (sa->sa_iprank > t)
1057 t = MED + ifa->ia_ifp->if_metric; /* case #3 */
1058 if (sa->sa_iprank > t)
1062 # if defined(IFF_POINTOPOINT) && !defined(UKERNEL)
1063 /* check for case #4 -- point-to-point link */
1064 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT)
1065 && (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1066 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED) / PPWEIGHT)
1069 t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1070 if (sa->sa_iprank > t)
1073 # endif /* IFF_POINTOPOINT */
1075 # endif /* !SUN5 && !DARWIN && !OBSD47 && !FBSD && USEIFADDR */
1076 # if (defined(AFS_DARWIN_ENV) || defined(AFS_OBSD47_ENV) || defined(AFS_FBSD_ENV)) && defined(USEIFADDR)
1078 # define afs_min(A,B) ((A)<(B)) ? (A) : (B)
1081 afsi_SetServerIPRank(struct srvAddr *sa, rx_ifaddr_t ifa)
1083 struct sockaddr sout;
1084 struct sockaddr_in *sin;
1085 # if defined(AFS_DARWIN80_ENV) && !defined(UKERNEL)
1091 afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
1092 afs_uint32 serverAddr;
1094 if (rx_ifaddr_address_family(ifa) != AF_INET)
1096 t = rx_ifaddr_address(ifa, &sout, sizeof(sout));
1098 sin = (struct sockaddr_in *)&sout;
1099 myAddr = ntohl(sin->sin_addr.s_addr); /* one of my IP addr in host order */
1103 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
1104 t = rx_ifaddr_netmask(ifa, &sout, sizeof(sout));
1106 sin = (struct sockaddr_in *)&sout;
1107 subnetmask = ntohl(sin->sin_addr.s_addr); /* subnet mask in host order */
1111 t = rx_ifaddr_dstaddress(ifa, &sout, sizeof(sout));
1113 sin = (struct sockaddr_in *)&sout;
1114 myDstaddr = ntohl(sin->sin_addr.s_addr);
1119 if (IN_CLASSA(myAddr))
1120 netMask = IN_CLASSA_NET;
1121 else if (IN_CLASSB(myAddr))
1122 netMask = IN_CLASSB_NET;
1123 else if (IN_CLASSC(myAddr))
1124 netMask = IN_CLASSC_NET;
1128 myNet = myAddr & netMask;
1129 mySubnet = myAddr & subnetmask;
1131 if ((serverAddr & netMask) == myNet) {
1132 if ((serverAddr & subnetmask) == mySubnet) {
1133 if (serverAddr == myAddr) { /* same machine */
1134 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1135 } else { /* same subnet */
1136 sa->sa_iprank = afs_min(sa->sa_iprank, HI + rx_ifnet_metric(rx_ifaddr_ifnet(ifa)));
1138 } else { /* same net */
1139 sa->sa_iprank = afs_min(sa->sa_iprank, MED + rx_ifnet_metric(rx_ifaddr_ifnet(ifa)));
1142 # ifdef IFF_POINTTOPOINT
1143 /* check for case #4 -- point-to-point link */
1144 if ((rx_ifnet_flags(rx_ifaddr_ifnet(ifa)) & IFF_POINTOPOINT)
1145 && (myDstaddr == serverAddr)) {
1146 if (rx_ifnet_metric(rx_ifaddr_ifnet(ifa)) >= (MAXDEFRANK - MED) / PPWEIGHT)
1149 t = MED + (PPWEIGHT << rx_ifnet_metric(rx_ifaddr_ifnet(ifa)));
1150 if (sa->sa_iprank > t)
1153 # endif /* IFF_POINTTOPOINT */
1155 # endif /* (DARWIN || OBSD47 || FBSD) && USEIFADDR */
1156 #endif /* AFS_USERSPACE_IP_ADDR */
1160 afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1163 afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr *)h);
1164 return 0; /* Never match, so we enumerate everyone */
1166 #endif /* AFS_SGI_ENV */
1168 afs_SetServerPrefs(struct srvAddr *const sa)
1170 #if defined(AFS_USERSPACE_IP_ADDR)
1174 for (i = 0; i < afs_cb_interface.numberOfInterfaces; i++) {
1175 afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1176 afs_cb_interface.subnetmask[i]);
1178 #else /* AFS_USERSPACE_IP_ADDR */
1179 # if defined(AFS_SUN5_ENV)
1180 # ifdef AFS_SUN510_ENV
1183 extern struct ill_s *ill_g_headp;
1184 long *addr = (long *)ill_g_headp;
1188 int subnet, subnetmask, net, netmask;
1191 # ifdef AFS_SUN510_ENV
1192 rw_enter(&afsifinfo_lock, RW_READER);
1194 for (i = 0; (afsifinfo[i].ipaddr != NULL) && (i < ADDRSPERSITE); i++) {
1196 if (IN_CLASSA(afsifinfo[i].ipaddr)) {
1197 netmask = IN_CLASSA_NET;
1198 } else if (IN_CLASSB(afsifinfo[i].ipaddr)) {
1199 netmask = IN_CLASSB_NET;
1200 } else if (IN_CLASSC(afsifinfo[i].ipaddr)) {
1201 netmask = IN_CLASSC_NET;
1205 net = afsifinfo[i].ipaddr & netmask;
1208 /* XXXXXX Do the individual ip ranking below XXXXX */
1209 if ((sa->sa_ip & netmask) == net) {
1210 if ((sa->sa_ip & subnetmask) == subnet) {
1211 if (afsifinfo[i].ipaddr == sa->sa_ip) { /* ie, ME! */
1212 sa->sa_iprank = TOPR;
1214 sa->sa_iprank = HI + afsifinfo[i].metric; /* case #2 */
1217 sa->sa_iprank = MED + afsifinfo[i].metric; /* case #3 */
1220 sa->sa_iprank = LO + afsifinfo[i].metric; /* case #4 */
1222 /* check for case #5 -- point-to-point link */
1223 if ((afsifinfo[i].flags & IFF_POINTOPOINT)
1224 && (afsifinfo[i].dstaddr == sa->sa_ip)) {
1226 if (afsifinfo[i].metric >= (MAXDEFRANK - MED) / PPWEIGHT)
1227 sa->sa_iprank = MAXDEFRANK;
1229 sa->sa_iprank = MED + (PPWEIGHT << afsifinfo[i].metric);
1234 rw_exit(&afsifinfo_lock);
1236 # else /* AFS_SUN510_ENV */
1238 for (ill = (struct ill_s *)*addr /*ill_g_headp */ ; ill;
1239 ill = ill->ill_next) {
1240 /* Make sure this is an IPv4 ILL */
1243 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
1244 subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1245 subnetmask = ipif->ipif_net_mask;
1247 * Generate the local net using the local address and
1248 * whate we know about Class A, B and C networks.
1250 if (IN_CLASSA(ipif->ipif_local_addr)) {
1251 netmask = IN_CLASSA_NET;
1252 } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1253 netmask = IN_CLASSB_NET;
1254 } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1255 netmask = IN_CLASSC_NET;
1259 net = ipif->ipif_local_addr & netmask;
1261 /* XXXXXX Do the individual ip ranking below XXXXX */
1262 if ((sa->sa_ip & netmask) == net) {
1263 if ((sa->sa_ip & subnetmask) == subnet) {
1264 if (ipif->ipif_local_addr == sa->sa_ip) { /* ie, ME! */
1265 sa->sa_iprank = TOPR;
1267 sa->sa_iprank = HI + ipif->ipif_metric; /* case #2 */
1270 sa->sa_iprank = MED + ipif->ipif_metric; /* case #3 */
1273 sa->sa_iprank = LO + ipif->ipif_metric; /* case #4 */
1275 /* check for case #5 -- point-to-point link */
1276 if ((ipif->ipif_flags & IFF_POINTOPOINT)
1277 && (ipif->ipif_pp_dst_addr == sa->sa_ip)) {
1279 if (ipif->ipif_metric >= (MAXDEFRANK - MED) / PPWEIGHT)
1280 sa->sa_iprank = MAXDEFRANK;
1282 sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1287 # endif /* AFS_SUN510_ENV */
1288 # else /* AFS_SUN5_ENV */
1290 rx_ifnet_t ifn = NULL;
1291 struct in_ifaddr *ifad = (struct in_ifaddr *)0;
1292 struct sockaddr_in *sin;
1295 ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1296 if (ifn) { /* local, more or less */
1297 # ifdef IFF_LOOPBACK
1298 if (ifn->if_flags & IFF_LOOPBACK) {
1299 sa->sa_iprank = TOPR;
1302 # endif /* IFF_LOOPBACK */
1303 sin = (struct sockaddr_in *)IA_SIN(ifad);
1304 if (SA2ULONG(sin) == sa->sa_ip) {
1305 sa->sa_iprank = TOPR;
1308 # ifdef IFF_BROADCAST
1309 if (ifn->if_flags & IFF_BROADCAST) {
1310 if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1315 # endif /* IFF_BROADCAST */
1316 # ifdef IFF_POINTOPOINT
1317 if (ifn->if_flags & IFF_POINTOPOINT) {
1318 if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1319 if (ifn->if_metric > 4) {
1323 sa->sa_iprank = ifn->if_metric;
1326 # endif /* IFF_POINTOPOINT */
1327 sa->sa_iprank += MED + ifn->if_metric; /* couldn't find anything better */
1329 # else /* USEIFADDR */
1333 (void)hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1334 (caddr_t) sa, NULL);
1335 # elif defined(AFS_DARWIN80_ENV)
1343 if (!ifnet_list_get(AF_INET, &ifns, &count)) {
1344 for (m = 0; m < count; m++) {
1345 if (!ifnet_get_address_list(ifns[m], &ifads)) {
1346 for (j = 0; ifads[j] != NULL && cnt < ADDRSPERSITE; j++) {
1347 afsi_SetServerIPRank(sa, ifads[j]);
1350 ifnet_free_address_list(ifads);
1353 ifnet_list_free(ifns);
1356 # elif defined(AFS_DARWIN_ENV)
1360 TAILQ_FOREACH(ifn, &ifnet, if_link) {
1361 TAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) {
1362 afsi_SetServerIPRank(sa, ifa);
1364 # elif defined(AFS_FBSD_ENV)
1366 struct in_ifaddr *ifa;
1367 struct rm_priotracker in_ifa_tracker;
1368 CURVNET_SET(rx_socket->so_vnet);
1369 IN_IFADDR_RLOCK(&in_ifa_tracker);
1370 AFS_FBSD_NET_FOREACH(ifa, &V_in_ifaddrhead, ia_link) {
1371 afsi_SetServerIPRank(sa, &ifa->ia_ifa);
1373 IN_IFADDR_RUNLOCK(&in_ifa_tracker);
1376 # elif defined(AFS_OBSD_ENV)
1378 extern struct in_ifaddrhead in_ifaddr;
1379 struct in_ifaddr *ifa;
1380 for (ifa = in_ifaddr.tqh_first; ifa; ifa = ifa->ia_list.tqe_next)
1381 afsi_SetServerIPRank(sa, ifa);
1383 # elif defined(AFS_NBSD40_ENV)
1385 extern struct in_ifaddrhead in_ifaddrhead;
1386 struct in_ifaddr *ifa;
1387 for (ifa = in_ifaddrhead.tqh_first; ifa; ifa = ifa->ia_list.tqe_next)
1388 afsi_SetServerIPRank(sa, ifa);
1392 struct in_ifaddr *ifa;
1393 for (ifa = in_ifaddr; ifa; ifa = ifa->ia_next) {
1394 afsi_SetServerIPRank(sa, ifa);
1397 # endif /* USEIFADDR */
1401 # endif /* AFS_SUN5_ENV */
1402 #endif /* AFS_USERSPACE_IP_ADDR */
1403 sa->sa_iprank += afs_randomMod15();
1406 } /* afs_SetServerPrefs */
1414 /* afs_FlushServer()
1415 * The addresses on this server struct has changed in some way and will
1416 * clean up all other structures that may reference it.
1417 * The afs_xserver, afs_xvcb and afs_xsrvAddr locks are assumed taken.
1420 afs_FlushServer(struct server *srvp, struct volume *tv)
1423 struct server *ts, **pts;
1425 /* Find any volumes residing on this server and flush their state */
1426 afs_ResetVolumes(srvp, tv);
1428 /* Flush all callbacks in the all vcaches for this specific server */
1429 afs_FlushServerCBs(srvp);
1431 /* Remove all the callbacks structs */
1433 struct afs_cbr *cb, *cbnext;
1435 for (cb = srvp->cbrs; cb; cb = cbnext) {
1438 } srvp->cbrs = (struct afs_cbr *)0;
1441 /* If no more srvAddr structs hanging off of this server struct,
1445 /* Remove the server structure from the cell list - if there */
1446 afs_RemoveCellEntry(srvp);
1448 /* Remove from the afs_servers hash chain */
1449 for (i = 0; i < NSERVERS; i++) {
1450 for (pts = &(afs_servers[i]), ts = *pts; ts;
1451 pts = &(ts->next), ts = *pts) {
1459 *pts = ts->next; /* Found it. Remove it */
1460 afs_osi_Free(ts, sizeof(struct server)); /* Free it */
1466 /* afs_RemoveSrvAddr()
1467 * This removes a SrvAddr structure from its server structure.
1468 * The srvAddr struct is not free'd because it connections may still
1469 * be open to it. It is up to the calling process to make sure it
1470 * remains connected to a server struct.
1471 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1472 * It is not removed from the afs_srvAddrs hash chain.
1473 * If resetting volumes, do not reset volume tv
1476 afs_RemoveSrvAddr(struct srvAddr *sap, struct volume *tv)
1478 struct srvAddr **psa, *sa;
1485 /* Find the srvAddr in the server's list and remove it */
1486 for (psa = &(srv->addr), sa = *psa; sa; psa = &(sa->next_sa), sa = *psa) {
1494 /* Flush the server struct since it's IP address has changed */
1495 afs_FlushServer(srv, tv);
1499 /* afs_GetCapabilities
1500 * Try and retrieve capabilities of a given file server. Carps on actual
1501 * failure. Servers are not expected to support this RPC. */
1503 afs_GetCapabilities(struct server *ts)
1505 Capabilities caps = {0, NULL};
1506 struct vrequest *treq = NULL;
1507 struct afs_conn *tc;
1508 struct unixuser *tu;
1509 struct rx_connection *rxconn;
1512 if ( !ts || !ts->cell )
1514 if ( !afs_osi_credp )
1517 if ((code = afs_CreateReq(&treq, afs_osi_credp)))
1519 tu = afs_GetUser(treq->uid, ts->cell->cellNum, SHARED_LOCK);
1521 afs_DestroyReq(treq);
1524 tc = afs_ConnBySA(ts->addr, ts->cell->fsport, ts->cell->cellNum, tu, 0, 1,
1525 SHARED_LOCK, 0, &rxconn);
1526 afs_PutUser(tu, SHARED_LOCK);
1528 afs_DestroyReq(treq);
1531 /* InitCallBackStateN, triggered by our RPC, may need this */
1532 ReleaseWriteLock(&afs_xserver);
1534 code = RXAFS_GetCapabilities(rxconn, &caps);
1536 ObtainWriteLock(&afs_xserver, 723);
1537 /* we forced a conn above; important we mark it down if needed */
1538 if ((code < 0) && (code != RXGEN_OPCODE)) {
1539 afs_ServerDown(tc->parent->srvr, code, rxconn);
1540 ForceNewConnections(tc->parent->srvr); /* multi homed clients */
1542 afs_PutConn(tc, rxconn, SHARED_LOCK);
1543 if ( code && code != RXGEN_OPCODE ) {
1544 afs_warn("RXAFS_GetCapabilities failed with code %d\n", code);
1545 /* better not be anything to free. we failed! */
1546 afs_DestroyReq(treq);
1550 ts->flags |= SCAPS_KNOWN;
1552 if ( caps.Capabilities_len > 0 ) {
1553 ts->capabilities = caps.Capabilities_val[0];
1554 xdr_free((xdrproc_t)xdr_Capabilities, &caps);
1555 caps.Capabilities_len = 0;
1556 caps.Capabilities_val = NULL;
1559 afs_DestroyReq(treq);
1562 static struct server *
1563 afs_SearchServer(u_short aport, afsUUID * uuidp, afs_int32 locktype,
1564 struct server **oldts, afs_int32 addr_uniquifier)
1566 struct server *ts = afs_FindServer(0, aport, uuidp, locktype);
1567 if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1568 /* Found a server struct that is multihomed and same
1569 * uniqufier (same IP addrs). The above if statement is the
1570 * same as in InstallUVolumeEntry().
1575 *oldts = ts; /* Will reuse if same uuid */
1580 * Return an updated and properly initialized server structure.
1582 * Takes a server ID, cell, and port.
1583 * If server does not exist, then one will be created.
1584 * @param[in] aserverp
1585 * The server address in network byte order
1586 * @param[in] nservers
1587 * The number of IP addresses claimed by the server
1589 * The cell the server is in
1591 * The port for the server (fileserver or vlserver) in network byte order
1592 * @param[in] locktype
1593 * The type of lock to hold when iterating server hash (unused).
1595 * The uuid for servers supporting one.
1596 * @param[in] addr_uniquifier
1597 * The vldb-provider per-instantiated-server uniquifer counter.
1599 * A volume not to reset information for if the server addresses
1603 * A server structure matching the request.
1606 afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers, afs_int32 acell,
1607 u_short aport, afs_int32 locktype, afsUUID * uuidp,
1608 afs_int32 addr_uniquifier, struct volume *tv)
1610 struct server *oldts = 0, *ts, *newts, *orphts = 0;
1611 struct srvAddr *oldsa, *newsa, *nextsa, *orphsa;
1612 afs_int32 iphash, k, srvcount = 0;
1613 unsigned int srvhash;
1615 AFS_STATCNT(afs_GetServer);
1617 ObtainSharedLock(&afs_xserver, 13);
1619 /* Check if the server struct exists and is up to date */
1622 panic("afs_GetServer: incorrect count of servers");
1623 ObtainReadLock(&afs_xsrvAddr);
1624 ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1625 ReleaseReadLock(&afs_xsrvAddr);
1626 if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1627 /* Found a server struct that is not multihomed and has the
1628 * IP address associated with it. A correct match.
1630 ReleaseSharedLock(&afs_xserver);
1635 panic("afs_GetServer: incorrect count of servers");
1637 ts = afs_SearchServer(aport, uuidp, locktype, &oldts, addr_uniquifier);
1639 ReleaseSharedLock(&afs_xserver);
1645 * Lock hierarchy requires xvcb, then xserver. We *have* xserver.
1646 * Do a little dance and see if we can grab xvcb. If not, we
1647 * need to recheck that oldts is still right after a drop and reobtain.
1649 if (EWOULDBLOCK == NBObtainWriteLock(&afs_xvcb, 300)) {
1650 ReleaseSharedLock(&afs_xserver);
1651 ObtainWriteLock(&afs_xvcb, 299);
1652 ObtainWriteLock(&afs_xserver, 35);
1654 /* we don't know what changed while we didn't hold the lock */
1656 ts = afs_SearchServer(aport, uuidp, locktype, &oldts,
1659 ReleaseWriteLock(&afs_xserver);
1660 ReleaseWriteLock(&afs_xvcb);
1664 UpgradeSToWLock(&afs_xserver, 36);
1666 ObtainWriteLock(&afs_xsrvAddr, 116);
1667 srvcount = afs_totalServers;
1669 /* Reuse/allocate a new server structure */
1673 newts = afs_osi_Alloc(sizeof(struct server));
1675 panic("malloc of server struct");
1677 memset(newts, 0, sizeof(struct server));
1679 /* Add the server struct to the afs_servers[] hash chain */
1681 (uuidp ? (afs_uuid_hash(uuidp) % NSERVERS) : SHash(aserverp[0]));
1682 newts->next = afs_servers[srvhash];
1683 afs_servers[srvhash] = newts;
1686 /* Initialize the server structure */
1687 if (uuidp) { /* Multihomed */
1688 newts->sr_uuid = *uuidp;
1689 newts->sr_addr_uniquifier = addr_uniquifier;
1690 newts->flags |= SRVR_MULTIHOMED;
1693 /* Use the afs_GetCellStale variant to avoid afs_GetServer recursion. */
1694 newts->cell = afs_GetCellStale(acell, 0);
1696 /* For each IP address we are registering */
1697 for (k = 0; k < nservers; k++) {
1698 iphash = SHash(aserverp[k]);
1700 /* Check if the srvAddr structure already exists. If so, remove
1701 * it from its server structure and add it to the new one.
1703 for (oldsa = afs_srvAddrs[iphash]; oldsa; oldsa = oldsa->next_bkt) {
1704 if ((oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport))
1707 if (oldsa && (oldsa->server != newts)) {
1708 afs_RemoveSrvAddr(oldsa, tv); /* Remove from its server struct */
1709 oldsa->next_sa = newts->addr; /* Add to the new server struct */
1710 newts->addr = oldsa;
1713 /* Reuse/allocate a new srvAddr structure */
1717 newsa = afs_osi_Alloc(sizeof(struct srvAddr));
1719 panic("malloc of srvAddr struct");
1720 afs_totalSrvAddrs++;
1721 memset(newsa, 0, sizeof(struct srvAddr));
1723 /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1724 newsa->next_bkt = afs_srvAddrs[iphash];
1725 afs_srvAddrs[iphash] = newsa;
1727 /* Hang off of the server structure */
1728 newsa->next_sa = newts->addr;
1729 newts->addr = newsa;
1731 /* Initialize the srvAddr Structure */
1732 newsa->sa_ip = aserverp[k];
1733 newsa->sa_portal = aport;
1736 /* Update the srvAddr Structure */
1737 newsa->server = newts;
1738 if (newts->flags & SRVR_ISDOWN)
1739 newsa->sa_flags |= SRVADDR_ISDOWN;
1741 newsa->sa_flags |= SRVADDR_MH;
1743 newsa->sa_flags &= ~SRVADDR_MH;
1745 /* Compute preference values and resort */
1746 if (!newsa->sa_iprank) {
1747 afs_SetServerPrefs(newsa); /* new server rank */
1750 afs_SortOneServer(newts); /* Sort by rank */
1752 /* If we reused the server struct, remove any of its srvAddr
1753 * structs that will no longer be associated with this server.
1755 if (oldts) { /* reused the server struct */
1756 for (orphsa = newts->addr; orphsa; orphsa = nextsa) {
1757 nextsa = orphsa->next_sa;
1758 for (k = 0; k < nservers; k++) {
1759 if (orphsa->sa_ip == aserverp[k])
1760 break; /* belongs */
1763 continue; /* belongs */
1765 /* Have a srvAddr struct. Now get a server struct (if not already) */
1767 orphts = afs_osi_Alloc(sizeof(struct server));
1769 panic("malloc of lo server struct");
1770 memset(orphts, 0, sizeof(struct server));
1773 /* Add the orphaned server to the afs_servers[] hash chain.
1774 * Its iphash does not matter since we never look up the server
1775 * in the afs_servers table by its ip address (only by uuid -
1776 * which this has none).
1778 iphash = SHash(aserverp[k]);
1779 orphts->next = afs_servers[iphash];
1780 afs_servers[iphash] = orphts;
1783 /* Use the afs_GetCellStale variant to avoid afs_GetServer recursion. */
1784 orphts->cell = afs_GetCellStale(acell, 0);
1787 /* Hang the srvAddr struct off of the server structure. The server
1788 * may have multiple srvAddrs, but it won't be marked multihomed.
1790 afs_RemoveSrvAddr(orphsa, tv); /* remove */
1791 orphsa->next_sa = orphts->addr; /* hang off server struct */
1792 orphts->addr = orphsa;
1793 orphsa->server = orphts;
1794 orphsa->sa_flags |= SRVADDR_NOUSE; /* flag indicating not in use */
1795 orphsa->sa_flags &= ~SRVADDR_MH; /* Not multihomed */
1798 /* We can't need this below, and won't reacquire */
1799 ReleaseWriteLock(&afs_xvcb);
1801 srvcount = afs_totalServers - srvcount; /* # servers added and removed */
1803 struct afs_stats_SrvUpDownInfo *upDownP;
1804 /* With the introduction of this new record, we need to adjust the
1805 * proper individual & global server up/down info.
1807 upDownP = GetUpDownStats(newts);
1808 upDownP->numTtlRecords += srvcount;
1809 afs_stats_cmperf.srvRecords += srvcount;
1810 if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1811 afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1814 ReleaseWriteLock(&afs_xsrvAddr);
1816 if ( aport == AFS_FSPORT && !(newts->flags & SCAPS_KNOWN))
1817 afs_GetCapabilities(newts);
1819 ReleaseWriteLock(&afs_xserver);
1821 } /* afs_GetServer */
1824 afs_ActivateServer(struct srvAddr *sap)
1826 osi_timeval32_t currTime; /*Filled with current time */
1827 osi_timeval32_t *currTimeP; /*Ptr to above */
1828 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record */
1829 struct server *aserver = sap->server;
1831 if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1833 * This server record has not yet been activated. Go for it,
1834 * recording its ``birth''.
1836 aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1837 currTimeP = &currTime;
1838 osi_GetTime(currTimeP);
1839 aserver->activationTime = currTime.tv_sec;
1840 upDownP = GetUpDownStats(aserver);
1841 if (aserver->flags & SRVR_ISDOWN) {
1842 upDownP->numDownRecords++;
1844 upDownP->numUpRecords++;
1845 upDownP->numRecordsNeverDown++;
1851 afs_RemoveAllConns(void)
1854 struct server *ts, *nts;
1857 ObtainReadLock(&afs_xserver);
1858 ObtainWriteLock(&afs_xconn, 1001);
1860 /*printf("Destroying connections ... ");*/
1861 for (i = 0; i < NSERVERS; i++) {
1862 for (ts = afs_servers[i]; ts; ts = nts) {
1864 for (sa = ts->addr; sa; sa = sa->next_sa) {
1866 afs_ReleaseConns(sa->conns);
1873 /*printf("done\n");*/
1875 ReleaseWriteLock(&afs_xconn);
1876 ReleaseReadLock(&afs_xserver);
1881 afs_MarkAllServersUp(void)
1887 ObtainWriteLock(&afs_xserver, 721);
1888 ObtainWriteLock(&afs_xsrvAddr, 722);
1889 for (i = 0; i< NSERVERS; i++) {
1890 for (ts = afs_servers[i]; ts; ts = ts->next) {
1891 for (sa = ts->addr; sa; sa = sa->next_sa) {
1892 afs_MarkServerUpOrDown(sa, 0);
1896 ReleaseWriteLock(&afs_xsrvAddr);
1897 ReleaseWriteLock(&afs_xserver);