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/stds.h"
38 #include "../afs/sysincludes.h" /* Standard vendor system headers */
42 #include <netinet/in.h>
45 #include "../h/hashing.h"
47 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
48 #include <netinet/in_var.h>
49 #endif /* AFS_HPUX110_ENV */
50 #ifdef AFS_DARWIN60_ENV
51 #include <net/if_var.h>
53 #endif /* !defined(UKERNEL) */
55 #include "../afs/afsincludes.h" /* Afs-based standard headers */
56 #include "../afs/afs_stats.h" /* afs statistics */
58 #if defined(AFS_SUN56_ENV)
60 #include <inet/common.h>
61 #if defined(AFS_SUN58_ENV)
62 # include <netinet/ip6.h>
63 # define ipif_local_addr ipif_lcl_addr
64 # ifndef V4_PART_OF_V6
65 # 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_setTimeHost=0; /* last host we used for time */
74 struct server *afs_servers[NSERVERS]; /* Hashed by server`s uuid & 1st ip */
75 afs_rwlock_t afs_xsrvAddr; /* allocation lock for srvAddrs */
76 struct srvAddr *afs_srvAddrs[NSERVERS]; /* Hashed by server's ip */
79 /* debugging aids - number of alloc'd server and srvAddr structs. */
80 int afs_reuseServers = 0;
81 int afs_reuseSrvAddrs = 0;
82 int afs_totalServers = 0;
83 int afs_totalSrvAddrs = 0;
88 /*------------------------------------------------------------------------
89 * afs_MarkServerUpOrDown
92 * Mark the given server up or down, and track its uptime stats.
95 * a_serverP : Ptr to server record to fiddle with.
96 * a_isDown : Is the server is to be marked down?
102 * The CM server structures must be write-locked.
106 *------------------------------------------------------------------------*/
108 void afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
110 register struct server *a_serverP = sa->server;
111 register struct srvAddr *sap;
112 osi_timeval_t currTime, *currTimeP; /*Current time*/
113 afs_int32 downTime; /*Computed downtime, in seconds*/
114 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
117 * If the server record is marked the same as the new status we've
118 * been fed, then there isn't much to be done.
120 if (( a_isDown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
121 (!a_isDown && !(sa->sa_flags & SRVADDR_ISDOWN)))
125 sa->sa_flags |= SRVADDR_ISDOWN;
126 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
127 if (!(sap->sa_flags & SRVADDR_ISDOWN)) {
128 /* Not all ips are up so don't bother with the
129 * server's up/down stats */
134 * All ips are down we treat the whole server down
136 a_serverP->flags |= SRVR_ISDOWN;
138 * If this was our time server, search for another time server
140 if (a_serverP == afs_setTimeHost)
143 sa->sa_flags &= ~SRVADDR_ISDOWN;
144 /* If any ips are up, the server is also marked up */
145 a_serverP->flags &= ~SRVR_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 */
156 * Compute the current time and which overall stats record is to be
157 * updated; we'll need them one way or another.
159 currTimeP = &currTime;
160 osi_GetuTime(currTimeP);
162 if (sa->sa_portal == AFS_FSPORT) {
163 upDownP = (a_serverP->cell->cell == 1) ?
164 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
165 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
166 } /*File Server record*/
168 upDownP = (a_serverP->cell->cell == 1) ?
169 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
170 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
171 } /*VL Server record*/
175 * Server going up -> down; remember the beginning of this
178 a_serverP->lastDowntimeStart = currTime.tv_sec;
180 (upDownP->numDownRecords)++;
181 (upDownP->numUpRecords)--;
182 } /*Server being marked down*/
185 * Server going down -> up; remember everything about this
186 * newly-completed downtime incident.
188 downTime = currTime.tv_sec - a_serverP->lastDowntimeStart;
189 (a_serverP->numDowntimeIncidents)++;
190 a_serverP->sumOfDowntimes += downTime;
192 (upDownP->numUpRecords)++;
193 (upDownP->numDownRecords)--;
194 (upDownP->numDowntimeIncidents)++;
195 if (a_serverP->numDowntimeIncidents == 1)
196 (upDownP->numRecordsNeverDown)--;
197 upDownP->sumOfDowntimes += downTime;
198 if ((upDownP->shortestDowntime == 0) ||
199 (downTime < upDownP->shortestDowntime))
200 upDownP->shortestDowntime = downTime;
201 if ((upDownP->longestDowntime == 0) ||
202 (downTime > upDownP->longestDowntime))
203 upDownP->longestDowntime = downTime;
206 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET0)
207 (upDownP->downDurations[0])++;
209 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET1)
210 (upDownP->downDurations[1])++;
212 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET2)
213 (upDownP->downDurations[2])++;
215 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET3)
216 (upDownP->downDurations[3])++;
218 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET4)
219 (upDownP->downDurations[4])++;
221 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET5)
222 (upDownP->downDurations[5])++;
224 (upDownP->downDurations[6])++;
226 } /*Server being marked up*/
228 } /*MarkServerUpOrDown*/
231 void afs_ServerDown(struct srvAddr *sa)
233 register struct server *aserver = sa->server;
234 register struct srvAddr *sap;
236 AFS_STATCNT(ServerDown);
237 if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
239 afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
240 if (sa->sa_portal == aserver->cell->vlport)
241 print_internet_address("afs: Lost contact with volume location server ",
244 print_internet_address("afs: Lost contact with file server ", sa, "", 1);
249 /* return true if we have any callback promises from this server */
250 static int HaveCallBacksFrom(struct server *aserver)
252 register afs_int32 now;
254 register struct vcache *tvc;
256 AFS_STATCNT(HaveCallBacksFrom);
257 now = osi_Time(); /* for checking for expired callbacks */
258 for(i=0;i<VCSIZE;i++) { /* for all guys in the hash table */
259 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
261 * Check to see if this entry has an unexpired callback promise
262 * from the required host
264 if (aserver == tvc->callback && tvc->cbExpires >= now
265 && ((tvc->states & CRO) == 0))
271 } /*HaveCallBacksFrom*/
274 static void CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
276 register struct server *aserver = sa->server;
277 register struct conn *tc;
278 register afs_int32 code;
280 AFS_STATCNT(CheckVLServer);
281 /* Ping dead servers to see if they're back */
282 if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN)) || (aserver->flags & SRVR_ISGONE))
285 return; /* can't do much */
287 tc = afs_ConnByHost(aserver, aserver->cell->vlport,
288 aserver->cell->cell, areq, 1, SHARED_LOCK);
291 rx_SetConnDeadTime(tc->id, 3);
294 code = VL_ProbeServer(tc->id);
296 rx_SetConnDeadTime(tc->id, AFS_RXDEADTIME);
297 afs_PutConn(tc, SHARED_LOCK);
299 * If probe worked, or probe call not yet defined (for compatibility
300 * with old vlsevers), then we treat this server as running again
302 if (code == 0 || (code <= -450 && code >= -470)) {
303 if (tc->srvr == sa) {
304 afs_MarkServerUpOrDown(sa, 0);
305 print_internet_address("afs: volume location server ",
306 sa, " is back up", 2);
313 #ifndef AFS_MINCHANGE /* So that some can increase it in param.h */
314 #define AFS_MINCHANGE 2 /* min change we'll bother with */
316 #ifndef AFS_MAXCHANGEBACK
317 #define AFS_MAXCHANGEBACK 10 /* max seconds we'll set a clock back at once */
321 /*------------------------------------------------------------------------
322 * EXPORTED afs_CountServers
325 * Originally meant to count the number of servers and determining
326 * up/down info, this routine will now simply sum up all of the
327 * server record ages. All other up/down information is kept on the
337 * This routine locks afs_xserver for write for the duration.
340 * Set CM perf stats field sumOfRecordAges for all server record
342 *------------------------------------------------------------------------*/
344 void afs_CountServers(void)
346 int currIdx; /*Curr idx into srv table*/
347 struct server *currSrvP; /*Ptr to curr server record*/
348 afs_int32 currChainLen; /*Length of curr hash chain*/
349 osi_timeval_t currTime; /*Current time*/
350 osi_timeval_t *currTimeP; /*Ptr to above*/
351 afs_int32 srvRecordAge; /*Age of server record, in secs*/
352 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to current up/down
353 info being manipulated*/
356 * Write-lock the server table so we don't get any interference.
358 ObtainReadLock(&afs_xserver);
361 * Iterate over each hash index in the server table, walking down each
362 * chain and tallying what we haven't computed from the records there on
363 * the fly. First, though, initialize the tallies that will change.
365 afs_stats_cmperf.srvMaxChainLength = 0;
367 afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
368 afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
369 afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
370 memset((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
372 afs_stats_cmperf.fs_UpDown[1].sumOfRecordAges = 0;
373 afs_stats_cmperf.fs_UpDown[1].ageOfYoungestRecord = 0;
374 afs_stats_cmperf.fs_UpDown[1].ageOfOldestRecord = 0;
375 memset((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
377 afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges = 0;
378 afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
379 afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord = 0;
380 memset((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
382 afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges = 0;
383 afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
384 afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord = 0;
385 memset((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
388 * Compute the current time, used to figure out server record ages.
390 currTimeP = &currTime;
391 osi_GetuTime(currTimeP);
394 * Sweep the server hash table, tallying all we need to know.
396 for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
398 for (currSrvP = afs_servers[currIdx]; currSrvP; currSrvP = currSrvP->next) {
400 * Bump the current chain length.
405 * Any further tallying for this record will only be done if it has
408 if ( (currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED) &&
409 currSrvP->addr && currSrvP->cell ) {
412 * Compute the current server record's age, then remember it
413 * in the appropriate places.
415 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
416 if (currSrvP->addr->sa_portal == AFS_FSPORT) {
417 upDownP = (currSrvP->cell->cell == 1) ?
418 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]):
419 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
420 } /*File Server record*/
422 upDownP = (currSrvP->cell->cell == 1) ?
423 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]):
424 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
425 } /*VL Server record*/
427 upDownP->sumOfRecordAges += srvRecordAge;
428 if ((upDownP->ageOfYoungestRecord == 0) ||
429 (srvRecordAge < upDownP->ageOfYoungestRecord))
430 upDownP->ageOfYoungestRecord = srvRecordAge;
431 if ((upDownP->ageOfOldestRecord == 0) ||
432 (srvRecordAge > upDownP->ageOfOldestRecord))
433 upDownP->ageOfOldestRecord = srvRecordAge;
435 if (currSrvP->numDowntimeIncidents <=
436 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
437 (upDownP->downIncidents[0])++;
439 if (currSrvP->numDowntimeIncidents <=
440 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
441 (upDownP->downIncidents[1])++;
443 if (currSrvP->numDowntimeIncidents <=
444 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
445 (upDownP->downIncidents[2])++;
447 if (currSrvP->numDowntimeIncidents <=
448 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
449 (upDownP->downIncidents[3])++;
451 if (currSrvP->numDowntimeIncidents <=
452 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
453 (upDownP->downIncidents[4])++;
455 (upDownP->downIncidents[5])++;
458 } /*Current server has been active*/
459 } /*Walk this chain*/
462 * Before advancing to the next chain, remember facts about this one.
464 if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
466 * We beat out the former champion (which was initially set to 0
467 * here). Mark down the new winner, and also remember if it's an
470 afs_stats_cmperf.srvMaxChainLength = currChainLen;
471 if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
472 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
473 } /*Update chain length maximum*/
474 } /*For each hash chain*/
477 * We're done. Unlock the server table before returning to our caller.
479 ReleaseReadLock(&afs_xserver);
481 } /*afs_CountServers*/
484 /* check down servers (if adown), or running servers (if !adown) */
485 void afs_CheckServers(int adown, struct cell *acellp)
487 struct vrequest treq;
493 afs_int32 start, end, delta;
499 struct srvAddr **addrs;
502 AFS_STATCNT(afs_CheckServers);
503 if ((code = afs_InitReq(&treq, &afs_osi_cred))) return;
504 ObtainReadLock(&afs_xserver); /* Necessary? */
505 ObtainReadLock(&afs_xsrvAddr);
508 for (i=0;i<NSERVERS;i++) {
509 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
514 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
516 for (i=0;i<NSERVERS;i++) {
517 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
518 if (j >= srvAddrCount) break;
523 ReleaseReadLock(&afs_xsrvAddr);
524 ReleaseReadLock(&afs_xserver);
526 for (i=0; i<j; i++) {
532 /* See if a cell to check was specified. If it is spec'd and not
533 * this server's cell, just skip the server.
535 if (acellp && acellp != ts->cell)
538 if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
539 (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
542 /* check vlserver with special code */
543 if (sa->sa_portal == AFS_VLPORT) {
544 CheckVLServer(sa, &treq);
548 if (!ts->cell) /* not really an active server, anyway, it must */
549 continue; /* have just been added by setsprefs */
551 /* get a connection, even if host is down; bumps conn ref count */
552 tu = afs_GetUser(treq.uid, ts->cell->cell, SHARED_LOCK);
553 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cell, tu,
554 1/*force*/, 1/*create*/, SHARED_LOCK);
555 afs_PutUser(tu, SHARED_LOCK);
558 if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
559 (tc->srvr->server == afs_setTimeHost)) {
560 if (sa->sa_flags & SRVADDR_ISDOWN) {
561 rx_SetConnDeadTime(tc->id, 3);
567 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
568 start = osi_Time(); /* time the gettimeofday call */
570 code = RXAFS_GetTime(tc->id, (afs_int32 *)&tv.tv_sec, (afs_int32 *)&tv.tv_usec);
575 * If we're supposed to set the time, and the call worked
576 * quickly (same second response) and this is the host we
577 * use for the time and the time is really different, then
578 * really set the time
580 if (code == 0 && start == end && afs_setTime != 0 &&
581 (tc->srvr->server == afs_setTimeHost ||
583 * Sync only to a server in the local cell: cell(id)==1
586 (afs_setTimeHost == (struct server *)0 &&
587 (ts->cell->cell == 1 || (ts->cell->states&CPrimary))))) {
589 char msgbuf[90]; /* strlen("afs: setting clock...") + slop */
591 delta = end - tv.tv_sec; /* how many secs fast we are */
592 /* see if clock has changed enough to make it worthwhile */
593 if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
594 if (delta > AFS_MAXCHANGEBACK) {
595 /* setting clock too far back, just do it a little */
596 tv.tv_sec = end - AFS_MAXCHANGEBACK;
598 afs_osi_SetTime(&tv);
600 strcpy(msgbuf, "afs: setting clock back ");
601 if (delta > AFS_MAXCHANGEBACK) {
602 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
603 afs_strcat(msgbuf, " seconds (of ");
604 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
605 afs_strcat(msgbuf, ", via ");
606 print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
608 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
609 afs_strcat(msgbuf, " seconds (via ");
610 print_internet_address(msgbuf, sa, ").", 0);
613 strcpy(msgbuf, "afs: setting clock ahead ");
614 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
615 afs_strcat(msgbuf, " seconds (via ");
616 print_internet_address(msgbuf, sa, ").", 0);
619 afs_setTimeHost = tc->srvr->server;
622 rx_SetConnDeadTime(tc->id, AFS_RXDEADTIME);
623 if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
625 print_internet_address("afs: file server ", sa, " is back up", 2);
627 ObtainWriteLock(&afs_xserver, 244);
628 ObtainWriteLock(&afs_xsrvAddr, 245);
629 afs_MarkServerUpOrDown(sa, 0);
630 ReleaseWriteLock(&afs_xsrvAddr);
631 ReleaseWriteLock(&afs_xserver);
633 if (afs_waitForeverCount) {
634 afs_osi_Wakeup(&afs_waitForever);
640 ForceNewConnections(sa); /* multi homed clients */
645 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
646 } /* Outer loop over addrs */
648 afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
650 } /*afs_CheckServers*/
653 /* find a server structure given the host address */
654 struct server *afs_FindServer (afs_int32 aserver, ushort aport,
655 afsUUID *uuidp, afs_int32 locktype)
661 AFS_STATCNT(afs_FindServer);
663 i = afs_uuid_hash(uuidp) % NSERVERS;
664 for (ts = afs_servers[i]; ts; ts = ts->next) {
665 if ( (ts->flags & SRVR_MULTIHOMED) &&
666 (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
667 (!ts->addr || (ts->addr->sa_portal == aport)) )
672 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
673 if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
683 /* some code for creating new server structs and setting preferences follows
684 * in the next few lines...
687 #define MAXDEFRANK 60000
688 #define DEFRANK 40000
690 /* Random number generator and constants from KnuthV2 2d ed, p170 */
696 a is 0.73m should be 0.01m .. 0.99m
697 c is more or less immaterial. 1 or a is suggested.
699 NB: LOW ORDER BITS are not very random. To get small random numbers,
700 treat result as <1, with implied binary point, and multiply by
702 NB: Has to be unsigned, since shifts on signed quantities may preserve
705 /* added rxi_getaddr() to try to get as much initial randomness as
706 possible, since at least one customer reboots ALL their clients
707 simultaneously -- so osi_Time is bound to be the same on some of the
708 clients. This is probably OK, but I don't want to see too much of it.
711 #define ranstage(x) (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
713 unsigned int afs_random(void)
715 static afs_int32 state = 0;
718 AFS_STATCNT(afs_random);
723 * 0xfffffff0 was changed to (~0 << 4) since it works no matter how many
724 * bits are in a tv_usec
726 state = (t.tv_usec & (~0 << 4) ) + (rxi_getaddr() & 0xff);
727 state += (t.tv_sec & 0xff);
738 /* returns int 0..14 using the high bits of a pseudo-random number instead of
739 the low bits, as the low bits are "less random" than the high ones...
740 slight roundoff error exists, an excercise for the reader.
741 need to multiply by something with lots of ones in it, so multiply by
742 8 or 16 is right out.
744 int afs_randomMod15(void)
748 temp = afs_random() >> 4;
749 temp = (temp *15) >> 28;
754 int afs_randomMod127(void)
758 temp = afs_random() >> 7;
759 temp = (temp *127) >> 25;
764 /* afs_SortOneServer()
765 * Sort all of the srvAddrs, of a server struct, by rank from low to high.
767 void afs_SortOneServer(struct server *asp)
769 struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
772 for (rootsa=&(asp->addr); *rootsa; rootsa=&(lowsa->next_sa)) {
774 lowsa = *rootsa; /* lowest sa is the first one */
775 lowrank = lowsa->sa_iprank;
777 for (tsa=*rootsa; tsa->next_sa; tsa=tsa->next_sa) {
778 rank = tsa->next_sa->sa_iprank;
779 if (rank < lowrank) {
781 lowsa = tsa->next_sa;
782 lowrank = lowsa->sa_iprank;
785 if (lowprev) { /* found one lower, so rearrange them */
786 lowprev->next_sa = lowsa->next_sa;
787 lowsa->next_sa = *rootsa;
794 * Sort the pointer to servers by the server's rank (its lowest rank).
795 * It is assumed that the server already has its IP addrs sorted (the
796 * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
798 void afs_SortServers(struct server *aservers[], int count)
803 AFS_STATCNT(afs_SortServers);
805 for (i=0; i<count; i++) {
806 if (!aservers[i]) break;
807 for (low=i,j=i+1; j<=count; j++) {
808 if ((!aservers[j]) || (!aservers[j]->addr))
810 if ((!aservers[low]) || (!aservers[low]->addr))
812 if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
818 aservers[i] = aservers[low];
822 } /*afs_SortServers*/
824 /* afs_SetServerPrefs is rather system-dependent. It pokes around in kernel
825 data structures to determine what the local IP addresses and subnet masks
826 are in order to choose which server(s) are on the local subnet.
828 As I see it, there are several cases:
829 1. The server address is one of this host's local addresses. In this case
830 this server is to be preferred over all others.
831 2. The server is on the same subnet as one of the this host's local
832 addresses. (ie, an odd-sized subnet, not class A,B,orC)
833 3. The server is on the same net as this host (class A,B or C)
834 4. The server is on a different logical subnet or net than this host, but
835 this host is a 'metric 0 gateway' to it. Ie, two address-spaces share
837 5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
839 6. This host and the server are disjoint.
841 That is a rough order of preference. If a point-to-point link has a high
842 metric, I'm assuming that it is a very slow link, and putting it at the
843 bottom of the list (at least until RX works better over slow links). If
844 its metric is 1, I'm assuming that it's relatively fast (T1) and putting
846 It's not easy to check for case #4, so I'm ignoring it for the time being.
848 BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
849 That could be used to prefer certain servers fairly easily. Maybe some
852 NOTE: this code is very system-dependent, and very dependent on the TCP/IP
853 protocols (well, addresses that are stored in uint32s, at any rate).
856 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
857 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
859 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
860 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
865 #define PPWEIGHT 4096
870 #if defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
871 #include <inet/common.h>
872 /* IP interface structure, one per local address */
873 typedef struct ipif_s { /**/
874 struct ipif_s * ipif_next;
875 struct ill_s * ipif_ill; /* Back pointer to our ill */
876 long ipif_id; /* Logical unit number */
877 u_int ipif_mtu; /* Starts at ipif_ill->ill_max_frag */
878 afs_int32 ipif_local_addr; /* Local IP address for this if. */
879 afs_int32 ipif_net_mask; /* Net mask for this interface. */
880 afs_int32 ipif_broadcast_addr; /* Broadcast addr for this interface. */
881 afs_int32 ipif_pp_dst_addr; /* Point-to-point dest address. */
882 u_int ipif_flags; /* Interface flags. */
883 u_int ipif_metric; /* BSD if metric, for compatibility. */
884 u_int ipif_ire_type; /* LOCAL or LOOPBACK */
885 mblk_t * ipif_arp_down_mp; /* Allocated at time arp comes up to
886 * prevent awkward out of mem condition
889 mblk_t * ipif_saved_ire_mp; /* Allocated for each extra IRE_SUBNET/
890 * RESOLVER on this interface so that
891 * they can survive ifconfig down.
894 * The packet counts in the ipif contain the sum of the
895 * packet counts in dead IREs that were affiliated with
898 u_long ipif_fo_pkt_count; /* Forwarded thru our dead IREs */
899 u_long ipif_ib_pkt_count; /* Inbound packets for our dead IREs */
900 u_long ipif_ob_pkt_count; /* Outbound packets to our dead IREs */
902 ipif_multicast_up : 1, /* We have joined the allhosts group */
906 typedef struct ipfb_s { /**/
907 struct ipf_s * ipfb_ipf; /* List of ... */
908 kmutex_t ipfb_lock; /* Protect all ipf in list */
911 typedef struct ilm_s { /**/
914 u_int ilm_timer; /* IGMP */
915 struct ipif_s * ilm_ipif; /* Back pointer to ipif */
916 struct ilm_s * ilm_next; /* Linked list for each ill */
919 typedef struct ill_s { /**/
920 struct ill_s * ill_next; /* Chained in at ill_g_head. */
921 struct ill_s ** ill_ptpn; /* Pointer to previous next. */
922 queue_t * ill_rq; /* Read queue. */
923 queue_t * ill_wq; /* Write queue. */
925 int ill_error; /* Error value sent up by device. */
927 ipif_t * ill_ipif; /* Interface chain for this ILL. */
928 u_int ill_ipif_up_count; /* Number of IPIFs currently up. */
929 u_int ill_max_frag; /* Max IDU. */
930 char * ill_name; /* Our name. */
931 u_int ill_name_length; /* Name length, incl. terminator. */
932 u_int ill_subnet_type; /* IRE_RESOLVER or IRE_SUBNET. */
933 u_int ill_ppa; /* Physical Point of Attachment num. */
935 int ill_sap_length; /* Including sign (for position) */
936 u_int ill_phys_addr_length; /* Excluding the sap. */
937 mblk_t * ill_frag_timer_mp; /* Reassembly timer state. */
938 ipfb_t * ill_frag_hash_tbl; /* Fragment hash list head. */
940 queue_t * ill_bind_pending_q; /* Queue waiting for DL_BIND_ACK. */
941 ipif_t * ill_ipif_pending; /* IPIF waiting for DL_BIND_ACK. */
943 /* ill_hdr_length and ill_hdr_mp will be non zero if
944 * the underlying device supports the M_DATA fastpath
948 ilm_t * ill_ilm; /* Multicast mebership for lower ill */
950 /* All non-nil cells between 'ill_first_mp_to_free' and
951 * 'ill_last_mp_to_free' are freed in ill_delete.
953 #define ill_first_mp_to_free ill_hdr_mp
954 mblk_t * ill_hdr_mp; /* Contains fastpath template */
955 mblk_t * ill_bcast_mp; /* DLPI header for broadcasts. */
956 mblk_t * ill_bind_pending; /* T_BIND_REQ awaiting completion. */
957 mblk_t * ill_resolver_mp; /* Resolver template. */
958 mblk_t * ill_attach_mp;
959 mblk_t * ill_bind_mp;
960 mblk_t * ill_unbind_mp;
961 mblk_t * ill_detach_mp;
962 #define ill_last_mp_to_free ill_detach_mp
965 ill_frag_timer_running : 1,
966 ill_needs_attach : 1,
969 ill_unbind_pending : 1,
971 ill_pad_to_bit_31 : 27;
972 MI_HRT_DCL(ill_rtime)
977 #ifdef AFS_USERSPACE_IP_ADDR
979 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
982 * The IP addresses and ranks are determined by afsd (in user space) and
983 * passed into the kernel at startup time through the AFSOP_ADVISEADDR
984 * system call. These are stored in the data structure
985 * called 'afs_cb_interface'.
987 * struct srvAddr *sa; remote server
988 * afs_int32 addr; one of my local addr in net order
989 * afs_uint32 subnetmask; subnet mask of local addr in net order
992 int afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr, afs_uint32 subnetmask)
994 afs_uint32 myAddr, myNet, mySubnet, netMask;
995 afs_uint32 serverAddr ;
997 myAddr = ntohl(addr); /* one of my IP addr in host order */
998 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
999 subnetmask = ntohl(subnetmask);/* subnet mask in host order */
1001 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1002 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1003 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1006 myNet = myAddr & netMask;
1007 mySubnet = myAddr & subnetmask;
1009 if ( (serverAddr & netMask ) == myNet ) {
1010 if ( (serverAddr & subnetmask ) == mySubnet) {
1011 if ( serverAddr == myAddr ) { /* same machine */
1012 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1013 } else { /* same subnet */
1014 sa->sa_iprank = afs_min(sa->sa_iprank, HI);
1016 } else { /* same net */
1017 sa->sa_iprank = afs_min(sa->sa_iprank, MED);
1021 #else /* AFS_USERSPACE_IP_ADDR */
1022 #if (! defined(AFS_SUN5_ENV)) && !defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1023 void afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
1025 struct sockaddr_in *sin;
1028 if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1029 if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1031 if ( SA2ULONG(sin) == ntohl(sa->sa_ip)) { /* ie, ME!!! */
1032 sa->sa_iprank = TOPR;
1034 t = HI + ifa->ia_ifp->if_metric; /* case #2 */
1035 if (sa->sa_iprank > t)
1039 t = MED + ifa->ia_ifp->if_metric;/* case #3 */
1040 if (sa->sa_iprank > t)
1044 #ifdef IFF_POINTTOPOINT
1045 /* check for case #4 -- point-to-point link */
1046 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1047 (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1048 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1051 t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1052 if (sa->sa_iprank > t)
1055 #endif /* IFF_POINTTOPOINT */
1057 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1058 #if defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1060 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
1063 afsi_SetServerIPRank(sa, ifa)
1067 struct sockaddr_in *sin;
1070 afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
1071 afs_uint32 serverAddr ;
1073 if (ifa->ifa_addr->sa_family != AF_INET)
1075 sin=(struct sockaddr_in *)ifa->ifa_addr;
1076 myAddr = ntohl(sin->sin_addr.s_addr); /* one of my IP addr in host order */
1077 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
1078 sin=(struct sockaddr_in *)ifa->ifa_netmask;
1079 subnetmask = ntohl(sin->sin_addr.s_addr);/* subnet mask in host order */
1080 sin=(struct sockaddr_in *)ifa->ifa_dstaddr;
1082 myDstaddr=sin->sin_addr.s_addr;
1084 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1085 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1086 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1089 myNet = myAddr & netMask;
1090 mySubnet = myAddr & subnetmask;
1092 if ( (serverAddr & netMask ) == myNet ) {
1093 if ( (serverAddr & subnetmask ) == mySubnet) {
1094 if ( serverAddr == myAddr ) { /* same machine */
1095 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1096 } else { /* same subnet */
1097 sa->sa_iprank = afs_min(sa->sa_iprank, HI + ifa->ifa_metric);
1099 } else { /* same net */
1100 sa->sa_iprank = afs_min(sa->sa_iprank, MED + ifa->ifa_metric);
1103 #ifdef IFF_POINTTOPOINT
1104 /* check for case #4 -- point-to-point link */
1105 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1106 (myDstaddr == serverAddr))) {
1107 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1110 t = MED + (PPWEIGHT << ifa->->ifa_metric);
1111 if (sa->sa_iprank > t)
1114 #endif /* IFF_POINTTOPOINT */
1116 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1117 #endif /* else AFS_USERSPACE_IP_ADDR */
1119 #ifdef AFS_SGI62_ENV
1121 afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1124 afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr*)h);
1125 return 0; /* Never match, so we enumerate everyone */
1127 #endif /* AFS_SGI62_ENV */
1129 static int afs_SetServerPrefs(struct srvAddr *sa)
1131 #if defined(AFS_USERSPACE_IP_ADDR)
1135 for (i=0; i<afs_cb_interface.numberOfInterfaces; i++) {
1136 afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1137 afs_cb_interface.subnetmask[i]);
1139 #else /* AFS_USERSPACE_IP_ADDR */
1140 #if defined(AFS_SUN5_ENV)
1141 extern struct ill_s *ill_g_headp;
1144 int subnet, subnetmask, net, netmask;
1145 long *addr = (long *) ill_g_headp;
1147 if (sa) sa->sa_iprank= 0;
1148 for (ill = (struct ill_s *)*addr /*ill_g_headp*/; ill; ill = ill->ill_next ) {
1149 #ifdef AFS_SUN58_ENV
1150 /* Make sure this is an IPv4 ILL */
1151 if (ill->ill_isv6) continue;
1153 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next ) {
1154 subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1155 subnetmask = ipif->ipif_net_mask;
1157 * Generate the local net using the local address and
1158 * whate we know about Class A, B and C networks.
1160 if (IN_CLASSA(ipif->ipif_local_addr)) {
1161 netmask = IN_CLASSA_NET;
1162 } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1163 netmask = IN_CLASSB_NET;
1164 } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1165 netmask = IN_CLASSC_NET;
1169 net = ipif->ipif_local_addr & netmask;
1172 if (ipif->ipif_local_addr != 0x7f000001) { /* ignore loopback */
1174 if (*cnt > 16) return;
1175 *addrp++ = ipif->ipif_local_addr;
1180 /* XXXXXX Do the individual ip ranking below XXXXX */
1181 if ((sa->sa_ip & netmask) == net) {
1182 if ((sa->sa_ip & subnetmask) == subnet) {
1183 if (ipif->ipif_local_addr == sa->sa_ip) { /* ie, ME! */
1184 sa->sa_iprank = TOPR;
1186 sa->sa_iprank = HI + ipif->ipif_metric; /* case #2 */
1189 sa->sa_iprank = MED + ipif->ipif_metric; /* case #3 */
1192 sa->sa_iprank = LO + ipif->ipif_metric; /* case #4 */
1194 /* check for case #5 -- point-to-point link */
1195 if ((ipif->ipif_flags & IFF_POINTOPOINT) &&
1196 (ipif->ipif_pp_dst_addr == sa->sa_ip )) {
1198 if (ipif->ipif_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1199 sa->sa_iprank = MAXDEFRANK;
1201 sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1208 struct ifnet *ifn = NULL;
1209 struct in_ifaddr *ifad = (struct in_ifaddr *) 0;
1210 struct sockaddr_in *sin;
1213 #ifdef notdef /* clean up, remove this */
1214 for (ifn = ifnet; ifn != NULL; ifn = ifn->if_next) {
1215 for (ifad = ifn->if_addrlist; ifad != NULL; ifad = ifad->ifa_next){
1216 if ((IFADDR2SA(ifad)->sa_family == AF_INET)
1217 && !(ifn->if_flags & IFF_LOOPBACK)) {
1219 if (*cnt > 16) return;
1220 *addrp++ = ((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr;
1229 ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1231 if (ifn) { /* local, more or less */
1233 if (ifn->if_flags & IFF_LOOPBACK) {
1234 sa->sa_iprank = TOPR;
1237 #endif /* IFF_LOOPBACK */
1238 sin = (struct sockaddr_in *) IA_SIN(ifad);
1239 if (SA2ULONG(sin) == sa->sa_ip) {
1240 sa->sa_iprank = TOPR;
1243 #ifdef IFF_BROADCAST
1244 if (ifn->if_flags & IFF_BROADCAST) {
1245 if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1250 #endif /* IFF_BROADCAST */
1251 #ifdef IFF_POINTOPOINT
1252 if (ifn->if_flags & IFF_POINTOPOINT) {
1253 if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1254 if (ifn->if_metric > 4) {
1258 else sa->sa_iprank = ifn->if_metric;
1261 #endif /* IFF_POINTOPOINT */
1262 sa->sa_iprank += MED + ifn->if_metric; /* couldn't find anything better */
1265 #else /* USEIFADDR */
1267 if (sa) sa->sa_iprank= LO;
1268 #ifdef AFS_SGI62_ENV
1269 (void) hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1271 #elif defined(AFS_DARWIN60_ENV)
1275 TAILQ_FOREACH(ifn , &ifnet, if_link) {
1276 TAILQ_FOREACH(ifa , &ifn->if_addrhead, ifa_link) {
1277 afsi_SetServerIPRank(sa, ifa);
1281 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1283 struct in_ifaddr *ifa;
1284 TAILQ_FOREACH(ifa , &in_ifaddrhead, ia_link) {
1285 afsi_SetServerIPRank(sa, ifa);
1290 struct in_ifaddr *ifa;
1291 for ( ifa = in_ifaddr; ifa; ifa = ifa->ia_next ) {
1292 afsi_SetServerIPRank(sa, ifa);
1297 #endif /* USEIFADDR */
1298 #endif /* AFS_SUN5_ENV */
1299 #endif /* else AFS_USERSPACE_IP_ADDR */
1302 if (sa) sa->sa_iprank += afs_randomMod15();
1305 } /* afs_SetServerPrefs */
1312 /* afs_FlushServer()
1313 * The addresses on this server struct has changed in some way and will
1314 * clean up all other structures that may reference it.
1315 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1317 void afs_FlushServer(struct server *srvp)
1320 struct server *ts, **pts;
1322 /* Find any volumes residing on this server and flush their state */
1323 afs_ResetVolumes(srvp);
1325 /* Flush all callbacks in the all vcaches for this specific server */
1326 afs_FlushServerCBs(srvp);
1328 /* Remove all the callbacks structs */
1330 struct afs_cbr *cb, *cbnext;
1332 MObtainWriteLock(&afs_xvcb, 300);
1333 for (cb=srvp->cbrs; cb; cb=cbnext) {
1337 srvp->cbrs = (struct afs_cbr *)0;
1338 ReleaseWriteLock(&afs_xvcb);
1341 /* If no more srvAddr structs hanging off of this server struct,
1345 /* Remove the server structure from the cell list - if there */
1346 afs_RemoveCellEntry(srvp);
1348 /* Remove from the afs_servers hash chain */
1349 for (i=0; i<NSERVERS; i++) {
1350 for (pts=&(afs_servers[i]), ts=*pts; ts; pts=&(ts->next), ts=*pts) {
1351 if (ts == srvp) break;
1356 *pts = ts->next; /* Found it. Remove it */
1357 afs_osi_Free(ts, sizeof(struct server)); /* Free it */
1363 /* afs_RemoveSrvAddr()
1364 * This removes a SrvAddr structure from its server structure.
1365 * The srvAddr struct is not free'd because it connections may still
1366 * be open to it. It is up to the calling process to make sure it
1367 * remains connected to a server struct.
1368 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1369 * It is not removed from the afs_srvAddrs hash chain.
1371 void afs_RemoveSrvAddr(struct srvAddr *sap)
1373 struct srvAddr **psa, *sa;
1379 /* Find the srvAddr in the server's list and remove it */
1380 for (psa=&(srv->addr), sa=*psa; sa; psa=&(sa->next_sa), sa=*psa) {
1381 if (sa == sap) break;
1388 /* Flush the server struct since it's IP address has changed */
1389 afs_FlushServer(srv);
1394 * Return an updated and properly initialized server structure
1395 * corresponding to the server ID, cell, and port specified.
1396 * If one does not exist, then one will be created.
1397 * aserver and aport must be in NET byte order.
1399 struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
1400 afs_int32 acell, u_short aport,
1401 afs_int32 locktype, afsUUID *uuidp,
1402 afs_int32 addr_uniquifier)
1404 struct server *oldts=0, *ts, *newts, *orphts=0;
1405 struct srvAddr *oldsa, *sa, *newsa, *nextsa, *orphsa;
1407 afs_int32 iphash, k, srvcount=0;
1408 unsigned int srvhash;
1410 AFS_STATCNT(afs_GetServer);
1412 ObtainSharedLock(&afs_xserver,13);
1414 /* Check if the server struct exists and is up to date */
1416 if (nservers != 1) panic("afs_GetServer: incorect count of servers");
1417 ObtainReadLock(&afs_xsrvAddr);
1418 ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1419 ReleaseReadLock(&afs_xsrvAddr);
1420 if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1421 /* Found a server struct that is not multihomed and has the
1422 * IP address associated with it. A correct match.
1424 ReleaseSharedLock(&afs_xserver);
1428 if (nservers <= 0) panic("afs_GetServer: incorrect count of servers");
1429 ts = afs_FindServer(0, aport, uuidp, locktype);
1430 if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1431 /* Found a server struct that is multihomed and same
1432 * uniqufier (same IP addrs). The above if statement is the
1433 * same as in InstallUVolumeEntry().
1435 ReleaseSharedLock(&afs_xserver);
1438 if (ts) oldts = ts; /* Will reuse if same uuid */
1441 UpgradeSToWLock(&afs_xserver,36);
1442 ObtainWriteLock(&afs_xsrvAddr,116);
1444 srvcount = afs_totalServers;
1446 /* Reuse/allocate a new server structure */
1450 newts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1451 if (!newts) panic("malloc of server struct");
1453 memset((char *)newts, 0, sizeof(struct server));
1455 /* Add the server struct to the afs_servers[] hash chain */
1456 srvhash = (uuidp ? (afs_uuid_hash(uuidp)%NSERVERS) : SHash(aserverp[0]));
1457 newts->next = afs_servers[srvhash];
1458 afs_servers[srvhash] = newts;
1461 /* Initialize the server structure */
1462 if (uuidp) { /* Multihomed */
1463 newts->sr_uuid = *uuidp;
1464 newts->sr_addr_uniquifier = addr_uniquifier;
1465 newts->flags |= SRVR_MULTIHOMED;
1467 if (acell) newts->cell = afs_GetCell(acell, 0);
1469 fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
1471 /* For each IP address we are registering */
1472 for (k=0; k<nservers; k++) {
1473 iphash = SHash(aserverp[k]);
1475 /* Check if the srvAddr structure already exists. If so, remove
1476 * it from its server structure and add it to the new one.
1478 for (oldsa=afs_srvAddrs[iphash]; oldsa; oldsa=oldsa->next_bkt) {
1479 if ( (oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport) ) break;
1481 if (oldsa && (oldsa->server != newts)) {
1482 afs_RemoveSrvAddr(oldsa); /* Remove from its server struct */
1483 oldsa->next_sa = newts->addr; /* Add to the new server struct */
1484 newts->addr = oldsa;
1487 /* Reuse/allocate a new srvAddr structure */
1491 newsa = (struct srvAddr *) afs_osi_Alloc(sizeof(struct srvAddr));
1492 if (!newsa) panic("malloc of srvAddr struct");
1493 afs_totalSrvAddrs++;
1494 memset((char *)newsa, 0, sizeof(struct srvAddr));
1496 /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1497 newsa->next_bkt = afs_srvAddrs[iphash];
1498 afs_srvAddrs[iphash] = newsa;
1500 /* Hang off of the server structure */
1501 newsa->next_sa = newts->addr;
1502 newts->addr = newsa;
1504 /* Initialize the srvAddr Structure */
1505 newsa->sa_ip = aserverp[k];
1506 newsa->sa_portal = aport;
1509 /* Update the srvAddr Structure */
1510 newsa->server = newts;
1511 if (newts->flags & SRVR_ISDOWN)
1512 newsa->sa_flags |= SRVADDR_ISDOWN;
1513 if (uuidp) newsa->sa_flags |= SRVADDR_MH;
1514 else newsa->sa_flags &= ~SRVADDR_MH;
1516 /* Compute preference values and resort */
1517 if (!newsa->sa_iprank) {
1518 if (aport == fsport) {
1519 afs_SetServerPrefs(newsa); /* new fileserver rank */
1521 newsa->sa_iprank = 10000 + afs_randomMod127(); /* new vlserver rank */
1525 afs_SortOneServer(newts); /* Sort by rank */
1527 /* If we reused the server struct, remove any of its srvAddr
1528 * structs that will no longer be associated with this server.
1530 if (oldts) { /* reused the server struct */
1531 for (orphsa=newts->addr; orphsa; orphsa=nextsa) {
1532 nextsa = orphsa->next_sa;
1533 for (k=0; k<nservers; k++) {
1534 if (orphsa->sa_ip == aserverp[k]) break; /* belongs */
1536 if (k < nservers) continue; /* belongs */
1538 /* Have a srvAddr struct. Now get a server struct (if not already) */
1540 orphts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1541 if (!orphts) panic("malloc of lo server struct");
1542 memset((char *)orphts, 0, sizeof(struct server));
1545 /* Add the orphaned server to the afs_servers[] hash chain.
1546 * Its iphash does not matter since we never look up the server
1547 * in the afs_servers table by its ip address (only by uuid -
1548 * which this has none).
1550 iphash = SHash(aserverp[k]);
1551 orphts->next = afs_servers[iphash];
1552 afs_servers[iphash] = orphts;
1554 if (acell) orphts->cell = afs_GetCell(acell, 0);
1557 /* Hang the srvAddr struct off of the server structure. The server
1558 * may have multiple srvAddrs, but it won't be marked multihomed.
1560 afs_RemoveSrvAddr(orphsa); /* remove */
1561 orphsa->next_sa = orphts->addr; /* hang off server struct */
1562 orphts->addr = orphsa;
1563 orphsa->server = orphts;
1564 orphsa->sa_flags |= SRVADDR_NOUSE; /* flag indicating not in use */
1565 orphsa->sa_flags &= ~SRVADDR_MH; /* Not multihomed */
1569 srvcount = afs_totalServers - srvcount; /* # servers added and removed */
1571 struct afs_stats_SrvUpDownInfo *upDownP;
1572 /* With the introduction of this new record, we need to adjust the
1573 * proper individual & global server up/down info.
1575 if (aport == fsport) { /* File Server record */
1576 upDownP = (acell == 1) ?
1577 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1578 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1579 } else { /* VL Server record */
1580 upDownP = (acell == 1) ?
1581 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1582 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1584 (upDownP->numTtlRecords) += srvcount;
1585 afs_stats_cmperf.srvRecords += srvcount;
1586 if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1587 afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1590 ReleaseWriteLock(&afs_xsrvAddr);
1591 ReleaseWriteLock(&afs_xserver);
1593 } /* afs_GetServer */
1595 void afs_ActivateServer(struct srvAddr *sap)
1597 osi_timeval_t currTime; /*Filled with current time*/
1598 osi_timeval_t *currTimeP; /*Ptr to above*/
1599 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
1600 struct server *aserver = sap->server;
1602 if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1604 * This server record has not yet been activated. Go for it,
1605 * recording its ``birth''.
1607 aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1608 currTimeP = &currTime;
1609 osi_GetuTime(currTimeP);
1610 aserver->activationTime = currTime.tv_sec;
1611 if (sap->sa_portal == AFS_FSPORT) {
1612 upDownP = (aserver->cell->cell == 1) ?
1613 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1614 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1615 } /*File Server record*/
1617 upDownP = (aserver->cell->cell == 1) ?
1618 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1619 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1620 } /*VL Server record*/
1621 if (aserver->flags & SRVR_ISDOWN)
1622 (upDownP->numDownRecords)++;
1624 (upDownP->numUpRecords)++;
1625 (upDownP->numRecordsNeverDown)++;