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