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"
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 "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;
246 AFS_STATCNT(ServerDown);
247 if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
249 afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
250 if (sa->sa_portal == aserver->cell->vlport)
251 print_internet_address("afs: Lost contact with volume location server ",
254 print_internet_address("afs: Lost contact with file server ", sa, "", 1);
259 /* return true if we have any callback promises from this server */
260 static int HaveCallBacksFrom(struct server *aserver)
262 register afs_int32 now;
264 register struct vcache *tvc;
266 AFS_STATCNT(HaveCallBacksFrom);
267 now = osi_Time(); /* for checking for expired callbacks */
268 for(i=0;i<VCSIZE;i++) { /* for all guys in the hash table */
269 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
271 * Check to see if this entry has an unexpired callback promise
272 * from the required host
274 if (aserver == tvc->callback && tvc->cbExpires >= now
275 && ((tvc->states & CRO) == 0))
281 } /*HaveCallBacksFrom*/
284 static void CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
286 register struct server *aserver = sa->server;
287 register struct conn *tc;
288 register afs_int32 code;
290 AFS_STATCNT(CheckVLServer);
291 /* Ping dead servers to see if they're back */
292 if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN)) || (aserver->flags & SRVR_ISGONE))
295 return; /* can't do much */
297 tc = afs_ConnByHost(aserver, aserver->cell->vlport,
298 aserver->cell->cellNum, areq, 1, SHARED_LOCK);
301 rx_SetConnDeadTime(tc->id, 3);
304 code = VL_ProbeServer(tc->id);
306 rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
307 afs_PutConn(tc, SHARED_LOCK);
309 * If probe worked, or probe call not yet defined (for compatibility
310 * with old vlsevers), then we treat this server as running again
312 if (code == 0 || (code <= -450 && code >= -470)) {
313 if (tc->srvr == sa) {
314 afs_MarkServerUpOrDown(sa, 0);
315 print_internet_address("afs: volume location server ",
316 sa, " is back up", 2);
323 #ifndef AFS_MINCHANGE /* So that some can increase it in param.h */
324 #define AFS_MINCHANGE 2 /* min change we'll bother with */
326 #ifndef AFS_MAXCHANGEBACK
327 #define AFS_MAXCHANGEBACK 10 /* max seconds we'll set a clock back at once */
331 /*------------------------------------------------------------------------
332 * EXPORTED afs_CountServers
335 * Originally meant to count the number of servers and determining
336 * up/down info, this routine will now simply sum up all of the
337 * server record ages. All other up/down information is kept on the
347 * This routine locks afs_xserver for write for the duration.
350 * Set CM perf stats field sumOfRecordAges for all server record
352 *------------------------------------------------------------------------*/
354 void afs_CountServers(void)
356 int currIdx; /*Curr idx into srv table*/
357 struct server *currSrvP; /*Ptr to curr server record*/
358 afs_int32 currChainLen; /*Length of curr hash chain*/
359 osi_timeval_t currTime; /*Current time*/
360 osi_timeval_t *currTimeP; /*Ptr to above*/
361 afs_int32 srvRecordAge; /*Age of server record, in secs*/
362 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to current up/down
363 info being manipulated*/
366 * Write-lock the server table so we don't get any interference.
368 ObtainReadLock(&afs_xserver);
371 * Iterate over each hash index in the server table, walking down each
372 * chain and tallying what we haven't computed from the records there on
373 * the fly. First, though, initialize the tallies that will change.
375 afs_stats_cmperf.srvMaxChainLength = 0;
377 afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
378 afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
379 afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
380 memset((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
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 memset((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
387 afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges = 0;
388 afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
389 afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord = 0;
390 memset((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
392 afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges = 0;
393 afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
394 afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord = 0;
395 memset((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
398 * Compute the current time, used to figure out server record ages.
400 currTimeP = &currTime;
401 osi_GetuTime(currTimeP);
404 * Sweep the server hash table, tallying all we need to know.
406 for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
408 for (currSrvP = afs_servers[currIdx]; currSrvP; currSrvP = currSrvP->next) {
410 * Bump the current chain length.
415 * Any further tallying for this record will only be done if it has
418 if ( (currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED) &&
419 currSrvP->addr && currSrvP->cell ) {
422 * Compute the current server record's age, then remember it
423 * in the appropriate places.
425 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
426 upDownP = GetUpDownStats(currSrvP);
427 upDownP->sumOfRecordAges += srvRecordAge;
428 if ((upDownP->ageOfYoungestRecord == 0) ||
429 (srvRecordAge < upDownP->ageOfYoungestRecord))
430 upDownP->ageOfYoungestRecord = srvRecordAge;
431 if ((upDownP->ageOfOldestRecord == 0) ||
432 (srvRecordAge > upDownP->ageOfOldestRecord))
433 upDownP->ageOfOldestRecord = srvRecordAge;
435 if (currSrvP->numDowntimeIncidents <=
436 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
437 (upDownP->downIncidents[0])++;
439 if (currSrvP->numDowntimeIncidents <=
440 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
441 (upDownP->downIncidents[1])++;
443 if (currSrvP->numDowntimeIncidents <=
444 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
445 (upDownP->downIncidents[2])++;
447 if (currSrvP->numDowntimeIncidents <=
448 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
449 (upDownP->downIncidents[3])++;
451 if (currSrvP->numDowntimeIncidents <=
452 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
453 (upDownP->downIncidents[4])++;
455 (upDownP->downIncidents[5])++;
458 } /*Current server has been active*/
459 } /*Walk this chain*/
462 * Before advancing to the next chain, remember facts about this one.
464 if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
466 * We beat out the former champion (which was initially set to 0
467 * here). Mark down the new winner, and also remember if it's an
470 afs_stats_cmperf.srvMaxChainLength = currChainLen;
471 if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
472 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
473 } /*Update chain length maximum*/
474 } /*For each hash chain*/
477 * We're done. Unlock the server table before returning to our caller.
479 ReleaseReadLock(&afs_xserver);
481 } /*afs_CountServers*/
484 /* check down servers (if adown), or running servers (if !adown) */
485 void afs_CheckServers(int adown, struct cell *acellp)
487 struct vrequest treq;
493 afs_int32 start, end, delta;
499 struct srvAddr **addrs;
502 AFS_STATCNT(afs_CheckServers);
503 if ((code = afs_InitReq(&treq, &afs_osi_cred))) return;
504 ObtainReadLock(&afs_xserver); /* Necessary? */
505 ObtainReadLock(&afs_xsrvAddr);
508 for (i=0;i<NSERVERS;i++) {
509 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
514 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
516 for (i=0;i<NSERVERS;i++) {
517 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
518 if (j >= srvAddrCount) break;
523 ReleaseReadLock(&afs_xsrvAddr);
524 ReleaseReadLock(&afs_xserver);
526 for (i=0; i<j; i++) {
532 /* See if a cell to check was specified. If it is spec'd and not
533 * this server's cell, just skip the server.
535 if (acellp && acellp != ts->cell)
538 if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
539 (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
542 /* check vlserver with special code */
543 if (sa->sa_portal == AFS_VLPORT) {
544 CheckVLServer(sa, &treq);
548 if (!ts->cell) /* not really an active server, anyway, it must */
549 continue; /* have just been added by setsprefs */
551 /* get a connection, even if host is down; bumps conn ref count */
552 tu = afs_GetUser(treq.uid, ts->cell->cellNum, SHARED_LOCK);
553 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
554 1/*force*/, 1/*create*/, SHARED_LOCK);
555 afs_PutUser(tu, SHARED_LOCK);
558 if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
559 (tc->srvr->server == afs_setTimeHost)) {
560 if (sa->sa_flags & SRVADDR_ISDOWN) {
561 rx_SetConnDeadTime(tc->id, 3);
567 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
568 start = osi_Time(); /* time the gettimeofday call */
570 code = RXAFS_GetTime(tc->id, (afs_int32 *)&tv.tv_sec, (afs_int32 *)&tv.tv_usec);
575 * If we're supposed to set the time, and the call worked
576 * quickly (same second response) and this is the host we
577 * use for the time and the time is really different, then
578 * really set the time
580 if (code == 0 && start == end && afs_setTime != 0 &&
581 (tc->srvr->server == afs_setTimeHost ||
582 /* Sync only to a server in the local cell */
583 (afs_setTimeHost == (struct server *)0 &&
584 afs_IsPrimaryCell(ts->cell)))) {
586 char msgbuf[90]; /* strlen("afs: setting clock...") + slop */
588 delta = end - tv.tv_sec; /* how many secs fast we are */
589 /* see if clock has changed enough to make it worthwhile */
590 if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
591 if (delta > AFS_MAXCHANGEBACK) {
592 /* setting clock too far back, just do it a little */
593 tv.tv_sec = end - AFS_MAXCHANGEBACK;
595 afs_osi_SetTime(&tv);
597 strcpy(msgbuf, "afs: setting clock back ");
598 if (delta > AFS_MAXCHANGEBACK) {
599 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
600 afs_strcat(msgbuf, " seconds (of ");
601 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
602 afs_strcat(msgbuf, ", via ");
603 print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
605 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
606 afs_strcat(msgbuf, " seconds (via ");
607 print_internet_address(msgbuf, sa, ").", 0);
610 strcpy(msgbuf, "afs: setting clock ahead ");
611 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
612 afs_strcat(msgbuf, " seconds (via ");
613 print_internet_address(msgbuf, sa, ").", 0);
616 afs_setTimeHost = tc->srvr->server;
619 rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
620 if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
622 print_internet_address("afs: file server ", sa, " is back up", 2);
624 ObtainWriteLock(&afs_xserver, 244);
625 ObtainWriteLock(&afs_xsrvAddr, 245);
626 afs_MarkServerUpOrDown(sa, 0);
627 ReleaseWriteLock(&afs_xsrvAddr);
628 ReleaseWriteLock(&afs_xserver);
630 if (afs_waitForeverCount) {
631 afs_osi_Wakeup(&afs_waitForever);
637 ForceNewConnections(sa); /* multi homed clients */
642 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
643 } /* Outer loop over addrs */
645 afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
647 } /*afs_CheckServers*/
650 /* find a server structure given the host address */
651 struct server *afs_FindServer (afs_int32 aserver, ushort aport,
652 afsUUID *uuidp, afs_int32 locktype)
658 AFS_STATCNT(afs_FindServer);
660 i = afs_uuid_hash(uuidp) % NSERVERS;
661 for (ts = afs_servers[i]; ts; ts = ts->next) {
662 if ( (ts->flags & SRVR_MULTIHOMED) &&
663 (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
664 (!ts->addr || (ts->addr->sa_portal == aport)) )
669 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
670 if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
680 /* some code for creating new server structs and setting preferences follows
681 * in the next few lines...
684 #define MAXDEFRANK 60000
685 #define DEFRANK 40000
687 /* Random number generator and constants from KnuthV2 2d ed, p170 */
693 a is 0.73m should be 0.01m .. 0.99m
694 c is more or less immaterial. 1 or a is suggested.
696 NB: LOW ORDER BITS are not very random. To get small random numbers,
697 treat result as <1, with implied binary point, and multiply by
699 NB: Has to be unsigned, since shifts on signed quantities may preserve
702 /* added rxi_getaddr() to try to get as much initial randomness as
703 possible, since at least one customer reboots ALL their clients
704 simultaneously -- so osi_Time is bound to be the same on some of the
705 clients. This is probably OK, but I don't want to see too much of it.
708 #define ranstage(x) (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
710 unsigned int afs_random(void)
712 static afs_int32 state = 0;
715 AFS_STATCNT(afs_random);
720 * 0xfffffff0 was changed to (~0 << 4) since it works no matter how many
721 * bits are in a tv_usec
723 state = (t.tv_usec & (~0 << 4) ) + (rxi_getaddr() & 0xff);
724 state += (t.tv_sec & 0xff);
735 /* returns int 0..14 using the high bits of a pseudo-random number instead of
736 the low bits, as the low bits are "less random" than the high ones...
737 slight roundoff error exists, an excercise for the reader.
738 need to multiply by something with lots of ones in it, so multiply by
739 8 or 16 is right out.
741 int afs_randomMod15(void)
745 temp = afs_random() >> 4;
746 temp = (temp *15) >> 28;
751 int afs_randomMod127(void)
755 temp = afs_random() >> 7;
756 temp = (temp *127) >> 25;
761 /* afs_SortOneServer()
762 * Sort all of the srvAddrs, of a server struct, by rank from low to high.
764 void afs_SortOneServer(struct server *asp)
766 struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
769 for (rootsa=&(asp->addr); *rootsa; rootsa=&(lowsa->next_sa)) {
771 lowsa = *rootsa; /* lowest sa is the first one */
772 lowrank = lowsa->sa_iprank;
774 for (tsa=*rootsa; tsa->next_sa; tsa=tsa->next_sa) {
775 rank = tsa->next_sa->sa_iprank;
776 if (rank < lowrank) {
778 lowsa = tsa->next_sa;
779 lowrank = lowsa->sa_iprank;
782 if (lowprev) { /* found one lower, so rearrange them */
783 lowprev->next_sa = lowsa->next_sa;
784 lowsa->next_sa = *rootsa;
791 * Sort the pointer to servers by the server's rank (its lowest rank).
792 * It is assumed that the server already has its IP addrs sorted (the
793 * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
795 void afs_SortServers(struct server *aservers[], int count)
800 AFS_STATCNT(afs_SortServers);
802 for (i=0; i<count; i++) {
803 if (!aservers[i]) break;
804 for (low=i,j=i+1; j<=count; j++) {
805 if ((!aservers[j]) || (!aservers[j]->addr))
807 if ((!aservers[low]) || (!aservers[low]->addr))
809 if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
815 aservers[i] = aservers[low];
819 } /*afs_SortServers*/
821 /* afs_SetServerPrefs is rather system-dependent. It pokes around in kernel
822 data structures to determine what the local IP addresses and subnet masks
823 are in order to choose which server(s) are on the local subnet.
825 As I see it, there are several cases:
826 1. The server address is one of this host's local addresses. In this case
827 this server is to be preferred over all others.
828 2. The server is on the same subnet as one of the this host's local
829 addresses. (ie, an odd-sized subnet, not class A,B,orC)
830 3. The server is on the same net as this host (class A,B or C)
831 4. The server is on a different logical subnet or net than this host, but
832 this host is a 'metric 0 gateway' to it. Ie, two address-spaces share
834 5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
836 6. This host and the server are disjoint.
838 That is a rough order of preference. If a point-to-point link has a high
839 metric, I'm assuming that it is a very slow link, and putting it at the
840 bottom of the list (at least until RX works better over slow links). If
841 its metric is 1, I'm assuming that it's relatively fast (T1) and putting
843 It's not easy to check for case #4, so I'm ignoring it for the time being.
845 BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
846 That could be used to prefer certain servers fairly easily. Maybe some
849 NOTE: this code is very system-dependent, and very dependent on the TCP/IP
850 protocols (well, addresses that are stored in uint32s, at any rate).
853 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
854 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
856 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
857 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
862 #define PPWEIGHT 4096
867 #if defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
868 #include <inet/common.h>
869 /* IP interface structure, one per local address */
870 typedef struct ipif_s { /**/
871 struct ipif_s * ipif_next;
872 struct ill_s * ipif_ill; /* Back pointer to our ill */
873 long ipif_id; /* Logical unit number */
874 u_int ipif_mtu; /* Starts at ipif_ill->ill_max_frag */
875 afs_int32 ipif_local_addr; /* Local IP address for this if. */
876 afs_int32 ipif_net_mask; /* Net mask for this interface. */
877 afs_int32 ipif_broadcast_addr; /* Broadcast addr for this interface. */
878 afs_int32 ipif_pp_dst_addr; /* Point-to-point dest address. */
879 u_int ipif_flags; /* Interface flags. */
880 u_int ipif_metric; /* BSD if metric, for compatibility. */
881 u_int ipif_ire_type; /* LOCAL or LOOPBACK */
882 mblk_t * ipif_arp_down_mp; /* Allocated at time arp comes up to
883 * prevent awkward out of mem condition
886 mblk_t * ipif_saved_ire_mp; /* Allocated for each extra IRE_SUBNET/
887 * RESOLVER on this interface so that
888 * they can survive ifconfig down.
891 * The packet counts in the ipif contain the sum of the
892 * packet counts in dead IREs that were affiliated with
895 u_long ipif_fo_pkt_count; /* Forwarded thru our dead IREs */
896 u_long ipif_ib_pkt_count; /* Inbound packets for our dead IREs */
897 u_long ipif_ob_pkt_count; /* Outbound packets to our dead IREs */
899 ipif_multicast_up : 1, /* We have joined the allhosts group */
903 typedef struct ipfb_s { /**/
904 struct ipf_s * ipfb_ipf; /* List of ... */
905 kmutex_t ipfb_lock; /* Protect all ipf in list */
908 typedef struct ilm_s { /**/
911 u_int ilm_timer; /* IGMP */
912 struct ipif_s * ilm_ipif; /* Back pointer to ipif */
913 struct ilm_s * ilm_next; /* Linked list for each ill */
916 typedef struct ill_s { /**/
917 struct ill_s * ill_next; /* Chained in at ill_g_head. */
918 struct ill_s ** ill_ptpn; /* Pointer to previous next. */
919 queue_t * ill_rq; /* Read queue. */
920 queue_t * ill_wq; /* Write queue. */
922 int ill_error; /* Error value sent up by device. */
924 ipif_t * ill_ipif; /* Interface chain for this ILL. */
925 u_int ill_ipif_up_count; /* Number of IPIFs currently up. */
926 u_int ill_max_frag; /* Max IDU. */
927 char * ill_name; /* Our name. */
928 u_int ill_name_length; /* Name length, incl. terminator. */
929 u_int ill_subnet_type; /* IRE_RESOLVER or IRE_SUBNET. */
930 u_int ill_ppa; /* Physical Point of Attachment num. */
932 int ill_sap_length; /* Including sign (for position) */
933 u_int ill_phys_addr_length; /* Excluding the sap. */
934 mblk_t * ill_frag_timer_mp; /* Reassembly timer state. */
935 ipfb_t * ill_frag_hash_tbl; /* Fragment hash list head. */
937 queue_t * ill_bind_pending_q; /* Queue waiting for DL_BIND_ACK. */
938 ipif_t * ill_ipif_pending; /* IPIF waiting for DL_BIND_ACK. */
940 /* ill_hdr_length and ill_hdr_mp will be non zero if
941 * the underlying device supports the M_DATA fastpath
945 ilm_t * ill_ilm; /* Multicast mebership for lower ill */
947 /* All non-nil cells between 'ill_first_mp_to_free' and
948 * 'ill_last_mp_to_free' are freed in ill_delete.
950 #define ill_first_mp_to_free ill_hdr_mp
951 mblk_t * ill_hdr_mp; /* Contains fastpath template */
952 mblk_t * ill_bcast_mp; /* DLPI header for broadcasts. */
953 mblk_t * ill_bind_pending; /* T_BIND_REQ awaiting completion. */
954 mblk_t * ill_resolver_mp; /* Resolver template. */
955 mblk_t * ill_attach_mp;
956 mblk_t * ill_bind_mp;
957 mblk_t * ill_unbind_mp;
958 mblk_t * ill_detach_mp;
959 #define ill_last_mp_to_free ill_detach_mp
962 ill_frag_timer_running : 1,
963 ill_needs_attach : 1,
966 ill_unbind_pending : 1,
968 ill_pad_to_bit_31 : 27;
969 MI_HRT_DCL(ill_rtime)
974 #ifdef AFS_USERSPACE_IP_ADDR
976 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
979 * The IP addresses and ranks are determined by afsd (in user space) and
980 * passed into the kernel at startup time through the AFSOP_ADVISEADDR
981 * system call. These are stored in the data structure
982 * called 'afs_cb_interface'.
984 * struct srvAddr *sa; remote server
985 * afs_int32 addr; one of my local addr in net order
986 * afs_uint32 subnetmask; subnet mask of local addr in net order
989 int afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr, afs_uint32 subnetmask)
991 afs_uint32 myAddr, myNet, mySubnet, netMask;
992 afs_uint32 serverAddr ;
994 myAddr = ntohl(addr); /* one of my IP addr in host order */
995 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
996 subnetmask = ntohl(subnetmask);/* subnet mask in host order */
998 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
999 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1000 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1003 myNet = myAddr & netMask;
1004 mySubnet = myAddr & subnetmask;
1006 if ( (serverAddr & netMask ) == myNet ) {
1007 if ( (serverAddr & subnetmask ) == mySubnet) {
1008 if ( serverAddr == myAddr ) { /* same machine */
1009 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1010 } else { /* same subnet */
1011 sa->sa_iprank = afs_min(sa->sa_iprank, HI);
1013 } else { /* same net */
1014 sa->sa_iprank = afs_min(sa->sa_iprank, MED);
1018 #else /* AFS_USERSPACE_IP_ADDR */
1019 #if (! defined(AFS_SUN5_ENV)) && !defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1020 void afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
1022 struct sockaddr_in *sin;
1025 if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1026 if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1028 if ( SA2ULONG(sin) == ntohl(sa->sa_ip)) { /* ie, ME!!! */
1029 sa->sa_iprank = TOPR;
1031 t = HI + ifa->ia_ifp->if_metric; /* case #2 */
1032 if (sa->sa_iprank > t)
1036 t = MED + ifa->ia_ifp->if_metric;/* case #3 */
1037 if (sa->sa_iprank > t)
1041 #ifdef IFF_POINTTOPOINT
1042 /* check for case #4 -- point-to-point link */
1043 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1044 (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1045 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1048 t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1049 if (sa->sa_iprank > t)
1052 #endif /* IFF_POINTTOPOINT */
1054 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1055 #if defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1057 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
1060 afsi_SetServerIPRank(sa, ifa)
1064 struct sockaddr_in *sin;
1067 afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
1068 afs_uint32 serverAddr ;
1070 if (ifa->ifa_addr->sa_family != AF_INET)
1072 sin=(struct sockaddr_in *)ifa->ifa_addr;
1073 myAddr = ntohl(sin->sin_addr.s_addr); /* one of my IP addr in host order */
1074 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
1075 sin=(struct sockaddr_in *)ifa->ifa_netmask;
1076 subnetmask = ntohl(sin->sin_addr.s_addr);/* subnet mask in host order */
1077 sin=(struct sockaddr_in *)ifa->ifa_dstaddr;
1079 myDstaddr=sin->sin_addr.s_addr;
1081 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1082 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1083 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1086 myNet = myAddr & netMask;
1087 mySubnet = myAddr & subnetmask;
1089 if ( (serverAddr & netMask ) == myNet ) {
1090 if ( (serverAddr & subnetmask ) == mySubnet) {
1091 if ( serverAddr == myAddr ) { /* same machine */
1092 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1093 } else { /* same subnet */
1094 sa->sa_iprank = afs_min(sa->sa_iprank, HI + ifa->ifa_metric);
1096 } else { /* same net */
1097 sa->sa_iprank = afs_min(sa->sa_iprank, MED + ifa->ifa_metric);
1100 #ifdef IFF_POINTTOPOINT
1101 /* check for case #4 -- point-to-point link */
1102 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1103 (myDstaddr == serverAddr))) {
1104 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1107 t = MED + (PPWEIGHT << ifa->->ifa_metric);
1108 if (sa->sa_iprank > t)
1111 #endif /* IFF_POINTTOPOINT */
1113 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1114 #endif /* else AFS_USERSPACE_IP_ADDR */
1116 #ifdef AFS_SGI62_ENV
1118 afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1121 afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr*)h);
1122 return 0; /* Never match, so we enumerate everyone */
1124 #endif /* AFS_SGI62_ENV */
1126 static int afs_SetServerPrefs(struct srvAddr *sa)
1128 #if defined(AFS_USERSPACE_IP_ADDR)
1132 for (i=0; i<afs_cb_interface.numberOfInterfaces; i++) {
1133 afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1134 afs_cb_interface.subnetmask[i]);
1136 #else /* AFS_USERSPACE_IP_ADDR */
1137 #if defined(AFS_SUN5_ENV)
1138 extern struct ill_s *ill_g_headp;
1141 int subnet, subnetmask, net, netmask;
1142 long *addr = (long *) ill_g_headp;
1144 if (sa) sa->sa_iprank= 0;
1145 for (ill = (struct ill_s *)*addr /*ill_g_headp*/; ill; ill = ill->ill_next ) {
1146 #ifdef AFS_SUN58_ENV
1147 /* Make sure this is an IPv4 ILL */
1148 if (ill->ill_isv6) continue;
1150 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next ) {
1151 subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1152 subnetmask = ipif->ipif_net_mask;
1154 * Generate the local net using the local address and
1155 * whate we know about Class A, B and C networks.
1157 if (IN_CLASSA(ipif->ipif_local_addr)) {
1158 netmask = IN_CLASSA_NET;
1159 } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1160 netmask = IN_CLASSB_NET;
1161 } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1162 netmask = IN_CLASSC_NET;
1166 net = ipif->ipif_local_addr & netmask;
1169 if (ipif->ipif_local_addr != 0x7f000001) { /* ignore loopback */
1171 if (*cnt > 16) return;
1172 *addrp++ = ipif->ipif_local_addr;
1177 /* XXXXXX Do the individual ip ranking below XXXXX */
1178 if ((sa->sa_ip & netmask) == net) {
1179 if ((sa->sa_ip & subnetmask) == subnet) {
1180 if (ipif->ipif_local_addr == sa->sa_ip) { /* ie, ME! */
1181 sa->sa_iprank = TOPR;
1183 sa->sa_iprank = HI + ipif->ipif_metric; /* case #2 */
1186 sa->sa_iprank = MED + ipif->ipif_metric; /* case #3 */
1189 sa->sa_iprank = LO + ipif->ipif_metric; /* case #4 */
1191 /* check for case #5 -- point-to-point link */
1192 if ((ipif->ipif_flags & IFF_POINTOPOINT) &&
1193 (ipif->ipif_pp_dst_addr == sa->sa_ip )) {
1195 if (ipif->ipif_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1196 sa->sa_iprank = MAXDEFRANK;
1198 sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1205 struct ifnet *ifn = NULL;
1206 struct in_ifaddr *ifad = (struct in_ifaddr *) 0;
1207 struct sockaddr_in *sin;
1210 #ifdef notdef /* clean up, remove this */
1211 for (ifn = ifnet; ifn != NULL; ifn = ifn->if_next) {
1212 for (ifad = ifn->if_addrlist; ifad != NULL; ifad = ifad->ifa_next){
1213 if ((IFADDR2SA(ifad)->sa_family == AF_INET)
1214 && !(ifn->if_flags & IFF_LOOPBACK)) {
1216 if (*cnt > 16) return;
1217 *addrp++ = ((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr;
1226 ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1228 if (ifn) { /* local, more or less */
1230 if (ifn->if_flags & IFF_LOOPBACK) {
1231 sa->sa_iprank = TOPR;
1234 #endif /* IFF_LOOPBACK */
1235 sin = (struct sockaddr_in *) IA_SIN(ifad);
1236 if (SA2ULONG(sin) == sa->sa_ip) {
1237 sa->sa_iprank = TOPR;
1240 #ifdef IFF_BROADCAST
1241 if (ifn->if_flags & IFF_BROADCAST) {
1242 if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1247 #endif /* IFF_BROADCAST */
1248 #ifdef IFF_POINTOPOINT
1249 if (ifn->if_flags & IFF_POINTOPOINT) {
1250 if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1251 if (ifn->if_metric > 4) {
1255 else sa->sa_iprank = ifn->if_metric;
1258 #endif /* IFF_POINTOPOINT */
1259 sa->sa_iprank += MED + ifn->if_metric; /* couldn't find anything better */
1262 #else /* USEIFADDR */
1264 if (sa) sa->sa_iprank= LO;
1265 #ifdef AFS_SGI62_ENV
1266 (void) hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1268 #elif defined(AFS_DARWIN60_ENV)
1272 TAILQ_FOREACH(ifn , &ifnet, if_link) {
1273 TAILQ_FOREACH(ifa , &ifn->if_addrhead, ifa_link) {
1274 afsi_SetServerIPRank(sa, ifa);
1278 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1280 struct in_ifaddr *ifa;
1281 TAILQ_FOREACH(ifa , &in_ifaddrhead, ia_link) {
1282 afsi_SetServerIPRank(sa, ifa);
1285 #elif defined(AFS_OBSD_ENV)
1287 extern struct in_ifaddrhead in_ifaddr;
1288 struct in_ifaddr *ifa;
1289 for (ifa = in_ifaddr.tqh_first; ifa; ifa = ifa->ia_list.tqe_next)
1290 afsi_SetServerIPRank(sa, ifa);
1294 struct in_ifaddr *ifa;
1295 for ( ifa = in_ifaddr; ifa; ifa = ifa->ia_next ) {
1296 afsi_SetServerIPRank(sa, ifa);
1302 #endif /* USEIFADDR */
1303 #endif /* AFS_SUN5_ENV */
1304 #endif /* else AFS_USERSPACE_IP_ADDR */
1306 if (sa) sa->sa_iprank += afs_randomMod15();
1309 } /* afs_SetServerPrefs */
1317 /* afs_FlushServer()
1318 * The addresses on this server struct has changed in some way and will
1319 * clean up all other structures that may reference it.
1320 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1322 void afs_FlushServer(struct server *srvp)
1325 struct server *ts, **pts;
1327 /* Find any volumes residing on this server and flush their state */
1328 afs_ResetVolumes(srvp);
1330 /* Flush all callbacks in the all vcaches for this specific server */
1331 afs_FlushServerCBs(srvp);
1333 /* Remove all the callbacks structs */
1335 struct afs_cbr *cb, *cbnext;
1337 MObtainWriteLock(&afs_xvcb, 300);
1338 for (cb=srvp->cbrs; cb; cb=cbnext) {
1342 srvp->cbrs = (struct afs_cbr *)0;
1343 ReleaseWriteLock(&afs_xvcb);
1346 /* If no more srvAddr structs hanging off of this server struct,
1350 /* Remove the server structure from the cell list - if there */
1351 afs_RemoveCellEntry(srvp);
1353 /* Remove from the afs_servers hash chain */
1354 for (i=0; i<NSERVERS; i++) {
1355 for (pts=&(afs_servers[i]), ts=*pts; ts; pts=&(ts->next), ts=*pts) {
1356 if (ts == srvp) break;
1361 *pts = ts->next; /* Found it. Remove it */
1362 afs_osi_Free(ts, sizeof(struct server)); /* Free it */
1368 /* afs_RemoveSrvAddr()
1369 * This removes a SrvAddr structure from its server structure.
1370 * The srvAddr struct is not free'd because it connections may still
1371 * be open to it. It is up to the calling process to make sure it
1372 * remains connected to a server struct.
1373 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1374 * It is not removed from the afs_srvAddrs hash chain.
1376 void afs_RemoveSrvAddr(struct srvAddr *sap)
1378 struct srvAddr **psa, *sa;
1384 /* Find the srvAddr in the server's list and remove it */
1385 for (psa=&(srv->addr), sa=*psa; sa; psa=&(sa->next_sa), sa=*psa) {
1386 if (sa == sap) break;
1393 /* Flush the server struct since it's IP address has changed */
1394 afs_FlushServer(srv);
1399 * Return an updated and properly initialized server structure
1400 * corresponding to the server ID, cell, and port specified.
1401 * If one does not exist, then one will be created.
1402 * aserver and aport must be in NET byte order.
1404 struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
1405 afs_int32 acell, u_short aport,
1406 afs_int32 locktype, afsUUID *uuidp,
1407 afs_int32 addr_uniquifier)
1409 struct server *oldts=0, *ts, *newts, *orphts=0;
1410 struct srvAddr *oldsa, *newsa, *nextsa, *orphsa;
1412 afs_int32 iphash, k, srvcount=0;
1413 unsigned int srvhash;
1415 AFS_STATCNT(afs_GetServer);
1417 ObtainSharedLock(&afs_xserver,13);
1419 /* Check if the server struct exists and is up to date */
1421 if (nservers != 1) panic("afs_GetServer: incorect count of servers");
1422 ObtainReadLock(&afs_xsrvAddr);
1423 ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1424 ReleaseReadLock(&afs_xsrvAddr);
1425 if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1426 /* Found a server struct that is not multihomed and has the
1427 * IP address associated with it. A correct match.
1429 ReleaseSharedLock(&afs_xserver);
1433 if (nservers <= 0) panic("afs_GetServer: incorrect count of servers");
1434 ts = afs_FindServer(0, aport, uuidp, locktype);
1435 if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1436 /* Found a server struct that is multihomed and same
1437 * uniqufier (same IP addrs). The above if statement is the
1438 * same as in InstallUVolumeEntry().
1440 ReleaseSharedLock(&afs_xserver);
1443 if (ts) oldts = ts; /* Will reuse if same uuid */
1446 UpgradeSToWLock(&afs_xserver,36);
1447 ObtainWriteLock(&afs_xsrvAddr,116);
1449 srvcount = afs_totalServers;
1451 /* Reuse/allocate a new server structure */
1455 newts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1456 if (!newts) panic("malloc of server struct");
1458 memset((char *)newts, 0, sizeof(struct server));
1460 /* Add the server struct to the afs_servers[] hash chain */
1461 srvhash = (uuidp ? (afs_uuid_hash(uuidp)%NSERVERS) : SHash(aserverp[0]));
1462 newts->next = afs_servers[srvhash];
1463 afs_servers[srvhash] = newts;
1466 /* Initialize the server structure */
1467 if (uuidp) { /* Multihomed */
1468 newts->sr_uuid = *uuidp;
1469 newts->sr_addr_uniquifier = addr_uniquifier;
1470 newts->flags |= SRVR_MULTIHOMED;
1472 if (acell) newts->cell = afs_GetCell(acell, 0);
1474 fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
1476 /* For each IP address we are registering */
1477 for (k=0; k<nservers; k++) {
1478 iphash = SHash(aserverp[k]);
1480 /* Check if the srvAddr structure already exists. If so, remove
1481 * it from its server structure and add it to the new one.
1483 for (oldsa=afs_srvAddrs[iphash]; oldsa; oldsa=oldsa->next_bkt) {
1484 if ( (oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport) ) break;
1486 if (oldsa && (oldsa->server != newts)) {
1487 afs_RemoveSrvAddr(oldsa); /* Remove from its server struct */
1488 oldsa->next_sa = newts->addr; /* Add to the new server struct */
1489 newts->addr = oldsa;
1492 /* Reuse/allocate a new srvAddr structure */
1496 newsa = (struct srvAddr *) afs_osi_Alloc(sizeof(struct srvAddr));
1497 if (!newsa) panic("malloc of srvAddr struct");
1498 afs_totalSrvAddrs++;
1499 memset((char *)newsa, 0, sizeof(struct srvAddr));
1501 /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1502 newsa->next_bkt = afs_srvAddrs[iphash];
1503 afs_srvAddrs[iphash] = newsa;
1505 /* Hang off of the server structure */
1506 newsa->next_sa = newts->addr;
1507 newts->addr = newsa;
1509 /* Initialize the srvAddr Structure */
1510 newsa->sa_ip = aserverp[k];
1511 newsa->sa_portal = aport;
1514 /* Update the srvAddr Structure */
1515 newsa->server = newts;
1516 if (newts->flags & SRVR_ISDOWN)
1517 newsa->sa_flags |= SRVADDR_ISDOWN;
1518 if (uuidp) newsa->sa_flags |= SRVADDR_MH;
1519 else newsa->sa_flags &= ~SRVADDR_MH;
1521 /* Compute preference values and resort */
1522 if (!newsa->sa_iprank) {
1523 if (aport == fsport) {
1524 afs_SetServerPrefs(newsa); /* new fileserver rank */
1526 newsa->sa_iprank = 10000 + afs_randomMod127(); /* new vlserver rank */
1530 afs_SortOneServer(newts); /* Sort by rank */
1532 /* If we reused the server struct, remove any of its srvAddr
1533 * structs that will no longer be associated with this server.
1535 if (oldts) { /* reused the server struct */
1536 for (orphsa=newts->addr; orphsa; orphsa=nextsa) {
1537 nextsa = orphsa->next_sa;
1538 for (k=0; k<nservers; k++) {
1539 if (orphsa->sa_ip == aserverp[k]) break; /* belongs */
1541 if (k < nservers) continue; /* belongs */
1543 /* Have a srvAddr struct. Now get a server struct (if not already) */
1545 orphts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1546 if (!orphts) panic("malloc of lo server struct");
1547 memset((char *)orphts, 0, sizeof(struct server));
1550 /* Add the orphaned server to the afs_servers[] hash chain.
1551 * Its iphash does not matter since we never look up the server
1552 * in the afs_servers table by its ip address (only by uuid -
1553 * which this has none).
1555 iphash = SHash(aserverp[k]);
1556 orphts->next = afs_servers[iphash];
1557 afs_servers[iphash] = orphts;
1559 if (acell) orphts->cell = afs_GetCell(acell, 0);
1562 /* Hang the srvAddr struct off of the server structure. The server
1563 * may have multiple srvAddrs, but it won't be marked multihomed.
1565 afs_RemoveSrvAddr(orphsa); /* remove */
1566 orphsa->next_sa = orphts->addr; /* hang off server struct */
1567 orphts->addr = orphsa;
1568 orphsa->server = orphts;
1569 orphsa->sa_flags |= SRVADDR_NOUSE; /* flag indicating not in use */
1570 orphsa->sa_flags &= ~SRVADDR_MH; /* Not multihomed */
1574 srvcount = afs_totalServers - srvcount; /* # servers added and removed */
1576 struct afs_stats_SrvUpDownInfo *upDownP;
1577 /* With the introduction of this new record, we need to adjust the
1578 * proper individual & global server up/down info.
1580 upDownP = GetUpDownStats(newts);
1581 upDownP->numTtlRecords += srvcount;
1582 afs_stats_cmperf.srvRecords += srvcount;
1583 if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1584 afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1587 ReleaseWriteLock(&afs_xsrvAddr);
1588 ReleaseWriteLock(&afs_xserver);
1590 } /* afs_GetServer */
1592 void afs_ActivateServer(struct srvAddr *sap)
1594 osi_timeval_t currTime; /*Filled with current time*/
1595 osi_timeval_t *currTimeP; /*Ptr to above*/
1596 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
1597 struct server *aserver = sap->server;
1599 if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1601 * This server record has not yet been activated. Go for it,
1602 * recording its ``birth''.
1604 aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1605 currTimeP = &currTime;
1606 osi_GetuTime(currTimeP);
1607 aserver->activationTime = currTime.tv_sec;
1608 upDownP = GetUpDownStats(aserver);
1609 if (aserver->flags & SRVR_ISDOWN) {
1610 upDownP->numDownRecords++;
1612 upDownP->numUpRecords++;
1613 upDownP->numRecordsNeverDown++;