2 * Copyright 2000, International Business Machines Corporation and others.
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
12 * afs_MarkServerUpOrDown
20 * afsi_SetServerIPRank
32 #include <afsconfig.h>
33 #include "../afs/param.h"
37 #include "../afs/stds.h"
38 #include "../afs/sysincludes.h" /* Standard vendor system headers */
42 #include <netinet/in.h>
45 #include "../h/hashing.h"
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>
53 #endif /* !defined(UKERNEL) */
55 #include "../afs/afsincludes.h" /* Afs-based standard headers */
56 #include "../afs/afs_stats.h" /* afs statistics */
58 #if defined(AFS_SUN56_ENV)
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]
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 */
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;
87 static struct afs_stats_SrvUpDownInfo *
88 GetUpDownStats(struct server *srv)
90 struct afs_stats_SrvUpDownInfo *upDownP;
91 u_short fsport = AFS_FSPORT;
94 fsport = srv->cell->fsport;
96 if (srv->addr->sa_portal == fsport)
97 upDownP = afs_stats_cmperf.fs_UpDown;
99 upDownP = afs_stats_cmperf.vl_UpDown;
101 if (srv->cell && afs_IsPrimaryCell(srv->cell))
102 return &upDownP[AFS_STATS_UPDOWN_IDX_SAME_CELL];
104 return &upDownP[AFS_STATS_UPDOWN_IDX_DIFF_CELL];
108 /*------------------------------------------------------------------------
109 * afs_MarkServerUpOrDown
112 * Mark the given server up or down, and track its uptime stats.
115 * a_serverP : Ptr to server record to fiddle with.
116 * a_isDown : Is the server is to be marked down?
122 * The CM server structures must be write-locked.
126 *------------------------------------------------------------------------*/
128 void afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
130 register struct server *a_serverP = sa->server;
131 register struct srvAddr *sap;
132 osi_timeval_t currTime, *currTimeP; /*Current time*/
133 afs_int32 downTime; /*Computed downtime, in seconds*/
134 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
137 * If the server record is marked the same as the new status we've
138 * been fed, then there isn't much to be done.
140 if (( a_isDown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
141 (!a_isDown && !(sa->sa_flags & SRVADDR_ISDOWN)))
145 sa->sa_flags |= SRVADDR_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 */
154 * All ips are down we treat the whole server down
156 a_serverP->flags |= SRVR_ISDOWN;
158 * If this was our time server, search for another time server
160 if (a_serverP == afs_setTimeHost)
163 sa->sa_flags &= ~SRVADDR_ISDOWN;
164 /* If any ips are up, the server is also marked up */
165 a_serverP->flags &= ~SRVR_ISDOWN;
166 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
167 if (sap->sa_flags & SRVADDR_ISDOWN) {
168 /* Not all ips are up so don't bother with the
169 * server's up/down stats */
176 * Compute the current time and which overall stats record is to be
177 * updated; we'll need them one way or another.
179 currTimeP = &currTime;
180 osi_GetuTime(currTimeP);
182 upDownP = GetUpDownStats(a_serverP);
186 * Server going up -> down; remember the beginning of this
189 a_serverP->lastDowntimeStart = currTime.tv_sec;
191 (upDownP->numDownRecords)++;
192 (upDownP->numUpRecords)--;
193 } /*Server being marked down*/
196 * Server going down -> up; remember everything about this
197 * newly-completed downtime incident.
199 downTime = currTime.tv_sec - a_serverP->lastDowntimeStart;
200 (a_serverP->numDowntimeIncidents)++;
201 a_serverP->sumOfDowntimes += downTime;
203 (upDownP->numUpRecords)++;
204 (upDownP->numDownRecords)--;
205 (upDownP->numDowntimeIncidents)++;
206 if (a_serverP->numDowntimeIncidents == 1)
207 (upDownP->numRecordsNeverDown)--;
208 upDownP->sumOfDowntimes += downTime;
209 if ((upDownP->shortestDowntime == 0) ||
210 (downTime < upDownP->shortestDowntime))
211 upDownP->shortestDowntime = downTime;
212 if ((upDownP->longestDowntime == 0) ||
213 (downTime > upDownP->longestDowntime))
214 upDownP->longestDowntime = downTime;
217 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET0)
218 (upDownP->downDurations[0])++;
220 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET1)
221 (upDownP->downDurations[1])++;
223 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET2)
224 (upDownP->downDurations[2])++;
226 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET3)
227 (upDownP->downDurations[3])++;
229 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET4)
230 (upDownP->downDurations[4])++;
232 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET5)
233 (upDownP->downDurations[5])++;
235 (upDownP->downDurations[6])++;
237 } /*Server being marked up*/
239 } /*MarkServerUpOrDown*/
242 void afs_ServerDown(struct srvAddr *sa)
244 register struct server *aserver = sa->server;
245 register struct srvAddr *sap;
247 AFS_STATCNT(ServerDown);
248 if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
250 afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
251 if (sa->sa_portal == aserver->cell->vlport)
252 print_internet_address("afs: Lost contact with volume location server ",
255 print_internet_address("afs: Lost contact with file server ", sa, "", 1);
260 /* return true if we have any callback promises from this server */
261 static int HaveCallBacksFrom(struct server *aserver)
263 register afs_int32 now;
265 register struct vcache *tvc;
267 AFS_STATCNT(HaveCallBacksFrom);
268 now = osi_Time(); /* for checking for expired callbacks */
269 for(i=0;i<VCSIZE;i++) { /* for all guys in the hash table */
270 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
272 * Check to see if this entry has an unexpired callback promise
273 * from the required host
275 if (aserver == tvc->callback && tvc->cbExpires >= now
276 && ((tvc->states & CRO) == 0))
282 } /*HaveCallBacksFrom*/
285 static void CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
287 register struct server *aserver = sa->server;
288 register struct conn *tc;
289 register afs_int32 code;
291 AFS_STATCNT(CheckVLServer);
292 /* Ping dead servers to see if they're back */
293 if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN)) || (aserver->flags & SRVR_ISGONE))
296 return; /* can't do much */
298 tc = afs_ConnByHost(aserver, aserver->cell->vlport,
299 aserver->cell->cellNum, areq, 1, SHARED_LOCK);
302 rx_SetConnDeadTime(tc->id, 3);
305 code = VL_ProbeServer(tc->id);
307 rx_SetConnDeadTime(tc->id, AFS_RXDEADTIME);
308 afs_PutConn(tc, SHARED_LOCK);
310 * If probe worked, or probe call not yet defined (for compatibility
311 * with old vlsevers), then we treat this server as running again
313 if (code == 0 || (code <= -450 && code >= -470)) {
314 if (tc->srvr == sa) {
315 afs_MarkServerUpOrDown(sa, 0);
316 print_internet_address("afs: volume location server ",
317 sa, " is back up", 2);
324 #ifndef AFS_MINCHANGE /* So that some can increase it in param.h */
325 #define AFS_MINCHANGE 2 /* min change we'll bother with */
327 #ifndef AFS_MAXCHANGEBACK
328 #define AFS_MAXCHANGEBACK 10 /* max seconds we'll set a clock back at once */
332 /*------------------------------------------------------------------------
333 * EXPORTED afs_CountServers
336 * Originally meant to count the number of servers and determining
337 * up/down info, this routine will now simply sum up all of the
338 * server record ages. All other up/down information is kept on the
348 * This routine locks afs_xserver for write for the duration.
351 * Set CM perf stats field sumOfRecordAges for all server record
353 *------------------------------------------------------------------------*/
355 void afs_CountServers(void)
357 int currIdx; /*Curr idx into srv table*/
358 struct server *currSrvP; /*Ptr to curr server record*/
359 afs_int32 currChainLen; /*Length of curr hash chain*/
360 osi_timeval_t currTime; /*Current time*/
361 osi_timeval_t *currTimeP; /*Ptr to above*/
362 afs_int32 srvRecordAge; /*Age of server record, in secs*/
363 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to current up/down
364 info being manipulated*/
367 * Write-lock the server table so we don't get any interference.
369 ObtainReadLock(&afs_xserver);
372 * Iterate over each hash index in the server table, walking down each
373 * chain and tallying what we haven't computed from the records there on
374 * the fly. First, though, initialize the tallies that will change.
376 afs_stats_cmperf.srvMaxChainLength = 0;
378 afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
379 afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
380 afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
381 memset((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
383 afs_stats_cmperf.fs_UpDown[1].sumOfRecordAges = 0;
384 afs_stats_cmperf.fs_UpDown[1].ageOfYoungestRecord = 0;
385 afs_stats_cmperf.fs_UpDown[1].ageOfOldestRecord = 0;
386 memset((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
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 memset((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
393 afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges = 0;
394 afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
395 afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord = 0;
396 memset((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
399 * Compute the current time, used to figure out server record ages.
401 currTimeP = &currTime;
402 osi_GetuTime(currTimeP);
405 * Sweep the server hash table, tallying all we need to know.
407 for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
409 for (currSrvP = afs_servers[currIdx]; currSrvP; currSrvP = currSrvP->next) {
411 * Bump the current chain length.
416 * Any further tallying for this record will only be done if it has
419 if ( (currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED) &&
420 currSrvP->addr && currSrvP->cell ) {
423 * Compute the current server record's age, then remember it
424 * in the appropriate places.
426 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
427 upDownP = GetUpDownStats(currSrvP);
428 upDownP->sumOfRecordAges += srvRecordAge;
429 if ((upDownP->ageOfYoungestRecord == 0) ||
430 (srvRecordAge < upDownP->ageOfYoungestRecord))
431 upDownP->ageOfYoungestRecord = srvRecordAge;
432 if ((upDownP->ageOfOldestRecord == 0) ||
433 (srvRecordAge > upDownP->ageOfOldestRecord))
434 upDownP->ageOfOldestRecord = srvRecordAge;
436 if (currSrvP->numDowntimeIncidents <=
437 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
438 (upDownP->downIncidents[0])++;
440 if (currSrvP->numDowntimeIncidents <=
441 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
442 (upDownP->downIncidents[1])++;
444 if (currSrvP->numDowntimeIncidents <=
445 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
446 (upDownP->downIncidents[2])++;
448 if (currSrvP->numDowntimeIncidents <=
449 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
450 (upDownP->downIncidents[3])++;
452 if (currSrvP->numDowntimeIncidents <=
453 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
454 (upDownP->downIncidents[4])++;
456 (upDownP->downIncidents[5])++;
459 } /*Current server has been active*/
460 } /*Walk this chain*/
463 * Before advancing to the next chain, remember facts about this one.
465 if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
467 * We beat out the former champion (which was initially set to 0
468 * here). Mark down the new winner, and also remember if it's an
471 afs_stats_cmperf.srvMaxChainLength = currChainLen;
472 if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
473 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
474 } /*Update chain length maximum*/
475 } /*For each hash chain*/
478 * We're done. Unlock the server table before returning to our caller.
480 ReleaseReadLock(&afs_xserver);
482 } /*afs_CountServers*/
485 /* check down servers (if adown), or running servers (if !adown) */
486 void afs_CheckServers(int adown, struct cell *acellp)
488 struct vrequest treq;
494 afs_int32 start, end, delta;
500 struct srvAddr **addrs;
503 AFS_STATCNT(afs_CheckServers);
504 if ((code = afs_InitReq(&treq, &afs_osi_cred))) return;
505 ObtainReadLock(&afs_xserver); /* Necessary? */
506 ObtainReadLock(&afs_xsrvAddr);
509 for (i=0;i<NSERVERS;i++) {
510 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
515 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
517 for (i=0;i<NSERVERS;i++) {
518 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
519 if (j >= srvAddrCount) break;
524 ReleaseReadLock(&afs_xsrvAddr);
525 ReleaseReadLock(&afs_xserver);
527 for (i=0; i<j; i++) {
533 /* See if a cell to check was specified. If it is spec'd and not
534 * this server's cell, just skip the server.
536 if (acellp && acellp != ts->cell)
539 if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
540 (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
543 /* check vlserver with special code */
544 if (sa->sa_portal == AFS_VLPORT) {
545 CheckVLServer(sa, &treq);
549 if (!ts->cell) /* not really an active server, anyway, it must */
550 continue; /* have just been added by setsprefs */
552 /* get a connection, even if host is down; bumps conn ref count */
553 tu = afs_GetUser(treq.uid, ts->cell->cellNum, SHARED_LOCK);
554 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
555 1/*force*/, 1/*create*/, SHARED_LOCK);
556 afs_PutUser(tu, SHARED_LOCK);
559 if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
560 (tc->srvr->server == afs_setTimeHost)) {
561 if (sa->sa_flags & SRVADDR_ISDOWN) {
562 rx_SetConnDeadTime(tc->id, 3);
568 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
569 start = osi_Time(); /* time the gettimeofday call */
571 code = RXAFS_GetTime(tc->id, (afs_int32 *)&tv.tv_sec, (afs_int32 *)&tv.tv_usec);
576 * If we're supposed to set the time, and the call worked
577 * quickly (same second response) and this is the host we
578 * use for the time and the time is really different, then
579 * really set the time
581 if (code == 0 && start == end && afs_setTime != 0 &&
582 (tc->srvr->server == afs_setTimeHost ||
583 /* Sync only to a server in the local cell */
584 (afs_setTimeHost == (struct server *)0 &&
585 afs_IsPrimaryCell(ts->cell)))) {
587 char msgbuf[90]; /* strlen("afs: setting clock...") + slop */
589 delta = end - tv.tv_sec; /* how many secs fast we are */
590 /* see if clock has changed enough to make it worthwhile */
591 if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
592 if (delta > AFS_MAXCHANGEBACK) {
593 /* setting clock too far back, just do it a little */
594 tv.tv_sec = end - AFS_MAXCHANGEBACK;
596 afs_osi_SetTime(&tv);
598 strcpy(msgbuf, "afs: setting clock back ");
599 if (delta > AFS_MAXCHANGEBACK) {
600 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
601 afs_strcat(msgbuf, " seconds (of ");
602 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
603 afs_strcat(msgbuf, ", via ");
604 print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
606 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
607 afs_strcat(msgbuf, " seconds (via ");
608 print_internet_address(msgbuf, sa, ").", 0);
611 strcpy(msgbuf, "afs: setting clock ahead ");
612 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
613 afs_strcat(msgbuf, " seconds (via ");
614 print_internet_address(msgbuf, sa, ").", 0);
617 afs_setTimeHost = tc->srvr->server;
620 rx_SetConnDeadTime(tc->id, AFS_RXDEADTIME);
621 if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
623 print_internet_address("afs: file server ", sa, " is back up", 2);
625 ObtainWriteLock(&afs_xserver, 244);
626 ObtainWriteLock(&afs_xsrvAddr, 245);
627 afs_MarkServerUpOrDown(sa, 0);
628 ReleaseWriteLock(&afs_xsrvAddr);
629 ReleaseWriteLock(&afs_xserver);
631 if (afs_waitForeverCount) {
632 afs_osi_Wakeup(&afs_waitForever);
638 ForceNewConnections(sa); /* multi homed clients */
643 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
644 } /* Outer loop over addrs */
646 afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
648 } /*afs_CheckServers*/
651 /* find a server structure given the host address */
652 struct server *afs_FindServer (afs_int32 aserver, ushort aport,
653 afsUUID *uuidp, afs_int32 locktype)
659 AFS_STATCNT(afs_FindServer);
661 i = afs_uuid_hash(uuidp) % NSERVERS;
662 for (ts = afs_servers[i]; ts; ts = ts->next) {
663 if ( (ts->flags & SRVR_MULTIHOMED) &&
664 (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
665 (!ts->addr || (ts->addr->sa_portal == aport)) )
670 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
671 if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
681 /* some code for creating new server structs and setting preferences follows
682 * in the next few lines...
685 #define MAXDEFRANK 60000
686 #define DEFRANK 40000
688 /* Random number generator and constants from KnuthV2 2d ed, p170 */
694 a is 0.73m should be 0.01m .. 0.99m
695 c is more or less immaterial. 1 or a is suggested.
697 NB: LOW ORDER BITS are not very random. To get small random numbers,
698 treat result as <1, with implied binary point, and multiply by
700 NB: Has to be unsigned, since shifts on signed quantities may preserve
703 /* added rxi_getaddr() to try to get as much initial randomness as
704 possible, since at least one customer reboots ALL their clients
705 simultaneously -- so osi_Time is bound to be the same on some of the
706 clients. This is probably OK, but I don't want to see too much of it.
709 #define ranstage(x) (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
711 unsigned int afs_random(void)
713 static afs_int32 state = 0;
716 AFS_STATCNT(afs_random);
721 * 0xfffffff0 was changed to (~0 << 4) since it works no matter how many
722 * bits are in a tv_usec
724 state = (t.tv_usec & (~0 << 4) ) + (rxi_getaddr() & 0xff);
725 state += (t.tv_sec & 0xff);
736 /* returns int 0..14 using the high bits of a pseudo-random number instead of
737 the low bits, as the low bits are "less random" than the high ones...
738 slight roundoff error exists, an excercise for the reader.
739 need to multiply by something with lots of ones in it, so multiply by
740 8 or 16 is right out.
742 int afs_randomMod15(void)
746 temp = afs_random() >> 4;
747 temp = (temp *15) >> 28;
752 int afs_randomMod127(void)
756 temp = afs_random() >> 7;
757 temp = (temp *127) >> 25;
762 /* afs_SortOneServer()
763 * Sort all of the srvAddrs, of a server struct, by rank from low to high.
765 void afs_SortOneServer(struct server *asp)
767 struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
770 for (rootsa=&(asp->addr); *rootsa; rootsa=&(lowsa->next_sa)) {
772 lowsa = *rootsa; /* lowest sa is the first one */
773 lowrank = lowsa->sa_iprank;
775 for (tsa=*rootsa; tsa->next_sa; tsa=tsa->next_sa) {
776 rank = tsa->next_sa->sa_iprank;
777 if (rank < lowrank) {
779 lowsa = tsa->next_sa;
780 lowrank = lowsa->sa_iprank;
783 if (lowprev) { /* found one lower, so rearrange them */
784 lowprev->next_sa = lowsa->next_sa;
785 lowsa->next_sa = *rootsa;
792 * Sort the pointer to servers by the server's rank (its lowest rank).
793 * It is assumed that the server already has its IP addrs sorted (the
794 * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
796 void afs_SortServers(struct server *aservers[], int count)
801 AFS_STATCNT(afs_SortServers);
803 for (i=0; i<count; i++) {
804 if (!aservers[i]) break;
805 for (low=i,j=i+1; j<=count; j++) {
806 if ((!aservers[j]) || (!aservers[j]->addr))
808 if ((!aservers[low]) || (!aservers[low]->addr))
810 if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
816 aservers[i] = aservers[low];
820 } /*afs_SortServers*/
822 /* afs_SetServerPrefs is rather system-dependent. It pokes around in kernel
823 data structures to determine what the local IP addresses and subnet masks
824 are in order to choose which server(s) are on the local subnet.
826 As I see it, there are several cases:
827 1. The server address is one of this host's local addresses. In this case
828 this server is to be preferred over all others.
829 2. The server is on the same subnet as one of the this host's local
830 addresses. (ie, an odd-sized subnet, not class A,B,orC)
831 3. The server is on the same net as this host (class A,B or C)
832 4. The server is on a different logical subnet or net than this host, but
833 this host is a 'metric 0 gateway' to it. Ie, two address-spaces share
835 5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
837 6. This host and the server are disjoint.
839 That is a rough order of preference. If a point-to-point link has a high
840 metric, I'm assuming that it is a very slow link, and putting it at the
841 bottom of the list (at least until RX works better over slow links). If
842 its metric is 1, I'm assuming that it's relatively fast (T1) and putting
844 It's not easy to check for case #4, so I'm ignoring it for the time being.
846 BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
847 That could be used to prefer certain servers fairly easily. Maybe some
850 NOTE: this code is very system-dependent, and very dependent on the TCP/IP
851 protocols (well, addresses that are stored in uint32s, at any rate).
854 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
855 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
857 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
858 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
863 #define PPWEIGHT 4096
868 #if defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
869 #include <inet/common.h>
870 /* IP interface structure, one per local address */
871 typedef struct ipif_s { /**/
872 struct ipif_s * ipif_next;
873 struct ill_s * ipif_ill; /* Back pointer to our ill */
874 long ipif_id; /* Logical unit number */
875 u_int ipif_mtu; /* Starts at ipif_ill->ill_max_frag */
876 afs_int32 ipif_local_addr; /* Local IP address for this if. */
877 afs_int32 ipif_net_mask; /* Net mask for this interface. */
878 afs_int32 ipif_broadcast_addr; /* Broadcast addr for this interface. */
879 afs_int32 ipif_pp_dst_addr; /* Point-to-point dest address. */
880 u_int ipif_flags; /* Interface flags. */
881 u_int ipif_metric; /* BSD if metric, for compatibility. */
882 u_int ipif_ire_type; /* LOCAL or LOOPBACK */
883 mblk_t * ipif_arp_down_mp; /* Allocated at time arp comes up to
884 * prevent awkward out of mem condition
887 mblk_t * ipif_saved_ire_mp; /* Allocated for each extra IRE_SUBNET/
888 * RESOLVER on this interface so that
889 * they can survive ifconfig down.
892 * The packet counts in the ipif contain the sum of the
893 * packet counts in dead IREs that were affiliated with
896 u_long ipif_fo_pkt_count; /* Forwarded thru our dead IREs */
897 u_long ipif_ib_pkt_count; /* Inbound packets for our dead IREs */
898 u_long ipif_ob_pkt_count; /* Outbound packets to our dead IREs */
900 ipif_multicast_up : 1, /* We have joined the allhosts group */
904 typedef struct ipfb_s { /**/
905 struct ipf_s * ipfb_ipf; /* List of ... */
906 kmutex_t ipfb_lock; /* Protect all ipf in list */
909 typedef struct ilm_s { /**/
912 u_int ilm_timer; /* IGMP */
913 struct ipif_s * ilm_ipif; /* Back pointer to ipif */
914 struct ilm_s * ilm_next; /* Linked list for each ill */
917 typedef struct ill_s { /**/
918 struct ill_s * ill_next; /* Chained in at ill_g_head. */
919 struct ill_s ** ill_ptpn; /* Pointer to previous next. */
920 queue_t * ill_rq; /* Read queue. */
921 queue_t * ill_wq; /* Write queue. */
923 int ill_error; /* Error value sent up by device. */
925 ipif_t * ill_ipif; /* Interface chain for this ILL. */
926 u_int ill_ipif_up_count; /* Number of IPIFs currently up. */
927 u_int ill_max_frag; /* Max IDU. */
928 char * ill_name; /* Our name. */
929 u_int ill_name_length; /* Name length, incl. terminator. */
930 u_int ill_subnet_type; /* IRE_RESOLVER or IRE_SUBNET. */
931 u_int ill_ppa; /* Physical Point of Attachment num. */
933 int ill_sap_length; /* Including sign (for position) */
934 u_int ill_phys_addr_length; /* Excluding the sap. */
935 mblk_t * ill_frag_timer_mp; /* Reassembly timer state. */
936 ipfb_t * ill_frag_hash_tbl; /* Fragment hash list head. */
938 queue_t * ill_bind_pending_q; /* Queue waiting for DL_BIND_ACK. */
939 ipif_t * ill_ipif_pending; /* IPIF waiting for DL_BIND_ACK. */
941 /* ill_hdr_length and ill_hdr_mp will be non zero if
942 * the underlying device supports the M_DATA fastpath
946 ilm_t * ill_ilm; /* Multicast mebership for lower ill */
948 /* All non-nil cells between 'ill_first_mp_to_free' and
949 * 'ill_last_mp_to_free' are freed in ill_delete.
951 #define ill_first_mp_to_free ill_hdr_mp
952 mblk_t * ill_hdr_mp; /* Contains fastpath template */
953 mblk_t * ill_bcast_mp; /* DLPI header for broadcasts. */
954 mblk_t * ill_bind_pending; /* T_BIND_REQ awaiting completion. */
955 mblk_t * ill_resolver_mp; /* Resolver template. */
956 mblk_t * ill_attach_mp;
957 mblk_t * ill_bind_mp;
958 mblk_t * ill_unbind_mp;
959 mblk_t * ill_detach_mp;
960 #define ill_last_mp_to_free ill_detach_mp
963 ill_frag_timer_running : 1,
964 ill_needs_attach : 1,
967 ill_unbind_pending : 1,
969 ill_pad_to_bit_31 : 27;
970 MI_HRT_DCL(ill_rtime)
975 #ifdef AFS_USERSPACE_IP_ADDR
977 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
980 * The IP addresses and ranks are determined by afsd (in user space) and
981 * passed into the kernel at startup time through the AFSOP_ADVISEADDR
982 * system call. These are stored in the data structure
983 * called 'afs_cb_interface'.
985 * struct srvAddr *sa; remote server
986 * afs_int32 addr; one of my local addr in net order
987 * afs_uint32 subnetmask; subnet mask of local addr in net order
990 int afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr, afs_uint32 subnetmask)
992 afs_uint32 myAddr, myNet, mySubnet, netMask;
993 afs_uint32 serverAddr ;
995 myAddr = ntohl(addr); /* one of my IP addr in host order */
996 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
997 subnetmask = ntohl(subnetmask);/* subnet mask in host order */
999 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1000 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1001 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1004 myNet = myAddr & netMask;
1005 mySubnet = myAddr & subnetmask;
1007 if ( (serverAddr & netMask ) == myNet ) {
1008 if ( (serverAddr & subnetmask ) == mySubnet) {
1009 if ( serverAddr == myAddr ) { /* same machine */
1010 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1011 } else { /* same subnet */
1012 sa->sa_iprank = afs_min(sa->sa_iprank, HI);
1014 } else { /* same net */
1015 sa->sa_iprank = afs_min(sa->sa_iprank, MED);
1019 #else /* AFS_USERSPACE_IP_ADDR */
1020 #if (! defined(AFS_SUN5_ENV)) && !defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1021 void afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
1023 struct sockaddr_in *sin;
1026 if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1027 if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1029 if ( SA2ULONG(sin) == ntohl(sa->sa_ip)) { /* ie, ME!!! */
1030 sa->sa_iprank = TOPR;
1032 t = HI + ifa->ia_ifp->if_metric; /* case #2 */
1033 if (sa->sa_iprank > t)
1037 t = MED + ifa->ia_ifp->if_metric;/* case #3 */
1038 if (sa->sa_iprank > t)
1042 #ifdef IFF_POINTTOPOINT
1043 /* check for case #4 -- point-to-point link */
1044 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1045 (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1046 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1049 t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1050 if (sa->sa_iprank > t)
1053 #endif /* IFF_POINTTOPOINT */
1055 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1056 #if defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1058 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
1061 afsi_SetServerIPRank(sa, ifa)
1065 struct sockaddr_in *sin;
1068 afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
1069 afs_uint32 serverAddr ;
1071 if (ifa->ifa_addr->sa_family != AF_INET)
1073 sin=(struct sockaddr_in *)ifa->ifa_addr;
1074 myAddr = ntohl(sin->sin_addr.s_addr); /* one of my IP addr in host order */
1075 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
1076 sin=(struct sockaddr_in *)ifa->ifa_netmask;
1077 subnetmask = ntohl(sin->sin_addr.s_addr);/* subnet mask in host order */
1078 sin=(struct sockaddr_in *)ifa->ifa_dstaddr;
1080 myDstaddr=sin->sin_addr.s_addr;
1082 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1083 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1084 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1087 myNet = myAddr & netMask;
1088 mySubnet = myAddr & subnetmask;
1090 if ( (serverAddr & netMask ) == myNet ) {
1091 if ( (serverAddr & subnetmask ) == mySubnet) {
1092 if ( serverAddr == myAddr ) { /* same machine */
1093 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1094 } else { /* same subnet */
1095 sa->sa_iprank = afs_min(sa->sa_iprank, HI + ifa->ifa_metric);
1097 } else { /* same net */
1098 sa->sa_iprank = afs_min(sa->sa_iprank, MED + ifa->ifa_metric);
1101 #ifdef IFF_POINTTOPOINT
1102 /* check for case #4 -- point-to-point link */
1103 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1104 (myDstaddr == serverAddr))) {
1105 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1108 t = MED + (PPWEIGHT << ifa->->ifa_metric);
1109 if (sa->sa_iprank > t)
1112 #endif /* IFF_POINTTOPOINT */
1114 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1115 #endif /* else AFS_USERSPACE_IP_ADDR */
1117 #ifdef AFS_SGI62_ENV
1119 afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1122 afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr*)h);
1123 return 0; /* Never match, so we enumerate everyone */
1125 #endif /* AFS_SGI62_ENV */
1127 static int afs_SetServerPrefs(struct srvAddr *sa)
1129 #if defined(AFS_USERSPACE_IP_ADDR)
1133 for (i=0; i<afs_cb_interface.numberOfInterfaces; i++) {
1134 afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1135 afs_cb_interface.subnetmask[i]);
1137 #else /* AFS_USERSPACE_IP_ADDR */
1138 #if defined(AFS_SUN5_ENV)
1139 extern struct ill_s *ill_g_headp;
1142 int subnet, subnetmask, net, netmask;
1143 long *addr = (long *) ill_g_headp;
1145 if (sa) sa->sa_iprank= 0;
1146 for (ill = (struct ill_s *)*addr /*ill_g_headp*/; ill; ill = ill->ill_next ) {
1147 #ifdef AFS_SUN58_ENV
1148 /* Make sure this is an IPv4 ILL */
1149 if (ill->ill_isv6) continue;
1151 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next ) {
1152 subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1153 subnetmask = ipif->ipif_net_mask;
1155 * Generate the local net using the local address and
1156 * whate we know about Class A, B and C networks.
1158 if (IN_CLASSA(ipif->ipif_local_addr)) {
1159 netmask = IN_CLASSA_NET;
1160 } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1161 netmask = IN_CLASSB_NET;
1162 } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1163 netmask = IN_CLASSC_NET;
1167 net = ipif->ipif_local_addr & netmask;
1170 if (ipif->ipif_local_addr != 0x7f000001) { /* ignore loopback */
1172 if (*cnt > 16) return;
1173 *addrp++ = ipif->ipif_local_addr;
1178 /* XXXXXX Do the individual ip ranking below XXXXX */
1179 if ((sa->sa_ip & netmask) == net) {
1180 if ((sa->sa_ip & subnetmask) == subnet) {
1181 if (ipif->ipif_local_addr == sa->sa_ip) { /* ie, ME! */
1182 sa->sa_iprank = TOPR;
1184 sa->sa_iprank = HI + ipif->ipif_metric; /* case #2 */
1187 sa->sa_iprank = MED + ipif->ipif_metric; /* case #3 */
1190 sa->sa_iprank = LO + ipif->ipif_metric; /* case #4 */
1192 /* check for case #5 -- point-to-point link */
1193 if ((ipif->ipif_flags & IFF_POINTOPOINT) &&
1194 (ipif->ipif_pp_dst_addr == sa->sa_ip )) {
1196 if (ipif->ipif_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1197 sa->sa_iprank = MAXDEFRANK;
1199 sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1206 struct ifnet *ifn = NULL;
1207 struct in_ifaddr *ifad = (struct in_ifaddr *) 0;
1208 struct sockaddr_in *sin;
1211 #ifdef notdef /* clean up, remove this */
1212 for (ifn = ifnet; ifn != NULL; ifn = ifn->if_next) {
1213 for (ifad = ifn->if_addrlist; ifad != NULL; ifad = ifad->ifa_next){
1214 if ((IFADDR2SA(ifad)->sa_family == AF_INET)
1215 && !(ifn->if_flags & IFF_LOOPBACK)) {
1217 if (*cnt > 16) return;
1218 *addrp++ = ((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr;
1227 ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1229 if (ifn) { /* local, more or less */
1231 if (ifn->if_flags & IFF_LOOPBACK) {
1232 sa->sa_iprank = TOPR;
1235 #endif /* IFF_LOOPBACK */
1236 sin = (struct sockaddr_in *) IA_SIN(ifad);
1237 if (SA2ULONG(sin) == sa->sa_ip) {
1238 sa->sa_iprank = TOPR;
1241 #ifdef IFF_BROADCAST
1242 if (ifn->if_flags & IFF_BROADCAST) {
1243 if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1248 #endif /* IFF_BROADCAST */
1249 #ifdef IFF_POINTOPOINT
1250 if (ifn->if_flags & IFF_POINTOPOINT) {
1251 if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1252 if (ifn->if_metric > 4) {
1256 else sa->sa_iprank = ifn->if_metric;
1259 #endif /* IFF_POINTOPOINT */
1260 sa->sa_iprank += MED + ifn->if_metric; /* couldn't find anything better */
1263 #else /* USEIFADDR */
1265 if (sa) sa->sa_iprank= LO;
1266 #ifdef AFS_SGI62_ENV
1267 (void) hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1269 #elif defined(AFS_DARWIN60_ENV)
1273 TAILQ_FOREACH(ifn , &ifnet, if_link) {
1274 TAILQ_FOREACH(ifa , &ifn->if_addrhead, ifa_link) {
1275 afsi_SetServerIPRank(sa, ifa);
1279 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1281 struct in_ifaddr *ifa;
1282 TAILQ_FOREACH(ifa , &in_ifaddrhead, ia_link) {
1283 afsi_SetServerIPRank(sa, ifa);
1288 struct in_ifaddr *ifa;
1289 for ( ifa = in_ifaddr; ifa; ifa = ifa->ia_next ) {
1290 afsi_SetServerIPRank(sa, ifa);
1295 #endif /* USEIFADDR */
1296 #endif /* AFS_SUN5_ENV */
1297 #endif /* else AFS_USERSPACE_IP_ADDR */
1300 if (sa) sa->sa_iprank += afs_randomMod15();
1303 } /* afs_SetServerPrefs */
1310 /* afs_FlushServer()
1311 * The addresses on this server struct has changed in some way and will
1312 * clean up all other structures that may reference it.
1313 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1315 void afs_FlushServer(struct server *srvp)
1318 struct server *ts, **pts;
1320 /* Find any volumes residing on this server and flush their state */
1321 afs_ResetVolumes(srvp);
1323 /* Flush all callbacks in the all vcaches for this specific server */
1324 afs_FlushServerCBs(srvp);
1326 /* Remove all the callbacks structs */
1328 struct afs_cbr *cb, *cbnext;
1330 MObtainWriteLock(&afs_xvcb, 300);
1331 for (cb=srvp->cbrs; cb; cb=cbnext) {
1335 srvp->cbrs = (struct afs_cbr *)0;
1336 ReleaseWriteLock(&afs_xvcb);
1339 /* If no more srvAddr structs hanging off of this server struct,
1343 /* Remove the server structure from the cell list - if there */
1344 afs_RemoveCellEntry(srvp);
1346 /* Remove from the afs_servers hash chain */
1347 for (i=0; i<NSERVERS; i++) {
1348 for (pts=&(afs_servers[i]), ts=*pts; ts; pts=&(ts->next), ts=*pts) {
1349 if (ts == srvp) break;
1354 *pts = ts->next; /* Found it. Remove it */
1355 afs_osi_Free(ts, sizeof(struct server)); /* Free it */
1361 /* afs_RemoveSrvAddr()
1362 * This removes a SrvAddr structure from its server structure.
1363 * The srvAddr struct is not free'd because it connections may still
1364 * be open to it. It is up to the calling process to make sure it
1365 * remains connected to a server struct.
1366 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1367 * It is not removed from the afs_srvAddrs hash chain.
1369 void afs_RemoveSrvAddr(struct srvAddr *sap)
1371 struct srvAddr **psa, *sa;
1377 /* Find the srvAddr in the server's list and remove it */
1378 for (psa=&(srv->addr), sa=*psa; sa; psa=&(sa->next_sa), sa=*psa) {
1379 if (sa == sap) break;
1386 /* Flush the server struct since it's IP address has changed */
1387 afs_FlushServer(srv);
1392 * Return an updated and properly initialized server structure
1393 * corresponding to the server ID, cell, and port specified.
1394 * If one does not exist, then one will be created.
1395 * aserver and aport must be in NET byte order.
1397 struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
1398 afs_int32 acell, u_short aport,
1399 afs_int32 locktype, afsUUID *uuidp,
1400 afs_int32 addr_uniquifier)
1402 struct server *oldts=0, *ts, *newts, *orphts=0;
1403 struct srvAddr *oldsa, *sa, *newsa, *nextsa, *orphsa;
1405 afs_int32 iphash, k, srvcount=0;
1406 unsigned int srvhash;
1408 AFS_STATCNT(afs_GetServer);
1410 ObtainSharedLock(&afs_xserver,13);
1412 /* Check if the server struct exists and is up to date */
1414 if (nservers != 1) panic("afs_GetServer: incorect count of servers");
1415 ObtainReadLock(&afs_xsrvAddr);
1416 ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1417 ReleaseReadLock(&afs_xsrvAddr);
1418 if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1419 /* Found a server struct that is not multihomed and has the
1420 * IP address associated with it. A correct match.
1422 ReleaseSharedLock(&afs_xserver);
1426 if (nservers <= 0) panic("afs_GetServer: incorrect count of servers");
1427 ts = afs_FindServer(0, aport, uuidp, locktype);
1428 if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1429 /* Found a server struct that is multihomed and same
1430 * uniqufier (same IP addrs). The above if statement is the
1431 * same as in InstallUVolumeEntry().
1433 ReleaseSharedLock(&afs_xserver);
1436 if (ts) oldts = ts; /* Will reuse if same uuid */
1439 UpgradeSToWLock(&afs_xserver,36);
1440 ObtainWriteLock(&afs_xsrvAddr,116);
1442 srvcount = afs_totalServers;
1444 /* Reuse/allocate a new server structure */
1448 newts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1449 if (!newts) panic("malloc of server struct");
1451 memset((char *)newts, 0, sizeof(struct server));
1453 /* Add the server struct to the afs_servers[] hash chain */
1454 srvhash = (uuidp ? (afs_uuid_hash(uuidp)%NSERVERS) : SHash(aserverp[0]));
1455 newts->next = afs_servers[srvhash];
1456 afs_servers[srvhash] = newts;
1459 /* Initialize the server structure */
1460 if (uuidp) { /* Multihomed */
1461 newts->sr_uuid = *uuidp;
1462 newts->sr_addr_uniquifier = addr_uniquifier;
1463 newts->flags |= SRVR_MULTIHOMED;
1465 if (acell) newts->cell = afs_GetCell(acell, 0);
1467 fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
1469 /* For each IP address we are registering */
1470 for (k=0; k<nservers; k++) {
1471 iphash = SHash(aserverp[k]);
1473 /* Check if the srvAddr structure already exists. If so, remove
1474 * it from its server structure and add it to the new one.
1476 for (oldsa=afs_srvAddrs[iphash]; oldsa; oldsa=oldsa->next_bkt) {
1477 if ( (oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport) ) break;
1479 if (oldsa && (oldsa->server != newts)) {
1480 afs_RemoveSrvAddr(oldsa); /* Remove from its server struct */
1481 oldsa->next_sa = newts->addr; /* Add to the new server struct */
1482 newts->addr = oldsa;
1485 /* Reuse/allocate a new srvAddr structure */
1489 newsa = (struct srvAddr *) afs_osi_Alloc(sizeof(struct srvAddr));
1490 if (!newsa) panic("malloc of srvAddr struct");
1491 afs_totalSrvAddrs++;
1492 memset((char *)newsa, 0, sizeof(struct srvAddr));
1494 /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1495 newsa->next_bkt = afs_srvAddrs[iphash];
1496 afs_srvAddrs[iphash] = newsa;
1498 /* Hang off of the server structure */
1499 newsa->next_sa = newts->addr;
1500 newts->addr = newsa;
1502 /* Initialize the srvAddr Structure */
1503 newsa->sa_ip = aserverp[k];
1504 newsa->sa_portal = aport;
1507 /* Update the srvAddr Structure */
1508 newsa->server = newts;
1509 if (newts->flags & SRVR_ISDOWN)
1510 newsa->sa_flags |= SRVADDR_ISDOWN;
1511 if (uuidp) newsa->sa_flags |= SRVADDR_MH;
1512 else newsa->sa_flags &= ~SRVADDR_MH;
1514 /* Compute preference values and resort */
1515 if (!newsa->sa_iprank) {
1516 if (aport == fsport) {
1517 afs_SetServerPrefs(newsa); /* new fileserver rank */
1519 newsa->sa_iprank = 10000 + afs_randomMod127(); /* new vlserver rank */
1523 afs_SortOneServer(newts); /* Sort by rank */
1525 /* If we reused the server struct, remove any of its srvAddr
1526 * structs that will no longer be associated with this server.
1528 if (oldts) { /* reused the server struct */
1529 for (orphsa=newts->addr; orphsa; orphsa=nextsa) {
1530 nextsa = orphsa->next_sa;
1531 for (k=0; k<nservers; k++) {
1532 if (orphsa->sa_ip == aserverp[k]) break; /* belongs */
1534 if (k < nservers) continue; /* belongs */
1536 /* Have a srvAddr struct. Now get a server struct (if not already) */
1538 orphts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1539 if (!orphts) panic("malloc of lo server struct");
1540 memset((char *)orphts, 0, sizeof(struct server));
1543 /* Add the orphaned server to the afs_servers[] hash chain.
1544 * Its iphash does not matter since we never look up the server
1545 * in the afs_servers table by its ip address (only by uuid -
1546 * which this has none).
1548 iphash = SHash(aserverp[k]);
1549 orphts->next = afs_servers[iphash];
1550 afs_servers[iphash] = orphts;
1552 if (acell) orphts->cell = afs_GetCell(acell, 0);
1555 /* Hang the srvAddr struct off of the server structure. The server
1556 * may have multiple srvAddrs, but it won't be marked multihomed.
1558 afs_RemoveSrvAddr(orphsa); /* remove */
1559 orphsa->next_sa = orphts->addr; /* hang off server struct */
1560 orphts->addr = orphsa;
1561 orphsa->server = orphts;
1562 orphsa->sa_flags |= SRVADDR_NOUSE; /* flag indicating not in use */
1563 orphsa->sa_flags &= ~SRVADDR_MH; /* Not multihomed */
1567 srvcount = afs_totalServers - srvcount; /* # servers added and removed */
1569 struct afs_stats_SrvUpDownInfo *upDownP;
1570 /* With the introduction of this new record, we need to adjust the
1571 * proper individual & global server up/down info.
1573 upDownP = GetUpDownStats(newts);
1574 upDownP->numTtlRecords += srvcount;
1575 afs_stats_cmperf.srvRecords += srvcount;
1576 if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1577 afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1580 ReleaseWriteLock(&afs_xsrvAddr);
1581 ReleaseWriteLock(&afs_xserver);
1583 } /* afs_GetServer */
1585 void afs_ActivateServer(struct srvAddr *sap)
1587 osi_timeval_t currTime; /*Filled with current time*/
1588 osi_timeval_t *currTimeP; /*Ptr to above*/
1589 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
1590 struct server *aserver = sap->server;
1592 if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1594 * This server record has not yet been activated. Go for it,
1595 * recording its ``birth''.
1597 aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1598 currTimeP = &currTime;
1599 osi_GetuTime(currTimeP);
1600 aserver->activationTime = currTime.tv_sec;
1601 upDownP = GetUpDownStats(aserver);
1602 if (aserver->flags & SRVR_ISDOWN) {
1603 upDownP->numDownRecords++;
1605 upDownP->numUpRecords++;
1606 upDownP->numRecordsNeverDown++;