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