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 "../afs/param.h" /* Should be always first */
33 #include "../afs/stds.h"
34 #include "../afs/sysincludes.h" /* Standard vendor system headers */
38 #include <netinet/in.h>
41 #include "../h/hashing.h"
43 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV)
44 #include <netinet/in_var.h>
45 #endif /* AFS_HPUX110_ENV */
46 #endif /* !defined(UKERNEL) */
48 #include "../afs/afsincludes.h" /* Afs-based standard headers */
49 #include "../afs/afs_stats.h" /* afs statistics */
51 #if defined(AFS_SUN56_ENV)
53 #include <inet/common.h>
57 /* Imported variables */
58 extern afs_int32 afs_setTime;
59 extern afs_int32 afs_waitForever;
60 extern short afs_waitForeverCount;
63 /* Exported variables */
64 afs_rwlock_t afs_xserver; /* allocation lock for servers */
65 struct server *afs_setTimeHost=0; /* last host we used for time */
66 struct server *afs_servers[NSERVERS]; /* Hashed by server`s uuid & 1st ip */
67 afs_rwlock_t afs_xsrvAddr; /* allocation lock for srvAddrs */
68 struct srvAddr *afs_srvAddrs[NSERVERS]; /* Hashed by server's ip */
71 /* debugging aids - number of alloc'd server and srvAddr structs. */
72 int afs_reuseServers = 0;
73 int afs_reuseSrvAddrs = 0;
74 int afs_totalServers = 0;
75 int afs_totalSrvAddrs = 0;
80 /*------------------------------------------------------------------------
81 * afs_MarkServerUpOrDown
84 * Mark the given server up or down, and track its uptime stats.
87 * a_serverP : Ptr to server record to fiddle with.
88 * a_isDown : Is the server is to be marked down?
94 * The CM server structures must be write-locked.
98 *------------------------------------------------------------------------*/
100 void afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
102 register struct server *a_serverP = sa->server;
103 register struct srvAddr *sap;
104 osi_timeval_t currTime, *currTimeP; /*Current time*/
105 afs_int32 downTime; /*Computed downtime, in seconds*/
106 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
109 * If the server record is marked the same as the new status we've
110 * been fed, then there isn't much to be done.
112 if (( a_isDown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
113 (!a_isDown && !(sa->sa_flags & SRVADDR_ISDOWN)))
117 sa->sa_flags |= SRVADDR_ISDOWN;
118 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
119 if (!(sap->sa_flags & SRVADDR_ISDOWN)) {
120 /* Not all ips are up so don't bother with the
121 * server's up/down stats */
126 * All ips are down we treat the whole server down
128 a_serverP->flags |= SRVR_ISDOWN;
130 * If this was our time server, search for another time server
132 if (a_serverP == afs_setTimeHost)
135 sa->sa_flags &= ~SRVADDR_ISDOWN;
136 /* If any ips are up, the server is also marked up */
137 a_serverP->flags &= ~SRVR_ISDOWN;
138 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
139 if (sap->sa_flags & SRVADDR_ISDOWN) {
140 /* Not all ips are up so don't bother with the
141 * server's up/down stats */
148 * Compute the current time and which overall stats record is to be
149 * updated; we'll need them one way or another.
151 currTimeP = &currTime;
152 osi_GetuTime(currTimeP);
154 if (sa->sa_portal == AFS_FSPORT) {
155 upDownP = (a_serverP->cell->cell == 1) ?
156 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
157 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
158 } /*File Server record*/
160 upDownP = (a_serverP->cell->cell == 1) ?
161 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
162 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
163 } /*VL Server record*/
167 * Server going up -> down; remember the beginning of this
170 a_serverP->lastDowntimeStart = currTime.tv_sec;
172 (upDownP->numDownRecords)++;
173 (upDownP->numUpRecords)--;
174 } /*Server being marked down*/
177 * Server going down -> up; remember everything about this
178 * newly-completed downtime incident.
180 downTime = currTime.tv_sec - a_serverP->lastDowntimeStart;
181 (a_serverP->numDowntimeIncidents)++;
182 a_serverP->sumOfDowntimes += downTime;
184 (upDownP->numUpRecords)++;
185 (upDownP->numDownRecords)--;
186 (upDownP->numDowntimeIncidents)++;
187 if (a_serverP->numDowntimeIncidents == 1)
188 (upDownP->numRecordsNeverDown)--;
189 upDownP->sumOfDowntimes += downTime;
190 if ((upDownP->shortestDowntime == 0) ||
191 (downTime < upDownP->shortestDowntime))
192 upDownP->shortestDowntime = downTime;
193 if ((upDownP->longestDowntime == 0) ||
194 (downTime > upDownP->longestDowntime))
195 upDownP->longestDowntime = downTime;
198 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET0)
199 (upDownP->downDurations[0])++;
201 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET1)
202 (upDownP->downDurations[1])++;
204 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET2)
205 (upDownP->downDurations[2])++;
207 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET3)
208 (upDownP->downDurations[3])++;
210 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET4)
211 (upDownP->downDurations[4])++;
213 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET5)
214 (upDownP->downDurations[5])++;
216 (upDownP->downDurations[6])++;
218 } /*Server being marked up*/
220 } /*MarkServerUpOrDown*/
223 void afs_ServerDown(struct srvAddr *sa)
225 register struct server *aserver = sa->server;
226 register struct srvAddr *sap;
228 AFS_STATCNT(ServerDown);
229 if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
231 afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
232 if (sa->sa_portal == aserver->cell->vlport)
233 print_internet_address("afs: Lost contact with volume location server ",
236 print_internet_address("afs: Lost contact with file server ", sa, "", 1);
241 /* return true if we have any callback promises from this server */
242 static HaveCallBacksFrom(aserver)
243 struct server *aserver;
246 register afs_int32 now;
248 register struct vcache *tvc;
250 AFS_STATCNT(HaveCallBacksFrom);
251 now = osi_Time(); /* for checking for expired callbacks */
252 for(i=0;i<VCSIZE;i++) { /* for all guys in the hash table */
253 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
255 * Check to see if this entry has an unexpired callback promise
256 * from the required host
258 if (aserver == tvc->callback && tvc->cbExpires >= now
259 && ((tvc->states & CRO) == 0))
265 } /*HaveCallBacksFrom*/
268 static void CheckVLServer(sa, areq)
269 struct vrequest *areq;
270 register struct srvAddr *sa;
272 register struct server *aserver = sa->server;
273 register struct conn *tc;
274 register afs_int32 code;
276 AFS_STATCNT(CheckVLServer);
277 /* Ping dead servers to see if they're back */
278 if (!(aserver->flags & SRVR_ISDOWN) || (aserver->flags & SRVR_ISGONE))
281 return; /* can't do much */
283 tc = afs_ConnByHost(aserver, aserver->cell->vlport,
284 aserver->cell->cell, areq, 1, SHARED_LOCK);
287 rx_SetConnDeadTime(tc->id, 3);
289 #ifdef RX_ENABLE_LOCKS
291 #endif /* RX_ENABLE_LOCKS */
292 code = VL_ProbeServer(tc->id);
293 #ifdef RX_ENABLE_LOCKS
295 #endif /* RX_ENABLE_LOCKS */
296 rx_SetConnDeadTime(tc->id, 50);
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()
346 { /*afs_CountServers*/
348 int currIdx; /*Curr idx into srv table*/
349 struct server *currSrvP; /*Ptr to curr server record*/
350 afs_int32 currChainLen; /*Length of curr hash chain*/
351 osi_timeval_t currTime; /*Current time*/
352 osi_timeval_t *currTimeP; /*Ptr to above*/
353 afs_int32 srvRecordAge; /*Age of server record, in secs*/
354 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to current up/down
355 info being manipulated*/
358 * Write-lock the server table so we don't get any interference.
360 ObtainReadLock(&afs_xserver);
363 * Iterate over each hash index in the server table, walking down each
364 * chain and tallying what we haven't computed from the records there on
365 * the fly. First, though, initialize the tallies that will change.
367 afs_stats_cmperf.srvMaxChainLength = 0;
369 afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
370 afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
371 afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
372 bzero((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents,
373 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
375 afs_stats_cmperf.fs_UpDown[1].sumOfRecordAges = 0;
376 afs_stats_cmperf.fs_UpDown[1].ageOfYoungestRecord = 0;
377 afs_stats_cmperf.fs_UpDown[1].ageOfOldestRecord = 0;
378 bzero((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents,
379 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
381 afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges = 0;
382 afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
383 afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord = 0;
384 bzero((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents,
385 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
387 afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges = 0;
388 afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
389 afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord = 0;
390 bzero((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents,
391 AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
394 * Compute the current time, used to figure out server record ages.
396 currTimeP = &currTime;
397 osi_GetuTime(currTimeP);
400 * Sweep the server hash table, tallying all we need to know.
402 for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
404 for (currSrvP = afs_servers[currIdx]; currSrvP; currSrvP = currSrvP->next) {
406 * Bump the current chain length.
411 * Any further tallying for this record will only be done if it has
414 if ( (currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED) &&
415 currSrvP->addr && currSrvP->cell ) {
418 * Compute the current server record's age, then remember it
419 * in the appropriate places.
421 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
422 if (currSrvP->addr->sa_portal == AFS_FSPORT) {
423 upDownP = (currSrvP->cell->cell == 1) ?
424 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]):
425 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
426 } /*File Server record*/
428 upDownP = (currSrvP->cell->cell == 1) ?
429 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]):
430 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
431 } /*VL Server record*/
433 upDownP->sumOfRecordAges += srvRecordAge;
434 if ((upDownP->ageOfYoungestRecord == 0) ||
435 (srvRecordAge < upDownP->ageOfYoungestRecord))
436 upDownP->ageOfYoungestRecord = srvRecordAge;
437 if ((upDownP->ageOfOldestRecord == 0) ||
438 (srvRecordAge > upDownP->ageOfOldestRecord))
439 upDownP->ageOfOldestRecord = srvRecordAge;
441 if (currSrvP->numDowntimeIncidents <=
442 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
443 (upDownP->downIncidents[0])++;
445 if (currSrvP->numDowntimeIncidents <=
446 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
447 (upDownP->downIncidents[1])++;
449 if (currSrvP->numDowntimeIncidents <=
450 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
451 (upDownP->downIncidents[2])++;
453 if (currSrvP->numDowntimeIncidents <=
454 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
455 (upDownP->downIncidents[3])++;
457 if (currSrvP->numDowntimeIncidents <=
458 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
459 (upDownP->downIncidents[4])++;
461 (upDownP->downIncidents[5])++;
464 } /*Current server has been active*/
465 } /*Walk this chain*/
468 * Before advancing to the next chain, remember facts about this one.
470 if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
472 * We beat out the former champion (which was initially set to 0
473 * here). Mark down the new winner, and also remember if it's an
476 afs_stats_cmperf.srvMaxChainLength = currChainLen;
477 if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
478 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
479 } /*Update chain length maximum*/
480 } /*For each hash chain*/
483 * We're done. Unlock the server table before returning to our caller.
485 ReleaseReadLock(&afs_xserver);
487 } /*afs_CountServers*/
490 /* check down servers (if adown), or running servers (if !adown) */
491 void afs_CheckServers(adown, acellp)
496 struct vrequest treq;
502 afs_int32 start, end, delta;
509 AFS_STATCNT(afs_CheckServers);
510 if (code = afs_InitReq(&treq, &afs_osi_cred)) return;
511 ObtainReadLock(&afs_xserver); /* Necessary? */
512 ObtainReadLock(&afs_xsrvAddr);
514 for (i=0;i<NSERVERS;i++) {
515 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
519 /* See if a cell to check was specified. If it is spec'd and not
520 * this server's cell, just skip the server.
522 if (acellp && acellp != ts->cell)
525 if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN))
526 || (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
528 /* check vlserver with special code */
529 if (sa->sa_portal == AFS_VLPORT) {
530 CheckVLServer(sa, &treq);
534 if (!ts->cell) /* not really an active server, anyway, it must */
535 continue; /* have just been added by setsprefs */
537 /* get a connection, even if host is down; bumps conn ref count */
538 tu = afs_GetUser(treq.uid, ts->cell, SHARED_LOCK);
539 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cell, tu,
540 1/*force*/, 1/*create*/, SHARED_LOCK);
541 afs_PutUser(tu, SHARED_LOCK);
545 if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
546 (tc->srvr->server == afs_setTimeHost)) {
547 if (sa->sa_flags & SRVADDR_ISDOWN) {
548 rx_SetConnDeadTime(tc->id, 3);
552 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
553 start = osi_Time(); /* time the gettimeofday call */
554 #ifdef RX_ENABLE_LOCKS
556 #endif /* RX_ENABLE_LOCKS */
557 code = RXAFS_GetTime(tc->id, &tv.tv_sec, &tv.tv_usec);
558 #ifdef RX_ENABLE_LOCKS
560 #endif /* RX_ENABLE_LOCKS */
564 * If we're supposed to set the time, and the call worked
565 * quickly (same second response) and this is the host we
566 * use for the time and the time is really different, then
567 * really set the time
569 if (code == 0 && start == end && afs_setTime != 0 &&
570 (tc->srvr->server == afs_setTimeHost ||
572 * Sync only to a server in the local cell: cell(id)==1
575 (afs_setTimeHost == (struct server *)0 &&
576 (ts->cell->cell == 1 || (ts->cell->states&CPrimary))))) {
577 char msgbuf[90]; /* strlen("afs: setting clock...") + slop */
579 delta = end - tv.tv_sec; /* how many secs fast we are */
580 /* see if clock has changed enough to make it worthwhile */
581 if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
582 if (delta > AFS_MAXCHANGEBACK) {
583 /* setting clock too far back, just do it a little */
584 tv.tv_sec = end - AFS_MAXCHANGEBACK;
586 afs_osi_SetTime(&tv);
588 strcpy(msgbuf, "afs: setting clock back ");
589 if (delta > AFS_MAXCHANGEBACK) {
590 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
591 afs_strcat(msgbuf, " seconds (of ");
592 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
593 afs_strcat(msgbuf, ", via ");
594 print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
596 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
597 afs_strcat(msgbuf, " seconds (via ");
598 print_internet_address(msgbuf, sa, ").", 0);
602 strcpy(msgbuf, "afs: setting clock ahead ");
603 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
604 afs_strcat(msgbuf, " seconds (via ");
605 print_internet_address(msgbuf, sa, ").", 0);
608 afs_setTimeHost = tc->srvr->server;
611 rx_SetConnDeadTime(tc->id, 50);
612 if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
614 print_internet_address("afs: file server ", sa, " is back up", 2);
616 * XXX We should hold a server write lock here XXX
618 afs_MarkServerUpOrDown(sa, 0);
619 if (afs_waitForeverCount) {
620 afs_osi_Wakeup(&afs_waitForever);
627 ForceNewConnections(sa); /* multi homed clients */
631 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
632 } /* for each server loop */
633 } /* for each server hash bucket loop */
634 ReleaseReadLock(&afs_xsrvAddr);
635 ReleaseReadLock(&afs_xserver);
637 } /*afs_CheckServers*/
640 /* find a server structure given the host address */
641 struct server *afs_FindServer (afs_int32 aserver, ushort aport,
642 afsUUID *uuidp, afs_int32 locktype)
648 AFS_STATCNT(afs_FindServer);
650 i = afs_uuid_hash(uuidp) % NSERVERS;
651 for (ts = afs_servers[i]; ts; ts = ts->next) {
652 if ( (ts->flags & SRVR_MULTIHOMED) &&
653 (bcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
654 (!ts->addr || (ts->addr->sa_portal == aport)) )
659 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
660 if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
665 return (struct server *)0;
670 /* some code for creating new server structs and setting preferences follows
671 * in the next few lines...
674 #define MAXDEFRANK 60000
675 #define DEFRANK 40000
677 /* Random number generator and constants from KnuthV2 2d ed, p170 */
683 a is 0.73m should be 0.01m .. 0.99m
684 c is more or less immaterial. 1 or a is suggested.
686 NB: LOW ORDER BITS are not very random. To get small random numbers,
687 treat result as <1, with implied binary point, and multiply by
689 NB: Has to be unsigned, since shifts on signed quantities may preserve
692 /* added rxi_getaddr() to try to get as much initial randomness as
693 possible, since at least one customer reboots ALL their clients
694 simultaneously -- so osi_Time is bound to be the same on some of the
695 clients. This is probably OK, but I don't want to see too much of it.
698 #define ranstage(x) (x)= (afs_uint32) (3141592621*((afs_uint32)x)+1)
699 extern afs_int32 rxi_getaddr();
701 unsigned int afs_random()
704 static afs_int32 state = 0;
707 AFS_STATCNT(afs_random);
712 * 0xfffffff0 was changed to (~0 << 4) since it works no matter how many
713 * bits are in a tv_usec
715 state = (t.tv_usec & (~0 << 4) ) + (rxi_getaddr() & 0xff);
716 state += (t.tv_sec & 0xff);
727 /* returns int 0..14 using the high bits of a pseudo-random number instead of
728 the low bits, as the low bits are "less random" than the high ones...
729 slight roundoff error exists, an excercise for the reader.
730 need to multiply by something with lots of ones in it, so multiply by
731 8 or 16 is right out.
733 int afs_randomMod15()
737 temp = afs_random() >> 4;
738 temp = (temp *15) >> 28;
743 int afs_randomMod127()
747 temp = afs_random() >> 7;
748 temp = (temp *127) >> 25;
753 /* afs_SortOneServer()
754 * Sort all of the srvAddrs, of a server struct, by rank from low to high.
756 void afs_SortOneServer(struct server *asp)
758 struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
761 for (rootsa=&(asp->addr); *rootsa; rootsa=&(lowsa->next_sa)) {
762 lowprev = (struct srvAddr *)0;
763 lowsa = *rootsa; /* lowest sa is the first one */
764 lowrank = lowsa->sa_iprank;
766 for (tsa=*rootsa; tsa->next_sa; tsa=tsa->next_sa) {
767 rank = tsa->next_sa->sa_iprank;
768 if (rank < lowrank) {
770 lowsa = tsa->next_sa;
771 lowrank = lowsa->sa_iprank;
774 if (lowprev) { /* found one lower, so rearrange them */
775 lowprev->next_sa = lowsa->next_sa;
776 lowsa->next_sa = *rootsa;
783 * Sort the pointer to servers by the server's rank (its lowest rank).
784 * It is assumed that the server already has its IP addrs sorted (the
785 * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
787 void afs_SortServers(struct server *aservers[], int count)
792 AFS_STATCNT(afs_SortServers);
794 for (i=0; i<count; i++) {
795 if (!aservers[i]) break;
796 for (low=i,j=i+1; j<=count; j++) {
797 if (!aservers[j]) break;
798 if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
804 aservers[i] = aservers[low];
808 } /*afs_SortServers*/
810 /* afs_SetServerPrefs is rather system-dependent. It pokes around in kernel
811 data structures to determine what the local IP addresses and subnet masks
812 are in order to choose which server(s) are on the local subnet.
814 As I see it, there are several cases:
815 1. The server address is one of this host's local addresses. In this case
816 this server is to be preferred over all others.
817 2. The server is on the same subnet as one of the this host's local
818 addresses. (ie, an odd-sized subnet, not class A,B,orC)
819 3. The server is on the same net as this host (class A,B or C)
820 4. The server is on a different logical subnet or net than this host, but
821 this host is a 'metric 0 gateway' to it. Ie, two address-spaces share
823 5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
825 6. This host and the server are disjoint.
827 That is a rough order of preference. If a point-to-point link has a high
828 metric, I'm assuming that it is a very slow link, and putting it at the
829 bottom of the list (at least until RX works better over slow links). If
830 its metric is 1, I'm assuming that it's relatively fast (T1) and putting
832 It's not easy to check for case #4, so I'm ignoring it for the time being.
834 BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
835 That could be used to prefer certain servers fairly easily. Maybe some
838 NOTE: this code is very system-dependent, and very dependent on the TCP/IP
839 protocols (well, addresses that are stored in uint32s, at any rate).
842 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
843 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
845 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
846 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
851 #define PPWEIGHT 4096
856 #if defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
857 #include <inet/common.h>
858 /* IP interface structure, one per local address */
859 typedef struct ipif_s { /**/
860 struct ipif_s * ipif_next;
861 struct ill_s * ipif_ill; /* Back pointer to our ill */
862 long ipif_id; /* Logical unit number */
863 u_int ipif_mtu; /* Starts at ipif_ill->ill_max_frag */
864 afs_int32 ipif_local_addr; /* Local IP address for this if. */
865 afs_int32 ipif_net_mask; /* Net mask for this interface. */
866 afs_int32 ipif_broadcast_addr; /* Broadcast addr for this interface. */
867 afs_int32 ipif_pp_dst_addr; /* Point-to-point dest address. */
868 u_int ipif_flags; /* Interface flags. */
869 u_int ipif_metric; /* BSD if metric, for compatibility. */
870 u_int ipif_ire_type; /* LOCAL or LOOPBACK */
871 mblk_t * ipif_arp_down_mp; /* Allocated at time arp comes up to
872 * prevent awkward out of mem condition
875 mblk_t * ipif_saved_ire_mp; /* Allocated for each extra IRE_SUBNET/
876 * RESOLVER on this interface so that
877 * they can survive ifconfig down.
880 * The packet counts in the ipif contain the sum of the
881 * packet counts in dead IREs that were affiliated with
884 u_long ipif_fo_pkt_count; /* Forwarded thru our dead IREs */
885 u_long ipif_ib_pkt_count; /* Inbound packets for our dead IREs */
886 u_long ipif_ob_pkt_count; /* Outbound packets to our dead IREs */
888 ipif_multicast_up : 1, /* We have joined the allhosts group */
892 typedef struct ipfb_s { /**/
893 struct ipf_s * ipfb_ipf; /* List of ... */
894 kmutex_t ipfb_lock; /* Protect all ipf in list */
897 typedef struct ilm_s { /**/
900 u_int ilm_timer; /* IGMP */
901 struct ipif_s * ilm_ipif; /* Back pointer to ipif */
902 struct ilm_s * ilm_next; /* Linked list for each ill */
905 typedef struct ill_s { /**/
906 struct ill_s * ill_next; /* Chained in at ill_g_head. */
907 struct ill_s ** ill_ptpn; /* Pointer to previous next. */
908 queue_t * ill_rq; /* Read queue. */
909 queue_t * ill_wq; /* Write queue. */
911 int ill_error; /* Error value sent up by device. */
913 ipif_t * ill_ipif; /* Interface chain for this ILL. */
914 u_int ill_ipif_up_count; /* Number of IPIFs currently up. */
915 u_int ill_max_frag; /* Max IDU. */
916 char * ill_name; /* Our name. */
917 u_int ill_name_length; /* Name length, incl. terminator. */
918 u_int ill_subnet_type; /* IRE_RESOLVER or IRE_SUBNET. */
919 u_int ill_ppa; /* Physical Point of Attachment num. */
921 int ill_sap_length; /* Including sign (for position) */
922 u_int ill_phys_addr_length; /* Excluding the sap. */
923 mblk_t * ill_frag_timer_mp; /* Reassembly timer state. */
924 ipfb_t * ill_frag_hash_tbl; /* Fragment hash list head. */
926 queue_t * ill_bind_pending_q; /* Queue waiting for DL_BIND_ACK. */
927 ipif_t * ill_ipif_pending; /* IPIF waiting for DL_BIND_ACK. */
929 /* ill_hdr_length and ill_hdr_mp will be non zero if
930 * the underlying device supports the M_DATA fastpath
934 ilm_t * ill_ilm; /* Multicast mebership for lower ill */
936 /* All non-nil cells between 'ill_first_mp_to_free' and
937 * 'ill_last_mp_to_free' are freed in ill_delete.
939 #define ill_first_mp_to_free ill_hdr_mp
940 mblk_t * ill_hdr_mp; /* Contains fastpath template */
941 mblk_t * ill_bcast_mp; /* DLPI header for broadcasts. */
942 mblk_t * ill_bind_pending; /* T_BIND_REQ awaiting completion. */
943 mblk_t * ill_resolver_mp; /* Resolver template. */
944 mblk_t * ill_attach_mp;
945 mblk_t * ill_bind_mp;
946 mblk_t * ill_unbind_mp;
947 mblk_t * ill_detach_mp;
948 #define ill_last_mp_to_free ill_detach_mp
951 ill_frag_timer_running : 1,
952 ill_needs_attach : 1,
955 ill_unbind_pending : 1,
957 ill_pad_to_bit_31 : 27;
958 MI_HRT_DCL(ill_rtime)
963 #ifdef AFS_USERSPACE_IP_ADDR
965 #define min(A,B) ((A)<(B)) ? (A) : (B)
968 * The IP addresses and ranks are determined by afsd (in user space) and
969 * passed into the kernel at startup time through the AFSOP_ADVISEADDR
970 * system call. These are stored in the data structure
971 * called 'afs_cb_interface'.
973 afsi_SetServerIPRank(sa, addr, subnetmask)
974 struct srvAddr *sa; /* remote server */
975 afs_int32 addr; /* one of my local addr in net order */
976 afs_uint32 subnetmask; /* subnet mask of local addr in net order */
978 afs_uint32 myAddr, myNet, mySubnet, netMask;
979 afs_uint32 serverAddr ;
981 myAddr = ntohl(addr); /* one of my IP addr in host order */
982 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
983 subnetmask = ntohl(subnetmask);/* subnet mask in host order */
985 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
986 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
987 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
990 myNet = myAddr & netMask;
991 mySubnet = myAddr & subnetmask;
993 if ( (serverAddr & netMask ) == myNet ) {
994 if ( (serverAddr & subnetmask ) == mySubnet) {
995 if ( serverAddr == myAddr ) { /* same machine */
996 sa->sa_iprank = min(sa->sa_iprank, TOPR);
997 } else { /* same subnet */
998 sa->sa_iprank = min(sa->sa_iprank, HI);
1000 } else { /* same net */
1001 sa->sa_iprank = min(sa->sa_iprank, MED);
1005 #else /* AFS_USERSPACE_IP_ADDR */
1006 #if (! defined(AFS_SUN5_ENV)) && defined(USEIFADDR)
1008 afsi_SetServerIPRank(sa, ifa)
1010 struct in_ifaddr *ifa;
1012 struct sockaddr_in *sin;
1015 if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1016 if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1018 if ( SA2ULONG(sin) == ntohl(sa->sa_ip)) { /* ie, ME!!! */
1019 sa->sa_iprank = TOPR;
1021 t = HI + ifa->ia_ifp->if_metric; /* case #2 */
1022 if (sa->sa_iprank > t)
1026 t = MED + ifa->ia_ifp->if_metric;/* case #3 */
1027 if (sa->sa_iprank > t)
1031 #ifdef IFF_POINTTOPOINT
1032 /* check for case #4 -- point-to-point link */
1033 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1034 (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1035 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1038 t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1039 if (sa->sa_iprank > t)
1042 #endif /* IFF_POINTTOPOINT */
1044 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1045 #endif /* else AFS_USERSPACE_IP_ADDR */
1047 #ifdef AFS_SGI62_ENV
1049 afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1052 afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr*)h);
1053 return 0; /* Never match, so we enumerate everyone */
1055 #endif /* AFS_SGI62_ENV */
1057 static afs_SetServerPrefs(sa)
1060 #if defined(AFS_USERSPACE_IP_ADDR)
1061 extern interfaceAddr afs_cb_interface;
1065 for (i=0; i<afs_cb_interface.numberOfInterfaces; i++) {
1066 afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1067 afs_cb_interface.subnetmask[i]);
1069 #else /* AFS_USERSPACE_IP_ADDR */
1070 #if defined(AFS_SUN5_ENV)
1071 extern struct ill_s *ill_g_headp;
1074 int subnet, subnetmask, net, netmask;
1075 long *addr = (long *) ill_g_headp;
1076 extern struct ifnet *rxi_FindIfnet();
1078 if (sa) sa->sa_iprank= 0;
1079 for (ill = (struct ill_s *)*addr /*ill_g_headp*/; ill; ill = ill->ill_next ) {
1080 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next ) {
1081 subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1082 subnetmask = ipif->ipif_net_mask;
1084 * Generate the local net using the local address and
1085 * whate we know about Class A, B and C networks.
1087 if (IN_CLASSA(ipif->ipif_local_addr)) {
1088 netmask = IN_CLASSA_NET;
1089 } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1090 netmask = IN_CLASSB_NET;
1091 } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1092 netmask = IN_CLASSC_NET;
1096 net = ipif->ipif_local_addr & netmask;
1099 if (ipif->ipif_local_addr != 0x7f000001) { /* ignore loopback */
1101 if (*cnt > 16) return;
1102 *addrp++ = ipif->ipif_local_addr;
1107 /* XXXXXX Do the individual ip ranking below XXXXX */
1108 if ((sa->sa_ip & netmask) == net) {
1109 if ((sa->sa_ip & subnetmask) == subnet) {
1110 if (ipif->ipif_local_addr == sa->sa_ip) { /* ie, ME! */
1111 sa->sa_iprank = TOPR;
1113 sa->sa_iprank = HI + ipif->ipif_metric; /* case #2 */
1116 sa->sa_iprank = MED + ipif->ipif_metric; /* case #3 */
1119 sa->sa_iprank = LO + ipif->ipif_metric; /* case #4 */
1121 /* check for case #5 -- point-to-point link */
1122 if ((ipif->ipif_flags & IFF_POINTOPOINT) &&
1123 (ipif->ipif_pp_dst_addr == sa->sa_ip )) {
1125 if (ipif->ipif_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1126 sa->sa_iprank = MAXDEFRANK;
1128 sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1135 struct ifnet *ifn = (struct ifnet *)0;
1136 struct in_ifaddr *ifad = (struct in_ifaddr *) 0;
1137 struct sockaddr_in *sin;
1140 #ifdef notdef /* clean up, remove this */
1141 for (ifn = ifnet; ifn != NULL; ifn = ifn->if_next) {
1142 for (ifad = ifn->if_addrlist; ifad != NULL; ifad = ifad->ifa_next){
1143 if ((IFADDR2SA(ifad)->sa_family == AF_INET)
1144 && !(ifn->if_flags & IFF_LOOPBACK)) {
1146 if (*cnt > 16) return;
1147 *addrp++ = ((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr;
1156 ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1158 if (ifn) { /* local, more or less */
1160 if (ifn->if_flags & IFF_LOOPBACK) {
1161 sa->sa_iprank = TOPR;
1164 #endif /* IFF_LOOPBACK */
1165 sin = (struct sockaddr_in *) IA_SIN(ifad);
1166 if (SA2ULONG(sin) == sa->sa_ip) {
1167 sa->sa_iprank = TOPR;
1170 #ifdef IFF_BROADCAST
1171 if (ifn->if_flags & IFF_BROADCAST) {
1172 if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1177 #endif /* IFF_BROADCAST */
1178 #ifdef IFF_POINTOPOINT
1179 if (ifn->if_flags & IFF_POINTOPOINT) {
1180 if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1181 if (ifn->if_metric > 4) {
1185 else sa->sa_iprank = ifn->if_metric;
1188 #endif /* IFF_POINTOPOINT */
1189 sa->sa_iprank += MED + ifn->if_metric; /* couldn't find anything better */
1192 #else /* USEIFADDR */
1194 if (sa) sa->sa_iprank= LO;
1195 #ifdef AFS_SGI62_ENV
1196 (void) hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1200 extern struct in_ifaddr *in_ifaddr;
1201 struct in_ifaddr *ifa;
1202 for ( ifa = in_ifaddr; ifa; ifa = ifa->ia_next ) {
1203 afsi_SetServerIPRank(sa, ifa);
1208 #endif /* USEIFADDR */
1209 #endif /* AFS_SUN5_ENV */
1210 #endif /* else AFS_USERSPACE_IP_ADDR */
1213 if (sa) sa->sa_iprank += afs_randomMod15();
1216 } /* afs_SetServerPrefs */
1223 /* afs_FlushServer()
1224 * The addresses on this server struct has changed in some way and will
1225 * clean up all other structures that may reference it.
1226 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1228 void afs_FlushServer(srvp)
1229 struct server *srvp;
1232 struct server *ts, **pts;
1234 /* Find any volumes residing on this server and flush their state */
1235 afs_ResetVolumes(srvp);
1237 /* Flush all callbacks in the all vcaches for this specific server */
1238 afs_FlushServerCBs(srvp);
1240 /* Remove all the callbacks structs */
1242 struct afs_cbr *cb, *cbnext;
1243 extern afs_lock_t afs_xvcb;
1245 MObtainWriteLock(&afs_xvcb, 300);
1246 for (cb=srvp->cbrs; cb; cb=cbnext) {
1250 srvp->cbrs = (struct afs_cbr *)0;
1251 ReleaseWriteLock(&afs_xvcb);
1254 /* If no more srvAddr structs hanging off of this server struct,
1258 /* Remove the server structure from the cell list - if there */
1259 afs_RemoveCellEntry(srvp);
1261 /* Remove from the afs_servers hash chain */
1262 for (i=0; i<NSERVERS; i++) {
1263 for (pts=&(afs_servers[i]), ts=*pts; ts; pts=&(ts->next), ts=*pts) {
1264 if (ts == srvp) break;
1269 *pts = ts->next; /* Found it. Remove it */
1270 afs_osi_Free(ts, sizeof(struct server)); /* Free it */
1276 /* afs_RemoveSrvAddr()
1277 * This removes a SrvAddr structure from its server structure.
1278 * The srvAddr struct is not free'd because it connections may still
1279 * be open to it. It is up to the calling process to make sure it
1280 * remains connected to a server struct.
1281 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1282 * It is not removed from the afs_srvAddrs hash chain.
1284 void afs_RemoveSrvAddr(sap)
1285 struct srvAddr *sap;
1287 struct srvAddr **psa, *sa;
1293 /* Find the srvAddr in the server's list and remove it */
1294 for (psa=&(srv->addr), sa=*psa; sa; psa=&(sa->next_sa), sa=*psa) {
1295 if (sa == sap) break;
1302 /* Flush the server struct since it's IP address has changed */
1303 afs_FlushServer(srv);
1308 * Return an updated and properly initialized server structure
1309 * corresponding to the server ID, cell, and port specified.
1310 * If one does not exist, then one will be created.
1311 * aserver and aport must be in NET byte order.
1313 struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
1314 afs_int32 acell, u_short aport,
1315 afs_int32 locktype, afsUUID *uuidp,
1316 afs_int32 addr_uniquifier)
1318 struct server *oldts=0, *ts, *newts, *orphts=0;
1319 struct srvAddr *oldsa, *sa, *newsa, *nextsa, *orphsa;
1321 afs_int32 iphash, k, srvcount=0;
1322 unsigned int srvhash;
1324 AFS_STATCNT(afs_GetServer);
1326 ObtainSharedLock(&afs_xserver,13);
1328 /* Check if the server struct exists and is up to date */
1330 if (nservers != 1) panic("afs_GetServer: incorect count of servers");
1331 ObtainReadLock(&afs_xsrvAddr);
1332 ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1333 ReleaseReadLock(&afs_xsrvAddr);
1334 if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1335 /* Found a server struct that is not multihomed and has the
1336 * IP address associated with it. A correct match.
1338 ReleaseSharedLock(&afs_xserver);
1342 if (nservers <= 0) panic("afs_GetServer: incorrect count of servers");
1343 ts = afs_FindServer(0, aport, uuidp, locktype);
1344 if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1345 /* Found a server struct that is multihomed and same
1346 * uniqufier (same IP addrs). The above if statement is the
1347 * same as in InstallUVolumeEntry().
1349 ReleaseSharedLock(&afs_xserver);
1352 if (ts) oldts = ts; /* Will reuse if same uuid */
1355 UpgradeSToWLock(&afs_xserver,36);
1356 ObtainWriteLock(&afs_xsrvAddr,116);
1358 srvcount = afs_totalServers;
1360 /* Reuse/allocate a new server structure */
1364 newts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1365 if (!newts) panic("malloc of server struct");
1367 bzero((char *)newts, sizeof(struct server));
1369 /* Add the server struct to the afs_servers[] hash chain */
1370 srvhash = (uuidp ? (afs_uuid_hash(uuidp)%NSERVERS) : SHash(aserverp[0]));
1371 newts->next = afs_servers[srvhash];
1372 afs_servers[srvhash] = newts;
1375 /* Initialize the server structure */
1376 if (uuidp) { /* Multihomed */
1377 newts->sr_uuid = *uuidp;
1378 newts->sr_addr_uniquifier = addr_uniquifier;
1379 newts->flags |= SRVR_MULTIHOMED;
1381 if (acell) newts->cell = afs_GetCell(acell, 0);
1383 fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
1385 /* For each IP address we are registering */
1386 for (k=0; k<nservers; k++) {
1387 iphash = SHash(aserverp[k]);
1389 /* Check if the srvAddr structure already exists. If so, remove
1390 * it from its server structure and add it to the new one.
1392 for (oldsa=afs_srvAddrs[iphash]; oldsa; oldsa=oldsa->next_bkt) {
1393 if ( (oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport) ) break;
1395 if (oldsa && (oldsa->server != newts)) {
1396 afs_RemoveSrvAddr(oldsa); /* Remove from its server struct */
1397 oldsa->next_sa = newts->addr; /* Add to the new server struct */
1398 newts->addr = oldsa;
1401 /* Reuse/allocate a new srvAddr structure */
1405 newsa = (struct srvAddr *) afs_osi_Alloc(sizeof(struct srvAddr));
1406 if (!newsa) panic("malloc of srvAddr struct");
1407 afs_totalSrvAddrs++;
1408 bzero((char *)newsa, sizeof(struct srvAddr));
1410 /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1411 newsa->next_bkt = afs_srvAddrs[iphash];
1412 afs_srvAddrs[iphash] = newsa;
1414 /* Hang off of the server structure */
1415 newsa->next_sa = newts->addr;
1416 newts->addr = newsa;
1418 /* Initialize the srvAddr Structure */
1419 newsa->sa_ip = aserverp[k];
1420 newsa->sa_portal = aport;
1423 /* Update the srvAddr Structure */
1424 newsa->server = newts;
1425 if (newts->flags & SRVR_ISDOWN)
1426 newsa->sa_flags |= SRVADDR_ISDOWN;
1427 if (uuidp) newsa->sa_flags |= SRVADDR_MH;
1428 else newsa->sa_flags &= ~SRVADDR_MH;
1430 /* Compute preference values and resort */
1431 if (!newsa->sa_iprank) {
1432 if (aport == fsport) {
1433 afs_SetServerPrefs(newsa); /* new fileserver rank */
1435 newsa->sa_iprank = 10000 + afs_randomMod127(); /* new vlserver rank */
1439 afs_SortOneServer(newts); /* Sort by rank */
1441 /* If we reused the server struct, remove any of its srvAddr
1442 * structs that will no longer be associated with this server.
1444 if (oldts) { /* reused the server struct */
1445 for (orphsa=newts->addr; orphsa; orphsa=nextsa) {
1446 nextsa = orphsa->next_sa;
1447 for (k=0; k<nservers; k++) {
1448 if (orphsa->sa_ip == aserverp[k]) break; /* belongs */
1450 if (k < nservers) continue; /* belongs */
1452 /* Have a srvAddr struct. Now get a server struct (if not already) */
1454 orphts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1455 if (!orphts) panic("malloc of lo server struct");
1456 bzero((char *)orphts, sizeof(struct server));
1459 /* Add the orphaned server to the afs_servers[] hash chain.
1460 * Its iphash does not matter since we never look up the server
1461 * in the afs_servers table by its ip address (only by uuid -
1462 * which this has none).
1464 iphash = SHash(aserverp[k]);
1465 orphts->next = afs_servers[iphash];
1466 afs_servers[iphash] = orphts;
1468 if (acell) orphts->cell = afs_GetCell(acell, 0);
1471 /* Hang the srvAddr struct off of the server structure. The server
1472 * may have multiple srvAddrs, but it won't be marked multihomed.
1474 afs_RemoveSrvAddr(orphsa); /* remove */
1475 orphsa->next_sa = orphts->addr; /* hang off server struct */
1476 orphts->addr = orphsa;
1477 orphsa->server = orphts;
1478 orphsa->sa_flags |= SRVADDR_NOUSE; /* flag indicating not in use */
1479 orphsa->sa_flags &= ~SRVADDR_MH; /* Not multihomed */
1483 srvcount = afs_totalServers - srvcount; /* # servers added and removed */
1485 struct afs_stats_SrvUpDownInfo *upDownP;
1486 /* With the introduction of this new record, we need to adjust the
1487 * proper individual & global server up/down info.
1489 if (aport == fsport) { /* File Server record */
1490 upDownP = (acell == 1) ?
1491 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1492 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1493 } else { /* VL Server record */
1494 upDownP = (acell == 1) ?
1495 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1496 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1498 (upDownP->numTtlRecords) += srvcount;
1499 afs_stats_cmperf.srvRecords += srvcount;
1500 if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1501 afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1504 ReleaseWriteLock(&afs_xsrvAddr);
1505 ReleaseWriteLock(&afs_xserver);
1507 } /* afs_GetServer */
1509 void afs_ActivateServer(sap)
1510 struct srvAddr *sap;
1512 osi_timeval_t currTime; /*Filled with current time*/
1513 osi_timeval_t *currTimeP; /*Ptr to above*/
1514 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
1515 struct server *aserver = sap->server;
1517 if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1519 * This server record has not yet been activated. Go for it,
1520 * recording its ``birth''.
1522 aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1523 currTimeP = &currTime;
1524 osi_GetuTime(currTimeP);
1525 aserver->activationTime = currTime.tv_sec;
1526 if (sap->sa_portal == AFS_FSPORT) {
1527 upDownP = (aserver->cell->cell == 1) ?
1528 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1529 &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1530 } /*File Server record*/
1532 upDownP = (aserver->cell->cell == 1) ?
1533 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1534 &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1535 } /*VL Server record*/
1536 if (aserver->flags & SRVR_ISDOWN)
1537 (upDownP->numDownRecords)++;
1539 (upDownP->numUpRecords)++;
1540 (upDownP->numRecordsNeverDown)++;