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