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