Use AFS_RXDEADTIME instead of hardcoding a value of 50
[openafs.git] / src / afs / afs_server.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * Implements:
12  * afs_MarkServerUpOrDown
13  * afs_ServerDown
14  * afs_CountServers
15  * afs_CheckServers
16  * afs_FindServer
17  * afs_random
18  * afs_randomMod127
19  * afs_SortServers
20  * afsi_SetServerIPRank
21  * afs_GetServer
22  * afs_ActivateServer
23  * 
24  *
25  * Local:
26  * HaveCallBacksFrom
27  * CheckVLServer
28  * afs_SortOneServer
29  * afs_SetServerPrefs
30  * 
31  */
32 #include <afsconfig.h>
33 #include "../afs/param.h"
34
35 RCSID("$Header$");
36
37 #include "../afs/stds.h"
38 #include "../afs/sysincludes.h" /* Standard vendor system headers */
39
40 #if !defined(UKERNEL)
41 #include <net/if.h>
42 #include <netinet/in.h>
43
44 #ifdef AFS_SGI62_ENV
45 #include "../h/hashing.h"
46 #endif
47 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV)
48 #include <netinet/in_var.h>
49 #endif /* AFS_HPUX110_ENV */
50 #endif /* !defined(UKERNEL) */
51
52 #include "../afs/afsincludes.h" /* Afs-based standard headers */
53 #include "../afs/afs_stats.h"   /* afs statistics */
54
55 #if     defined(AFS_SUN56_ENV)
56 #include <inet/led.h>
57 #include <inet/common.h>
58 #if     defined(AFS_SUN58_ENV)
59 # include <netinet/ip6.h>
60 # define ipif_local_addr ipif_lcl_addr
61 #  ifndef V4_PART_OF_V6
62 #  define V4_PART_OF_V6(v6)       v6.s6_addr32[3]
63 #  endif
64 # endif
65 #include <inet/ip.h>
66 #endif
67
68 /* Imported variables */
69 extern afs_int32 afs_setTime;
70 extern afs_int32 afs_waitForever;
71 extern short afs_waitForeverCount;
72
73
74 /* Exported variables */
75 afs_rwlock_t afs_xserver;               /* allocation lock for servers */
76 struct server *afs_setTimeHost=0;       /* last host we used for time */
77 struct server *afs_servers[NSERVERS];    /* Hashed by server`s uuid & 1st ip */
78 afs_rwlock_t afs_xsrvAddr;              /* allocation lock for srvAddrs */
79 struct srvAddr *afs_srvAddrs[NSERVERS];  /* Hashed by server's ip */
80
81
82 /* debugging aids - number of alloc'd server and srvAddr structs. */
83 int afs_reuseServers  = 0;
84 int afs_reuseSrvAddrs = 0;
85 int afs_totalServers  = 0;
86 int afs_totalSrvAddrs = 0;
87
88
89
90
91 /*------------------------------------------------------------------------
92  * afs_MarkServerUpOrDown
93  *
94  * Description:
95  *      Mark the given server up or down, and track its uptime stats.
96  *
97  * Arguments:
98  *      a_serverP : Ptr to server record to fiddle with.
99  *      a_isDown  : Is the server is to be marked down?
100  *
101  * Returns:
102  *      Nothing.
103  *
104  * Environment:
105  *      The CM server structures must be write-locked.
106  *
107  * Side Effects:
108  *      As advertised.
109  *------------------------------------------------------------------------*/
110
111 void afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
112 {
113     register struct server *a_serverP = sa->server;
114     register struct srvAddr *sap;
115     osi_timeval_t currTime, *currTimeP;     /*Current time*/
116     afs_int32 downTime;                      /*Computed downtime, in seconds*/
117     struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
118
119     /*
120      * If the server record is marked the same as the new status we've
121      * been fed, then there isn't much to be done.
122      */
123     if (( a_isDown &&  (sa->sa_flags & SRVADDR_ISDOWN)) || 
124         (!a_isDown && !(sa->sa_flags & SRVADDR_ISDOWN)))
125         return;
126
127     if (a_isDown) {
128         sa->sa_flags |= SRVADDR_ISDOWN;
129         for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
130             if (!(sap->sa_flags & SRVADDR_ISDOWN)) {
131                 /* Not all ips are up so don't bother with the
132                  * server's up/down stats */
133                 return;
134             }
135         }    
136         /* 
137          * All ips are down we treat the whole server down
138          */
139         a_serverP->flags |= SRVR_ISDOWN;
140         /*
141          * If this was our time server, search for another time server
142          */
143         if (a_serverP == afs_setTimeHost)
144             afs_setTimeHost = 0;
145     } else {
146         sa->sa_flags &= ~SRVADDR_ISDOWN;
147         /* If any ips are up, the server is also marked up */
148         a_serverP->flags &= ~SRVR_ISDOWN;
149         for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
150             if (sap->sa_flags & SRVADDR_ISDOWN) {
151                 /* Not all ips are up so don't bother with the
152                  * server's up/down stats */
153                 return;
154             }
155         }    
156     }
157 #ifndef AFS_NOSTATS
158     /*
159      * Compute the current time and which overall stats record is to be
160      * updated; we'll need them one way or another.
161      */
162     currTimeP = &currTime;
163     osi_GetuTime(currTimeP);
164
165     if (sa->sa_portal == AFS_FSPORT) {
166         upDownP = (a_serverP->cell->cell == 1) ?
167             &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
168             &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
169     } /*File Server record*/
170     else {
171         upDownP = (a_serverP->cell->cell == 1) ?
172             &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
173             &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
174     } /*VL Server record*/
175
176     if (a_isDown) {
177         /*
178          * Server going up -> down; remember the beginning of this
179          * downtime incident.
180          */
181         a_serverP->lastDowntimeStart = currTime.tv_sec;
182
183         (upDownP->numDownRecords)++;
184         (upDownP->numUpRecords)--;
185     } /*Server being marked down*/
186     else {
187         /*
188          * Server going down -> up; remember everything about this
189          * newly-completed downtime incident.
190          */
191         downTime = currTime.tv_sec - a_serverP->lastDowntimeStart;
192         (a_serverP->numDowntimeIncidents)++;
193         a_serverP->sumOfDowntimes += downTime;
194
195         (upDownP->numUpRecords)++;
196         (upDownP->numDownRecords)--;
197         (upDownP->numDowntimeIncidents)++;
198         if (a_serverP->numDowntimeIncidents == 1)
199             (upDownP->numRecordsNeverDown)--;
200         upDownP->sumOfDowntimes += downTime;
201         if ((upDownP->shortestDowntime == 0) ||
202             (downTime < upDownP->shortestDowntime))
203             upDownP->shortestDowntime = downTime;
204         if ((upDownP->longestDowntime == 0) ||
205             (downTime > upDownP->longestDowntime))
206             upDownP->longestDowntime = downTime;
207
208
209         if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET0)
210             (upDownP->downDurations[0])++;
211         else
212             if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET1)
213                 (upDownP->downDurations[1])++;
214         else
215             if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET2)
216                 (upDownP->downDurations[2])++;
217         else
218             if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET3)
219                 (upDownP->downDurations[3])++;
220         else
221             if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET4)
222                 (upDownP->downDurations[4])++;
223         else
224             if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET5)
225                 (upDownP->downDurations[5])++;
226         else
227             (upDownP->downDurations[6])++;
228
229     } /*Server being marked up*/
230 #endif
231 } /*MarkServerUpOrDown*/
232
233
234 void afs_ServerDown(struct srvAddr *sa)
235 {
236     register struct server *aserver = sa->server;
237     register struct srvAddr *sap;
238
239     AFS_STATCNT(ServerDown);
240     if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
241         return;
242     afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
243     if (sa->sa_portal == aserver->cell->vlport)
244          print_internet_address("afs: Lost contact with volume location server ",
245                                sa, "", 1);
246     else
247          print_internet_address("afs: Lost contact with file server ", sa, "", 1);
248
249 } /*ServerDown*/
250
251
252 /* return true if we have any callback promises from this server */
253 static HaveCallBacksFrom(aserver)
254     struct server *aserver;
255
256 {
257     register afs_int32 now;
258     register int i;
259     register struct vcache *tvc;
260
261     AFS_STATCNT(HaveCallBacksFrom);
262     now = osi_Time();       /* for checking for expired callbacks */
263     for(i=0;i<VCSIZE;i++) { /* for all guys in the hash table */
264         for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
265             /*
266              * Check to see if this entry has an unexpired callback promise
267              * from the required host
268              */
269             if (aserver == tvc->callback && tvc->cbExpires >= now
270                 && ((tvc->states & CRO) == 0))
271                 return 1;
272         }
273     }
274     return 0;
275
276 } /*HaveCallBacksFrom*/
277
278
279 static void CheckVLServer(sa, areq)
280     struct vrequest *areq;
281     register struct srvAddr *sa;
282 {
283     register struct server *aserver = sa->server;
284     register struct conn *tc;
285     register afs_int32 code;
286
287     AFS_STATCNT(CheckVLServer);
288     /* Ping dead servers to see if they're back */
289     if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN)) || (aserver->flags & SRVR_ISGONE))
290         return;
291     if (!aserver->cell)
292         return; /* can't do much */
293
294     tc = afs_ConnByHost(aserver, aserver->cell->vlport, 
295                         aserver->cell->cell, areq, 1, SHARED_LOCK);
296     if (!tc)
297         return;
298     rx_SetConnDeadTime(tc->id, 3);
299
300     RX_AFS_GUNLOCK();
301     code = VL_ProbeServer(tc->id);
302     RX_AFS_GLOCK();
303     rx_SetConnDeadTime(tc->id, AFS_RXDEADTIME);
304     afs_PutConn(tc, SHARED_LOCK);
305     /*
306      * If probe worked, or probe call not yet defined (for compatibility
307      * with old vlsevers), then we treat this server as running again
308      */
309     if (code == 0 || (code <= -450 && code >= -470)) {
310         if (tc->srvr == sa) {
311             afs_MarkServerUpOrDown(sa, 0);
312             print_internet_address("afs: volume location server ",
313                                    sa, " is back up", 2);
314         }
315     }
316
317 } /*CheckVLServer*/
318
319
320 #ifndef AFS_MINCHANGE   /* So that some can increase it in param.h */
321 #define AFS_MINCHANGE 2         /* min change we'll bother with */
322 #endif
323 #ifndef AFS_MAXCHANGEBACK
324 #define AFS_MAXCHANGEBACK 10    /* max seconds we'll set a clock back at once */
325 #endif
326
327
328 /*------------------------------------------------------------------------
329  * EXPORTED afs_CountServers
330  *
331  * Description:
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
335  *      fly.
336  *
337  * Arguments:
338  *      None.
339  *
340  * Returns:
341  *      Nothing.
342  *
343  * Environment:
344  *      This routine locks afs_xserver for write for the duration.
345  *
346  * Side Effects:
347  *      Set CM perf stats field sumOfRecordAges for all server record
348  *      entries.
349  *------------------------------------------------------------------------*/
350
351 void afs_CountServers()
352
353 { /*afs_CountServers*/
354
355     int currIdx;                                /*Curr idx into srv table*/
356     struct server *currSrvP;                    /*Ptr to curr server record*/
357     afs_int32 currChainLen;                             /*Length of curr hash chain*/
358     osi_timeval_t currTime;                     /*Current time*/
359     osi_timeval_t *currTimeP;                   /*Ptr to above*/
360     afs_int32 srvRecordAge;                             /*Age of server record, in secs*/
361     struct afs_stats_SrvUpDownInfo *upDownP;    /*Ptr to current up/down
362                                                   info being manipulated*/
363
364     /*
365      * Write-lock the server table so we don't get any interference.
366      */
367     ObtainReadLock(&afs_xserver);
368
369     /*
370      * Iterate over each hash index in the server table, walking down each
371      * chain and tallying what we haven't computed from the records there on
372      * the fly.  First, though, initialize the tallies that will change.
373      */
374     afs_stats_cmperf.srvMaxChainLength = 0;
375
376     afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges     = 0;
377     afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
378     afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord   = 0;
379     memset((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
380
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((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
385
386     afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges     = 0;
387     afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
388     afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord   = 0;
389     memset((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
390
391     afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges     = 0;
392     afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
393     afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord   = 0;
394     memset((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
395
396     /*
397      * Compute the current time, used to figure out server record ages.
398      */
399     currTimeP = &currTime;
400     osi_GetuTime(currTimeP);
401
402     /*
403      * Sweep the server hash table, tallying all we need to know.
404      */
405     for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
406         currChainLen = 0;
407         for (currSrvP = afs_servers[currIdx]; currSrvP; currSrvP = currSrvP->next) {
408             /*
409              * Bump the current chain length.
410              */
411             currChainLen++;
412
413             /*
414              * Any further tallying for this record will only be done if it has
415              * been activated. 
416              */
417             if ( (currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED) &&
418                   currSrvP->addr && currSrvP->cell ) {
419
420                 /*
421                  * Compute the current server record's age, then remember it
422                  * in the appropriate places.
423                  */
424                 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
425                 if (currSrvP->addr->sa_portal == AFS_FSPORT) {
426                     upDownP = (currSrvP->cell->cell == 1) ?
427                         &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]):
428                         &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
429                 } /*File Server record*/
430                 else {
431                     upDownP = (currSrvP->cell->cell == 1) ?
432                         &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]):
433                         &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
434                 } /*VL Server record*/
435
436                 upDownP->sumOfRecordAges += srvRecordAge;
437                 if ((upDownP->ageOfYoungestRecord == 0) ||
438                     (srvRecordAge < upDownP->ageOfYoungestRecord))
439                     upDownP->ageOfYoungestRecord = srvRecordAge;
440                 if ((upDownP->ageOfOldestRecord == 0) ||
441                     (srvRecordAge > upDownP->ageOfOldestRecord))
442                     upDownP->ageOfOldestRecord = srvRecordAge;
443
444                 if (currSrvP->numDowntimeIncidents <=
445                     AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
446                     (upDownP->downIncidents[0])++;
447                 else
448                     if (currSrvP->numDowntimeIncidents <=
449                         AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
450                         (upDownP->downIncidents[1])++;
451                 else
452                     if (currSrvP->numDowntimeIncidents <=
453                         AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
454                         (upDownP->downIncidents[2])++;
455                 else
456                     if (currSrvP->numDowntimeIncidents <=
457                         AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
458                         (upDownP->downIncidents[3])++;
459                 else
460                     if (currSrvP->numDowntimeIncidents <=
461                         AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
462                         (upDownP->downIncidents[4])++;
463                 else
464                     (upDownP->downIncidents[5])++;
465
466
467             } /*Current server has been active*/
468         } /*Walk this chain*/
469
470         /*
471          * Before advancing to the next chain, remember facts about this one.
472          */
473         if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
474             /*
475              * We beat out the former champion (which was initially set to 0
476              * here).  Mark down the new winner, and also remember if it's an
477              * all-time winner.
478              */
479             afs_stats_cmperf.srvMaxChainLength = currChainLen;
480             if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
481                 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
482         } /*Update chain length maximum*/
483     } /*For each hash chain*/
484
485     /*
486      * We're done.  Unlock the server table before returning to our caller.
487      */
488     ReleaseReadLock(&afs_xserver);
489
490 } /*afs_CountServers*/
491
492
493 /* check down servers (if adown), or running servers (if !adown) */
494 void afs_CheckServers(adown, acellp)
495     struct cell *acellp;
496     int adown;
497
498 {
499     struct vrequest treq;
500     struct server *ts;
501     struct srvAddr *sa;
502     struct conn *tc;
503     afs_int32 i, j;
504     afs_int32 code;
505     afs_int32 start, end, delta;
506     osi_timeval_t tv;
507     int setTimer;
508     struct unixuser *tu;
509     char tbuffer[CVBS];
510     int srvAddrCount;
511     struct srvAddr **addrs;
512     XSTATS_DECLS;
513
514     AFS_STATCNT(afs_CheckServers);
515     if (code = afs_InitReq(&treq, &afs_osi_cred)) return;
516     ObtainReadLock(&afs_xserver);  /* Necessary? */
517     ObtainReadLock(&afs_xsrvAddr);      
518
519     srvAddrCount = 0;
520     for (i=0;i<NSERVERS;i++) {
521         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) { 
522             srvAddrCount++;
523         }
524     }
525
526     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
527     j = 0;
528     for (i=0;i<NSERVERS;i++) {
529         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) { 
530             if (j >= srvAddrCount) break;
531             addrs[j++] = sa;
532         }
533     }
534
535     ReleaseReadLock(&afs_xsrvAddr);     
536     ReleaseReadLock(&afs_xserver);
537
538     for (i=0; i<j; i++) {
539         sa = addrs[i];
540         ts = sa->server;
541         if (!ts)
542             continue;
543
544         /* See if a cell to check was specified.  If it is spec'd and not
545          * this server's cell, just skip the server.
546          */
547         if (acellp && acellp != ts->cell)
548             continue;
549
550         if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
551             (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
552             continue;
553
554         /* check vlserver with special code */
555         if (sa->sa_portal == AFS_VLPORT) {
556             CheckVLServer(sa, &treq);
557             continue;
558         }
559
560         if (!ts->cell) /* not really an active server, anyway, it must */
561             continue;  /* have just been added by setsprefs */ 
562
563         /* get a connection, even if host is down; bumps conn ref count */
564         tu = afs_GetUser(treq.uid, ts->cell, SHARED_LOCK);
565         tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cell, tu,
566                           1/*force*/, 1/*create*/, SHARED_LOCK);
567         afs_PutUser(tu, SHARED_LOCK);
568         if (!tc) continue;
569
570         if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
571             (tc->srvr->server == afs_setTimeHost)) {
572             if (sa->sa_flags & SRVADDR_ISDOWN) {
573                 rx_SetConnDeadTime(tc->id, 3);
574                 setTimer = 1;
575             } else {
576                 setTimer = 0;
577             }
578
579             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
580             start = osi_Time();         /* time the gettimeofday call */
581             RX_AFS_GUNLOCK();
582             code = RXAFS_GetTime(tc->id, &tv.tv_sec, &tv.tv_usec);
583             RX_AFS_GLOCK();
584             end = osi_Time();
585             XSTATS_END_TIME;
586             /*
587              * If we're supposed to set the time, and the call worked
588              * quickly (same second response) and this is the host we
589              * use for the time and the time is really different, then
590              * really set the time
591              */
592             if (code == 0 && start == end && afs_setTime != 0 &&
593                 (tc->srvr->server == afs_setTimeHost ||
594                 /*
595                  * Sync only to a server in the local cell: cell(id)==1
596                  * or CPrimary.
597                  */
598                 (afs_setTimeHost == (struct server *)0 &&
599                  (ts->cell->cell == 1 || (ts->cell->states&CPrimary))))) {
600
601                 char msgbuf[90];  /* strlen("afs: setting clock...") + slop */
602                 /* set the time */
603                 delta = end - tv.tv_sec;   /* how many secs fast we are */
604                 /* see if clock has changed enough to make it worthwhile */
605                 if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
606                     if (delta > AFS_MAXCHANGEBACK) {
607                         /* setting clock too far back, just do it a little */
608                         tv.tv_sec = end - AFS_MAXCHANGEBACK;
609                     }
610                     afs_osi_SetTime(&tv);
611                     if (delta > 0) {
612                         strcpy(msgbuf, "afs: setting clock back ");
613                         if (delta > AFS_MAXCHANGEBACK) {
614                             afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
615                             afs_strcat(msgbuf, " seconds (of ");
616                             afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
617                             afs_strcat(msgbuf, ", via ");
618                             print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
619                         } else {
620                             afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
621                             afs_strcat(msgbuf, " seconds (via ");
622                             print_internet_address(msgbuf, sa, ").", 0);
623                         }
624                     } else {
625                         strcpy(msgbuf, "afs: setting clock ahead ");
626                         afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
627                         afs_strcat(msgbuf, " seconds (via ");
628                         print_internet_address(msgbuf, sa, ").", 0);
629                     }
630                 }
631                 afs_setTimeHost = tc->srvr->server;
632             }
633             if (setTimer)
634                 rx_SetConnDeadTime(tc->id, AFS_RXDEADTIME);
635             if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
636                 /* server back up */
637                 print_internet_address("afs: file server ", sa, " is back up", 2);
638
639                 ObtainWriteLock(&afs_xserver, 244);
640                 ObtainWriteLock(&afs_xsrvAddr, 245);    
641                 afs_MarkServerUpOrDown(sa, 0);
642                 ReleaseWriteLock(&afs_xsrvAddr);
643                 ReleaseWriteLock(&afs_xserver);
644
645                 if (afs_waitForeverCount) {
646                     afs_osi_Wakeup(&afs_waitForever);
647                 }
648             } else {
649                 if (code < 0) {
650                     /* server crashed */
651                     afs_ServerDown(sa);
652                     ForceNewConnections(sa);  /* multi homed clients */
653                 }
654             }
655         }
656
657         afs_PutConn(tc, SHARED_LOCK);   /* done with it now */
658     } /* Outer loop over addrs */
659
660     afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
661
662 } /*afs_CheckServers*/
663
664
665 /* find a server structure given the host address */
666 struct server *afs_FindServer (afs_int32 aserver, ushort aport,
667                                afsUUID *uuidp, afs_int32 locktype)
668 {
669     struct server *ts;
670     struct srvAddr *sa;
671     int i;
672
673     AFS_STATCNT(afs_FindServer);
674     if (uuidp) {
675         i = afs_uuid_hash(uuidp) % NSERVERS;
676         for (ts = afs_servers[i]; ts; ts = ts->next) {
677             if ( (ts->flags & SRVR_MULTIHOMED) &&
678                  (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
679                  (!ts->addr || (ts->addr->sa_portal == aport)) )
680                 return ts;
681         }
682     } else {
683         i = SHash(aserver);
684         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
685             if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
686               return sa->server;
687             }
688         }
689     }
690     return (struct server *)0;
691
692 } /*afs_FindServer*/
693
694
695 /* some code for creating new server structs and setting preferences follows
696  * in the next few lines...
697  */
698
699 #define MAXDEFRANK 60000
700 #define DEFRANK    40000
701
702 /* Random number generator and constants from KnuthV2 2d ed, p170 */
703
704 /* Rules:
705    X = (aX + c) % m
706    m is a power of two 
707    a % 8 is 5
708    a is 0.73m  should be 0.01m .. 0.99m
709    c is more or less immaterial.  1 or a is suggested.
710   
711 NB:  LOW ORDER BITS are not very random.  To get small random numbers,
712      treat result as <1, with implied binary point, and multiply by 
713      desired modulus.
714 NB:  Has to be unsigned, since shifts on signed quantities may preserve
715      the sign bit.
716 */
717 /* added rxi_getaddr() to try to get as much initial randomness as 
718    possible, since at least one customer reboots ALL their clients 
719    simultaneously -- so osi_Time is bound to be the same on some of the
720    clients.  This is probably OK, but I don't want to see too much of it.
721 */
722
723 #define ranstage(x)     (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
724 extern afs_int32 rxi_getaddr();
725
726 unsigned int afs_random()
727
728 {
729     static afs_int32 state = 0;
730     register int i;
731
732     AFS_STATCNT(afs_random);
733     if (!state) {
734         osi_timeval_t t;
735         osi_GetTime(&t);
736         /*
737          * 0xfffffff0 was changed to (~0 << 4) since it works no matter how many
738          * bits are in a tv_usec
739          */
740         state = (t.tv_usec & (~0 << 4) ) + (rxi_getaddr() & 0xff); 
741         state += (t.tv_sec & 0xff);
742         for (i=0;i<30;i++) {
743             ranstage(state);
744         }
745     }
746
747     ranstage(state);
748     return (state);
749
750 } /*afs_random*/
751
752 /* returns int 0..14 using the high bits of a pseudo-random number instead of
753    the low bits, as the low bits are "less random" than the high ones...
754    slight roundoff error exists, an excercise for the reader.
755    need to multiply by something with lots of ones in it, so multiply by 
756    8 or 16 is right out.
757  */
758 int afs_randomMod15()
759 {
760 afs_uint32 temp;
761
762 temp = afs_random() >> 4;
763 temp = (temp *15) >> 28;
764
765 return temp;
766 }
767
768 int afs_randomMod127()
769 {
770 afs_uint32 temp;
771
772 temp = afs_random() >> 7;
773 temp = (temp *127) >> 25;
774
775 return temp;
776 }
777
778 /* afs_SortOneServer()
779  * Sort all of the srvAddrs, of a server struct, by rank from low to high.
780  */
781 void afs_SortOneServer(struct server *asp)
782 {
783    struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
784    int lowrank, rank;
785       
786    for (rootsa=&(asp->addr); *rootsa; rootsa=&(lowsa->next_sa)) {
787       lowprev = (struct srvAddr *)0;
788       lowsa   = *rootsa;             /* lowest sa is the first one */
789       lowrank = lowsa->sa_iprank;
790
791       for (tsa=*rootsa; tsa->next_sa; tsa=tsa->next_sa) {
792          rank = tsa->next_sa->sa_iprank;
793          if (rank < lowrank) {
794             lowprev = tsa;
795             lowsa   = tsa->next_sa;
796             lowrank = lowsa->sa_iprank;
797          }
798       }
799       if (lowprev) { /* found one lower, so rearrange them */
800          lowprev->next_sa = lowsa->next_sa;
801          lowsa->next_sa   = *rootsa;
802          *rootsa          = lowsa;
803       }
804    }
805 }
806     
807 /* afs_SortServer()
808  * Sort the pointer to servers by the server's rank (its lowest rank).
809  * It is assumed that the server already has its IP addrs sorted (the
810  * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
811  */
812 void afs_SortServers(struct server *aservers[], int count)
813 {
814     struct server *ts;
815     int i, j, low;
816
817     AFS_STATCNT(afs_SortServers);
818
819     for (i=0; i<count; i++) {
820        if (!aservers[i]) break;
821        for (low=i,j=i+1; j<=count; j++) {
822            if ((!aservers[j]) || (!aservers[j]->addr)) 
823                break;
824            if ((!aservers[low]) || (!aservers[low]->addr))
825                break;
826            if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
827                low = j;
828            }
829        }
830        if (low != i) {
831           ts = aservers[i]; 
832           aservers[i] = aservers[low];
833           aservers[low] = ts;
834        }
835     }
836 } /*afs_SortServers*/
837
838 /* afs_SetServerPrefs is rather system-dependent.  It pokes around in kernel
839    data structures to determine what the local IP addresses and subnet masks 
840    are in order to choose which server(s) are on the local subnet.
841
842    As I see it, there are several cases:
843    1. The server address is one of this host's local addresses.  In this case
844           this server is to be preferred over all others.
845    2. The server is on the same subnet as one of the this host's local
846       addresses.  (ie, an odd-sized subnet, not class A,B,orC)
847    3. The server is on the same net as this host (class A,B or C)
848    4. The server is on a different logical subnet or net than this host, but
849    this host is a 'metric 0 gateway' to it.  Ie, two address-spaces share
850    one physical medium.
851    5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the 
852    server.
853    6. This host and the server are disjoint.
854
855    That is a rough order of preference.  If a point-to-point link has a high
856    metric, I'm assuming that it is a very slow link, and putting it at the 
857    bottom of the list (at least until RX works better over slow links).  If 
858    its metric is 1, I'm assuming that it's relatively fast (T1) and putting 
859    it ahead of #6.
860    It's not easy to check for case #4, so I'm ignoring it for the time being.
861
862    BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
863    That could be used to prefer certain servers fairly easily.  Maybe some 
864    other time...
865
866    NOTE: this code is very system-dependent, and very dependent on the TCP/IP
867    protocols (well, addresses that are stored in uint32s, at any rate).
868  */
869
870 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
871 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
872
873 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
874 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
875 #define TOPR 5000
876 #define HI  20000
877 #define MED 30000
878 #define LO DEFRANK
879 #define PPWEIGHT 4096
880
881 #define USEIFADDR
882
883  
884 #if     defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
885 #include <inet/common.h>
886 /* IP interface structure, one per local address */
887 typedef struct ipif_s {                 /**/
888         struct ipif_s   * ipif_next;
889         struct ill_s    * ipif_ill;     /* Back pointer to our ill */
890         long    ipif_id;                /* Logical unit number */
891         u_int   ipif_mtu;               /* Starts at ipif_ill->ill_max_frag */
892         afs_int32       ipif_local_addr;        /* Local IP address for this if. */
893         afs_int32       ipif_net_mask;          /* Net mask for this interface. */
894         afs_int32       ipif_broadcast_addr;    /* Broadcast addr for this interface. */
895         afs_int32       ipif_pp_dst_addr;       /* Point-to-point dest address. */
896         u_int   ipif_flags;             /* Interface flags. */
897         u_int   ipif_metric;            /* BSD if metric, for compatibility. */
898         u_int   ipif_ire_type;          /* LOCAL or LOOPBACK */
899         mblk_t  * ipif_arp_down_mp;     /* Allocated at time arp comes up to
900                                          * prevent awkward out of mem condition
901                                          * later
902                                          */
903         mblk_t  * ipif_saved_ire_mp;    /* Allocated for each extra IRE_SUBNET/
904                                          * RESOLVER on this interface so that
905                                          * they can survive ifconfig down.
906                                          */
907         /*
908          * The packet counts in the ipif contain the sum of the
909          * packet counts in dead IREs that were affiliated with
910          * this ipif.
911          */
912         u_long  ipif_fo_pkt_count;      /* Forwarded thru our dead IREs */
913         u_long  ipif_ib_pkt_count;      /* Inbound packets for our dead IREs */
914         u_long  ipif_ob_pkt_count;      /* Outbound packets to our dead IREs */
915         unsigned int
916                 ipif_multicast_up : 1,  /* We have joined the allhosts group */
917                 : 0;
918 } ipif_t;
919
920 typedef struct ipfb_s {                 /**/
921         struct ipf_s    * ipfb_ipf;     /* List of ... */
922         kmutex_t        ipfb_lock;      /* Protect all ipf in list */
923 } ipfb_t;
924
925 typedef struct ilm_s {                  /**/
926         afs_int32               ilm_addr;
927         int             ilm_refcnt;
928         u_int           ilm_timer;      /* IGMP */
929         struct ipif_s   * ilm_ipif;     /* Back pointer to ipif */
930         struct ilm_s    * ilm_next;     /* Linked list for each ill */
931 } ilm_t;
932
933 typedef struct ill_s {                  /**/
934         struct  ill_s   * ill_next;     /* Chained in at ill_g_head. */
935         struct  ill_s   ** ill_ptpn;    /* Pointer to previous next. */
936         queue_t * ill_rq;               /* Read queue. */
937         queue_t * ill_wq;               /* Write queue. */
938
939         int     ill_error;              /* Error value sent up by device. */
940
941         ipif_t  * ill_ipif;             /* Interface chain for this ILL. */
942         u_int   ill_ipif_up_count;      /* Number of IPIFs currently up. */
943         u_int   ill_max_frag;           /* Max IDU. */
944         char    * ill_name;             /* Our name. */
945         u_int   ill_name_length;        /* Name length, incl. terminator. */
946         u_int   ill_subnet_type;        /* IRE_RESOLVER or IRE_SUBNET. */
947         u_int   ill_ppa;                /* Physical Point of Attachment num. */
948         u_long  ill_sap;
949         int     ill_sap_length;         /* Including sign (for position) */
950         u_int   ill_phys_addr_length;   /* Excluding the sap. */
951         mblk_t  * ill_frag_timer_mp;    /* Reassembly timer state. */
952         ipfb_t  * ill_frag_hash_tbl;    /* Fragment hash list head. */
953
954         queue_t * ill_bind_pending_q;   /* Queue waiting for DL_BIND_ACK. */
955         ipif_t  * ill_ipif_pending;     /* IPIF waiting for DL_BIND_ACK. */
956
957         /* ill_hdr_length and ill_hdr_mp will be non zero if
958          * the underlying device supports the M_DATA fastpath
959          */
960         int     ill_hdr_length;
961
962         ilm_t   * ill_ilm;              /* Multicast mebership for lower ill */
963
964         /* All non-nil cells between 'ill_first_mp_to_free' and
965          * 'ill_last_mp_to_free' are freed in ill_delete.
966          */
967 #define ill_first_mp_to_free    ill_hdr_mp
968         mblk_t  * ill_hdr_mp;           /* Contains fastpath template */
969         mblk_t  * ill_bcast_mp;         /* DLPI header for broadcasts. */
970         mblk_t  * ill_bind_pending;     /* T_BIND_REQ awaiting completion. */
971         mblk_t  * ill_resolver_mp;      /* Resolver template. */
972         mblk_t  * ill_attach_mp;
973         mblk_t  * ill_bind_mp;
974         mblk_t  * ill_unbind_mp;
975         mblk_t  * ill_detach_mp;
976 #define ill_last_mp_to_free     ill_detach_mp
977
978         u_int
979                 ill_frag_timer_running : 1,
980                 ill_needs_attach : 1,
981                 ill_is_ptp : 1,
982                 ill_priv_stream : 1,
983                 ill_unbind_pending : 1,
984
985                 ill_pad_to_bit_31 : 27;
986         MI_HRT_DCL(ill_rtime)
987         MI_HRT_DCL(ill_rtmp)
988 } ill_t;
989 #endif
990
991 #ifdef AFS_USERSPACE_IP_ADDR
992 #ifndef afs_min
993 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
994 #endif
995 /*
996  * The IP addresses and ranks are determined by afsd (in user space) and
997  * passed into the kernel at startup time through the AFSOP_ADVISEADDR
998  * system call. These are stored in the data structure 
999  * called 'afs_cb_interface'. 
1000  */
1001 afsi_SetServerIPRank(sa, addr, subnetmask)
1002    struct srvAddr *sa;         /* remote server */
1003    afs_int32 addr;                 /* one of my local addr in net order  */
1004    afs_uint32 subnetmask;         /* subnet mask of local addr in net order */
1005 {
1006    afs_uint32 myAddr, myNet, mySubnet, netMask;
1007    afs_uint32 serverAddr ; 
1008
1009    myAddr = ntohl(addr);          /* one of my IP addr in host order */
1010    serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
1011    subnetmask = ntohl(subnetmask);/* subnet mask in host order */
1012
1013    if      ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1014    else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1015    else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1016    else                          netMask = 0;
1017
1018    myNet    =  myAddr & netMask;
1019    mySubnet =  myAddr & subnetmask;
1020
1021    if ( (serverAddr & netMask ) == myNet ) {
1022       if ( (serverAddr & subnetmask ) == mySubnet) {
1023          if ( serverAddr == myAddr ) {    /* same machine */
1024            sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1025          } else {                           /* same subnet */
1026             sa->sa_iprank = afs_min(sa->sa_iprank, HI);
1027          }
1028       } else {                               /* same net */
1029          sa->sa_iprank = afs_min(sa->sa_iprank, MED);
1030       }
1031    }
1032 }
1033 #else /* AFS_USERSPACE_IP_ADDR */
1034 #if (! defined(AFS_SUN5_ENV)) && defined(USEIFADDR)
1035 void
1036 afsi_SetServerIPRank(sa, ifa)
1037     struct srvAddr *sa;
1038     struct in_ifaddr *ifa;
1039 {
1040     struct sockaddr_in *sin;
1041     int t;
1042     
1043     if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1044         if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1045             sin=IA_SIN(ifa);
1046             if ( SA2ULONG(sin) == ntohl(sa->sa_ip)) {   /* ie, ME!!!  */
1047                 sa->sa_iprank = TOPR;
1048             } else { 
1049                 t = HI + ifa->ia_ifp->if_metric; /* case #2 */
1050                 if (sa->sa_iprank > t)
1051                     sa->sa_iprank = t;
1052             }
1053         } else {
1054             t = MED + ifa->ia_ifp->if_metric;/* case #3 */
1055             if (sa->sa_iprank > t)
1056                 sa->sa_iprank = t;
1057         }
1058     }
1059 #ifdef  IFF_POINTTOPOINT
1060     /* check for case #4 -- point-to-point link */
1061     if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1062         (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1063         if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT) 
1064             t = MAXDEFRANK;
1065         else 
1066             t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1067         if (sa->sa_iprank > t)
1068             sa->sa_iprank = t;
1069     }
1070 #endif /* IFF_POINTTOPOINT */
1071 }
1072 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1073 #endif /* else AFS_USERSPACE_IP_ADDR */
1074
1075 #ifdef AFS_SGI62_ENV
1076 static int
1077 afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1078                 caddr_t arg2)
1079 {
1080    afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr*)h);
1081    return 0; /* Never match, so we enumerate everyone */
1082 }
1083 #endif /* AFS_SGI62_ENV */
1084
1085 static afs_SetServerPrefs(sa)
1086     struct srvAddr *sa;
1087 {
1088 #if     defined(AFS_USERSPACE_IP_ADDR)
1089     extern interfaceAddr afs_cb_interface;
1090     int i;
1091
1092     sa->sa_iprank = LO;
1093     for (i=0; i<afs_cb_interface.numberOfInterfaces; i++) {
1094        afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1095                                 afs_cb_interface.subnetmask[i]);
1096     }
1097 #else   /* AFS_USERSPACE_IP_ADDR */
1098 #if     defined(AFS_SUN5_ENV)
1099     extern struct ill_s *ill_g_headp;
1100     ill_t *ill;
1101     ipif_t * ipif;
1102     int subnet, subnetmask, net, netmask;
1103     long *addr = (long *) ill_g_headp;
1104     extern struct ifnet *rxi_FindIfnet();
1105
1106     if (sa) sa->sa_iprank= 0;
1107     for (ill = (struct ill_s *)*addr /*ill_g_headp*/; ill; ill = ill->ill_next ) {
1108 #ifdef AFS_SUN58_ENV
1109         /* Make sure this is an IPv4 ILL */
1110         if (ill->ill_isv6) continue;
1111 #endif
1112         for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next ) {
1113             subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1114             subnetmask = ipif->ipif_net_mask;
1115             /*
1116              * Generate the local net using the local address and 
1117              * whate we know about Class A, B and C networks.
1118              */
1119             if (IN_CLASSA(ipif->ipif_local_addr)) {
1120                 netmask = IN_CLASSA_NET;
1121             } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1122                 netmask = IN_CLASSB_NET;
1123             } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1124                 netmask = IN_CLASSC_NET;
1125             } else {
1126                 netmask = 0;
1127             }
1128             net = ipif->ipif_local_addr & netmask;
1129 #ifdef notdef 
1130             if (!s) {
1131                 if (ipif->ipif_local_addr != 0x7f000001) { /* ignore loopback */
1132                     *cnt += 1;
1133                     if (*cnt > 16) return;
1134                     *addrp++ = ipif->ipif_local_addr;
1135                 }
1136             } else
1137 #endif /* notdef */
1138               {
1139                 /* XXXXXX Do the individual ip ranking below XXXXX */
1140                 if ((sa->sa_ip & netmask) == net) {
1141                     if ((sa->sa_ip & subnetmask) == subnet) {
1142                         if (ipif->ipif_local_addr == sa->sa_ip) {  /* ie, ME!  */
1143                             sa->sa_iprank = TOPR;
1144                         } else { 
1145                             sa->sa_iprank = HI + ipif->ipif_metric; /* case #2 */
1146                         }
1147                     }  else {
1148                         sa->sa_iprank = MED + ipif->ipif_metric;   /* case #3 */
1149                     }
1150                 } else {
1151                     sa->sa_iprank = LO + ipif->ipif_metric;     /* case #4 */
1152                 }
1153                 /* check for case #5 -- point-to-point link */
1154                 if ((ipif->ipif_flags & IFF_POINTOPOINT) &&
1155                     (ipif->ipif_pp_dst_addr == sa->sa_ip )) {
1156
1157                     if (ipif->ipif_metric >= (MAXDEFRANK - MED)/PPWEIGHT) 
1158                         sa->sa_iprank = MAXDEFRANK;
1159                     else 
1160                         sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1161                 }
1162             }
1163         }
1164     }
1165 #else
1166 #ifndef USEIFADDR
1167     struct ifnet *ifn = (struct ifnet *)0;
1168     struct in_ifaddr *ifad = (struct in_ifaddr *) 0;
1169     struct sockaddr_in *sin;
1170
1171     if (!sa) {
1172 #ifdef notdef /* clean up, remove this */
1173         for (ifn = ifnet; ifn != NULL; ifn = ifn->if_next) {
1174             for (ifad = ifn->if_addrlist; ifad != NULL; ifad = ifad->ifa_next){
1175                if ((IFADDR2SA(ifad)->sa_family == AF_INET) 
1176                    && !(ifn->if_flags & IFF_LOOPBACK)) {
1177                   *cnt += 1;
1178                   if (*cnt > 16) return;
1179                   *addrp++ = ((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr;
1180                 }
1181             }
1182         }
1183 #endif /* notdef */
1184         return;
1185     }
1186     sa->sa_iprank= 0;
1187 #ifdef  ADAPT_MTU
1188     ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1189 #endif
1190     if (ifn) {  /* local, more or less */
1191 #ifdef IFF_LOOPBACK
1192       if (ifn->if_flags & IFF_LOOPBACK) {
1193         sa->sa_iprank = TOPR;
1194         goto end;
1195       }
1196 #endif /* IFF_LOOPBACK */
1197       sin = (struct sockaddr_in *) IA_SIN(ifad);
1198       if (SA2ULONG(sin) == sa->sa_ip) {
1199         sa->sa_iprank = TOPR;
1200         goto end;
1201       }
1202 #ifdef IFF_BROADCAST
1203       if (ifn->if_flags & IFF_BROADCAST) {
1204          if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1205             sa->sa_iprank = HI;
1206             goto end;
1207           }
1208        }
1209 #endif /* IFF_BROADCAST */
1210 #ifdef IFF_POINTOPOINT
1211       if (ifn->if_flags & IFF_POINTOPOINT) {
1212         if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1213           if (ifn->if_metric > 4) {
1214             sa->sa_iprank = LO;
1215             goto end;
1216           }
1217           else sa->sa_iprank = ifn->if_metric;
1218         }
1219       }
1220 #endif /* IFF_POINTOPOINT */
1221       sa->sa_iprank += MED + ifn->if_metric;      /* couldn't find anything better */
1222     }
1223         
1224 #else /* USEIFADDR */
1225     
1226     if (sa) sa->sa_iprank= LO;
1227 #ifdef AFS_SGI62_ENV
1228     (void) hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1229                      (caddr_t)sa, NULL);
1230 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1231     {
1232         struct in_ifaddr *ifa;
1233         TAILQ_FOREACH(ifa , &in_ifaddrhead, ia_link) {
1234             afsi_SetServerIPRank(sa, ifa);
1235         }
1236     }
1237 #else
1238     {
1239         extern struct in_ifaddr *in_ifaddr;
1240         struct in_ifaddr *ifa;
1241         for ( ifa = in_ifaddr; ifa; ifa = ifa->ia_next ) {
1242             afsi_SetServerIPRank(sa, ifa);
1243         }
1244     }
1245 #endif
1246
1247 #endif /* USEIFADDR */
1248 #endif /* AFS_SUN5_ENV */
1249 #endif /* else AFS_USERSPACE_IP_ADDR */
1250
1251   end: 
1252     if (sa) sa->sa_iprank += afs_randomMod15();
1253
1254 return 0;
1255 }  /* afs_SetServerPrefs */
1256 #undef TOPR
1257 #undef HI
1258 #undef MED
1259 #undef LO
1260 #undef PPWEIGHT
1261
1262 /* afs_FlushServer()
1263  * The addresses on this server struct has changed in some way and will
1264  * clean up all other structures that may reference it.
1265  * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1266  */
1267 void afs_FlushServer(srvp)
1268   struct server *srvp;
1269 {
1270   afs_int32 i;
1271   struct server  *ts, **pts;
1272
1273   /* Find any volumes residing on this server and flush their state */
1274   afs_ResetVolumes(srvp);
1275
1276   /* Flush all callbacks in the all vcaches for this specific server */
1277   afs_FlushServerCBs(srvp);
1278
1279   /* Remove all the callbacks structs */
1280   if (srvp->cbrs) {
1281      struct afs_cbr *cb, *cbnext;
1282      extern afs_lock_t afs_xvcb;
1283
1284      MObtainWriteLock(&afs_xvcb, 300);
1285      for (cb=srvp->cbrs; cb; cb=cbnext) {
1286         cbnext = cb->next;
1287         afs_FreeCBR(cb);
1288      }
1289      srvp->cbrs = (struct afs_cbr *)0;
1290      ReleaseWriteLock(&afs_xvcb);
1291   }
1292   
1293   /* If no more srvAddr structs hanging off of this server struct,
1294    * then clean it up.
1295    */
1296   if (!srvp->addr) {
1297      /* Remove the server structure from the cell list - if there */
1298      afs_RemoveCellEntry(srvp);
1299
1300      /* Remove from the afs_servers hash chain */
1301      for (i=0; i<NSERVERS; i++) {
1302         for (pts=&(afs_servers[i]), ts=*pts; ts; pts=&(ts->next), ts=*pts) {
1303            if (ts == srvp) break;
1304         }
1305         if (ts) break;
1306      }
1307      if (ts) {
1308         *pts = ts->next;                /* Found it. Remove it */
1309         afs_osi_Free(ts, sizeof(struct server)); /* Free it */
1310         afs_totalServers--;
1311      }
1312   }
1313 }
1314
1315 /* afs_RemoveSrvAddr()
1316  * This removes a SrvAddr structure from its server structure.
1317  * The srvAddr struct is not free'd because it connections may still
1318  * be open to it. It is up to the calling process to make sure it
1319  * remains connected to a server struct.
1320  * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1321  *    It is not removed from the afs_srvAddrs hash chain.
1322  */
1323 void afs_RemoveSrvAddr(sap)
1324   struct srvAddr *sap;
1325 {
1326   struct srvAddr **psa, *sa;
1327   struct server  *srv;
1328
1329   if (!sap) return;
1330   srv = sap->server;
1331
1332   /* Find the srvAddr in the server's list and remove it */
1333   for (psa=&(srv->addr), sa=*psa; sa; psa=&(sa->next_sa), sa=*psa) {
1334      if (sa == sap) break;
1335   }
1336   if (sa) {
1337      *psa = sa->next_sa;
1338      sa->next_sa = 0;
1339      sa->server  = 0;
1340
1341      /* Flush the server struct since it's IP address has changed */
1342      afs_FlushServer(srv);
1343   }
1344 }
1345
1346 /* afs_GetServer()
1347  * Return an updated and properly initialized server structure
1348  * corresponding to the server ID, cell, and port specified.
1349  * If one does not exist, then one will be created.
1350  * aserver and aport must be in NET byte order.
1351  */
1352 struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
1353                              afs_int32 acell, u_short aport,
1354                              afs_int32 locktype, afsUUID *uuidp,
1355                              afs_int32 addr_uniquifier)
1356 {
1357     struct server  *oldts=0, *ts, *newts, *orphts=0;
1358     struct srvAddr *oldsa, *sa, *newsa, *nextsa, *orphsa;
1359     u_short fsport;
1360     afs_int32 iphash, k, srvcount=0;
1361     unsigned int srvhash;
1362
1363     AFS_STATCNT(afs_GetServer);
1364
1365     ObtainSharedLock(&afs_xserver,13);
1366
1367     /* Check if the server struct exists and is up to date */
1368     if (!uuidp) {
1369        if (nservers != 1) panic("afs_GetServer: incorect count of servers");
1370        ObtainReadLock(&afs_xsrvAddr);   
1371        ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1372        ReleaseReadLock(&afs_xsrvAddr);  
1373        if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1374           /* Found a server struct that is not multihomed and has the
1375            * IP address associated with it. A correct match.
1376            */
1377           ReleaseSharedLock(&afs_xserver);
1378           return(ts);
1379        }
1380     } else {
1381        if (nservers <= 0) panic("afs_GetServer: incorrect count of servers");
1382        ts = afs_FindServer(0, aport, uuidp, locktype);
1383        if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1384           /* Found a server struct that is multihomed and same
1385            * uniqufier (same IP addrs). The above if statement is the
1386            * same as in InstallUVolumeEntry().
1387            */
1388           ReleaseSharedLock(&afs_xserver);
1389           return ts;
1390        }
1391        if (ts) oldts = ts;      /* Will reuse if same uuid */
1392     }
1393
1394     UpgradeSToWLock(&afs_xserver,36);
1395     ObtainWriteLock(&afs_xsrvAddr,116); 
1396
1397     srvcount = afs_totalServers;
1398
1399     /* Reuse/allocate a new server structure */
1400     if (oldts) {
1401        newts = oldts; 
1402     } else {
1403        newts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1404        if (!newts) panic("malloc of server struct");
1405        afs_totalServers++;
1406        memset((char *)newts, 0, sizeof(struct server));
1407
1408        /* Add the server struct to the afs_servers[] hash chain */
1409        srvhash = (uuidp ? (afs_uuid_hash(uuidp)%NSERVERS) : SHash(aserverp[0]));
1410        newts->next = afs_servers[srvhash];
1411        afs_servers[srvhash] = newts;
1412     }
1413
1414     /* Initialize the server structure */
1415     if (uuidp) { /* Multihomed */
1416        newts->sr_uuid            = *uuidp;
1417        newts->sr_addr_uniquifier = addr_uniquifier;
1418        newts->flags             |= SRVR_MULTIHOMED;
1419     }
1420     if (acell) newts->cell = afs_GetCell(acell, 0);
1421
1422     fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
1423
1424     /* For each IP address we are registering */
1425     for (k=0; k<nservers; k++) {
1426        iphash = SHash(aserverp[k]);
1427
1428        /* Check if the srvAddr structure already exists. If so, remove
1429         * it from its server structure and add it to the new one.
1430         */
1431        for (oldsa=afs_srvAddrs[iphash]; oldsa; oldsa=oldsa->next_bkt) {
1432           if ( (oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport) ) break;
1433        }
1434        if (oldsa && (oldsa->server != newts)) {
1435           afs_RemoveSrvAddr(oldsa);     /* Remove from its server struct */
1436           oldsa->next_sa = newts->addr; /* Add to the  new server struct */
1437           newts->addr    = oldsa;
1438        }
1439
1440        /* Reuse/allocate a new srvAddr structure */
1441        if (oldsa) {
1442           newsa = oldsa;
1443        } else {
1444           newsa = (struct srvAddr *) afs_osi_Alloc(sizeof(struct srvAddr));
1445           if (!newsa) panic("malloc of srvAddr struct");
1446           afs_totalSrvAddrs++;
1447           memset((char *)newsa, 0, sizeof(struct srvAddr));
1448
1449           /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1450           newsa->next_bkt = afs_srvAddrs[iphash];
1451           afs_srvAddrs[iphash] = newsa;
1452
1453           /* Hang off of the server structure  */
1454           newsa->next_sa = newts->addr;
1455           newts->addr    = newsa;
1456
1457           /* Initialize the srvAddr Structure */
1458           newsa->sa_ip     = aserverp[k];
1459           newsa->sa_portal = aport;
1460        }
1461
1462        /* Update the srvAddr Structure */
1463        newsa->server    = newts;
1464        if (newts->flags & SRVR_ISDOWN)
1465           newsa->sa_flags |= SRVADDR_ISDOWN;
1466        if (uuidp) newsa->sa_flags |=  SRVADDR_MH;
1467        else       newsa->sa_flags &= ~SRVADDR_MH;
1468
1469        /* Compute preference values and resort */
1470        if (!newsa->sa_iprank) {
1471           if (aport == fsport) { 
1472              afs_SetServerPrefs(newsa);    /* new fileserver rank */
1473           } else {
1474              newsa->sa_iprank = 10000 + afs_randomMod127(); /* new vlserver rank */
1475           }
1476        }
1477     }
1478     afs_SortOneServer(newts);     /* Sort by rank */
1479
1480     /* If we reused the server struct, remove any of its srvAddr
1481      * structs that will no longer be associated with this server.
1482      */
1483     if (oldts) {    /* reused the server struct */
1484        for (orphsa=newts->addr; orphsa; orphsa=nextsa) {
1485           nextsa = orphsa->next_sa;
1486           for (k=0; k<nservers; k++) {
1487              if (orphsa->sa_ip == aserverp[k]) break; /* belongs */
1488           }
1489           if (k < nservers) continue;                 /* belongs */
1490
1491           /* Have a srvAddr struct. Now get a server struct (if not already) */
1492           if (!orphts) {
1493              orphts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1494              if (!orphts) panic("malloc of lo server struct");
1495              memset((char *)orphts, 0, sizeof(struct server));
1496              afs_totalServers++;
1497
1498              /* Add the orphaned server to the afs_servers[] hash chain.
1499               * Its iphash does not matter since we never look up the server
1500               * in the afs_servers table by its ip address (only by uuid - 
1501               * which this has none).
1502               */
1503              iphash = SHash(aserverp[k]);
1504              orphts->next = afs_servers[iphash];
1505              afs_servers[iphash] = orphts;
1506
1507              if (acell) orphts->cell = afs_GetCell(acell, 0);
1508           }
1509
1510           /* Hang the srvAddr struct off of the server structure. The server
1511            * may have multiple srvAddrs, but it won't be marked multihomed.
1512            */
1513           afs_RemoveSrvAddr(orphsa);                 /* remove */
1514           orphsa->next_sa   = orphts->addr;          /* hang off server struct */
1515           orphts->addr      = orphsa;
1516           orphsa->server    = orphts;
1517           orphsa->sa_flags |= SRVADDR_NOUSE;         /* flag indicating not in use */
1518           orphsa->sa_flags &= ~SRVADDR_MH;           /* Not multihomed */
1519        }
1520     }
1521
1522     srvcount = afs_totalServers - srvcount;  /* # servers added and removed */
1523     if (srvcount) {
1524        struct afs_stats_SrvUpDownInfo *upDownP;
1525        /* With the introduction of this new record, we need to adjust the
1526         * proper individual & global server up/down info.
1527         */
1528        if (aport == fsport) {   /* File Server record */
1529           upDownP = (acell == 1) ?
1530             &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1531             &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1532        } else {                   /* VL Server record */
1533           upDownP = (acell == 1) ?
1534             &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1535             &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1536        } 
1537        (upDownP->numTtlRecords)    += srvcount;
1538        afs_stats_cmperf.srvRecords += srvcount;
1539        if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1540           afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1541     }
1542
1543     ReleaseWriteLock(&afs_xsrvAddr);    
1544     ReleaseWriteLock(&afs_xserver);
1545     return(newts);
1546 } /* afs_GetServer */
1547
1548 void afs_ActivateServer(sap) 
1549      struct srvAddr *sap;
1550 {
1551    osi_timeval_t currTime;              /*Filled with current time*/
1552    osi_timeval_t *currTimeP;            /*Ptr to above*/
1553    struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
1554    struct server *aserver = sap->server;
1555
1556    if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1557       /*
1558        * This server record has not yet been activated.  Go for it,
1559        * recording its ``birth''.
1560        */
1561       aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1562       currTimeP = &currTime;
1563       osi_GetuTime(currTimeP);
1564       aserver->activationTime = currTime.tv_sec;
1565       if (sap->sa_portal == AFS_FSPORT) {
1566          upDownP = (aserver->cell->cell == 1) ?
1567               &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1568                    &(afs_stats_cmperf.fs_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1569       } /*File Server record*/
1570       else {
1571          upDownP = (aserver->cell->cell == 1) ?
1572               &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_SAME_CELL]) :
1573                    &(afs_stats_cmperf.vl_UpDown[AFS_STATS_UPDOWN_IDX_DIFF_CELL]);
1574       } /*VL Server record*/
1575       if (aserver->flags & SRVR_ISDOWN)
1576            (upDownP->numDownRecords)++;
1577       else {
1578          (upDownP->numUpRecords)++;
1579          (upDownP->numRecordsNeverDown)++;
1580       }
1581    }
1582 }