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 */
41 #if !defined(AFS_LINUX20_ENV)
44 #include <netinet/in.h>
47 #include "h/hashing.h"
49 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
50 #include <netinet/in_var.h>
51 #endif /* AFS_HPUX110_ENV */
52 #ifdef AFS_DARWIN60_ENV
53 #include <net/if_var.h>
55 #endif /* !defined(UKERNEL) */
57 #include "afsincludes.h" /* Afs-based standard headers */
58 #include "afs/afs_stats.h" /* afs statistics */
60 #if defined(AFS_SUN56_ENV)
62 #include <inet/common.h>
63 #if defined(AFS_SUN58_ENV)
64 # include <netinet/ip6.h>
65 # define ipif_local_addr ipif_lcl_addr
66 # ifndef V4_PART_OF_V6
67 # define V4_PART_OF_V6(v6) v6.s6_addr32[3]
73 /* Exported variables */
74 afs_rwlock_t afs_xserver; /* allocation lock for servers */
75 struct server *afs_setTimeHost=0; /* last host we used for time */
76 struct server *afs_servers[NSERVERS]; /* Hashed by server`s uuid & 1st ip */
77 afs_rwlock_t afs_xsrvAddr; /* allocation lock for srvAddrs */
78 struct srvAddr *afs_srvAddrs[NSERVERS]; /* Hashed by server's ip */
81 /* debugging aids - number of alloc'd server and srvAddr structs. */
82 int afs_reuseServers = 0;
83 int afs_reuseSrvAddrs = 0;
84 int afs_totalServers = 0;
85 int afs_totalSrvAddrs = 0;
89 static struct afs_stats_SrvUpDownInfo *
90 GetUpDownStats(struct server *srv)
92 struct afs_stats_SrvUpDownInfo *upDownP;
93 u_short fsport = AFS_FSPORT;
96 fsport = srv->cell->fsport;
98 if (srv->addr->sa_portal == fsport)
99 upDownP = afs_stats_cmperf.fs_UpDown;
101 upDownP = afs_stats_cmperf.vl_UpDown;
103 if (srv->cell && afs_IsPrimaryCell(srv->cell))
104 return &upDownP[AFS_STATS_UPDOWN_IDX_SAME_CELL];
106 return &upDownP[AFS_STATS_UPDOWN_IDX_DIFF_CELL];
110 /*------------------------------------------------------------------------
111 * afs_MarkServerUpOrDown
114 * Mark the given server up or down, and track its uptime stats.
117 * a_serverP : Ptr to server record to fiddle with.
118 * a_isDown : Is the server is to be marked down?
124 * The CM server structures must be write-locked.
128 *------------------------------------------------------------------------*/
130 void afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
132 register struct server *a_serverP = sa->server;
133 register struct srvAddr *sap;
134 osi_timeval_t currTime, *currTimeP; /*Current time*/
135 afs_int32 downTime; /*Computed downtime, in seconds*/
136 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
139 * If the server record is marked the same as the new status we've
140 * been fed, then there isn't much to be done.
142 if (( a_isDown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
143 (!a_isDown && !(sa->sa_flags & SRVADDR_ISDOWN)))
147 sa->sa_flags |= SRVADDR_ISDOWN;
148 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
149 if (!(sap->sa_flags & SRVADDR_ISDOWN)) {
150 /* Not all ips are up so don't bother with the
151 * server's up/down stats */
156 * All ips are down we treat the whole server down
158 a_serverP->flags |= SRVR_ISDOWN;
160 * If this was our time server, search for another time server
162 if (a_serverP == afs_setTimeHost)
165 sa->sa_flags &= ~SRVADDR_ISDOWN;
166 /* If any ips are up, the server is also marked up */
167 a_serverP->flags &= ~SRVR_ISDOWN;
168 for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
169 if (sap->sa_flags & SRVADDR_ISDOWN) {
170 /* Not all ips are up so don't bother with the
171 * server's up/down stats */
178 * Compute the current time and which overall stats record is to be
179 * updated; we'll need them one way or another.
181 currTimeP = &currTime;
182 osi_GetuTime(currTimeP);
184 upDownP = GetUpDownStats(a_serverP);
188 * Server going up -> down; remember the beginning of this
191 a_serverP->lastDowntimeStart = currTime.tv_sec;
193 (upDownP->numDownRecords)++;
194 (upDownP->numUpRecords)--;
195 } /*Server being marked down*/
198 * Server going down -> up; remember everything about this
199 * newly-completed downtime incident.
201 downTime = currTime.tv_sec - a_serverP->lastDowntimeStart;
202 (a_serverP->numDowntimeIncidents)++;
203 a_serverP->sumOfDowntimes += downTime;
205 (upDownP->numUpRecords)++;
206 (upDownP->numDownRecords)--;
207 (upDownP->numDowntimeIncidents)++;
208 if (a_serverP->numDowntimeIncidents == 1)
209 (upDownP->numRecordsNeverDown)--;
210 upDownP->sumOfDowntimes += downTime;
211 if ((upDownP->shortestDowntime == 0) ||
212 (downTime < upDownP->shortestDowntime))
213 upDownP->shortestDowntime = downTime;
214 if ((upDownP->longestDowntime == 0) ||
215 (downTime > upDownP->longestDowntime))
216 upDownP->longestDowntime = downTime;
219 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET0)
220 (upDownP->downDurations[0])++;
222 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET1)
223 (upDownP->downDurations[1])++;
225 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET2)
226 (upDownP->downDurations[2])++;
228 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET3)
229 (upDownP->downDurations[3])++;
231 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET4)
232 (upDownP->downDurations[4])++;
234 if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET5)
235 (upDownP->downDurations[5])++;
237 (upDownP->downDurations[6])++;
239 } /*Server being marked up*/
241 } /*MarkServerUpOrDown*/
244 void afs_ServerDown(struct srvAddr *sa)
246 register struct server *aserver = sa->server;
248 AFS_STATCNT(ServerDown);
249 if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
251 afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
252 if (sa->sa_portal == aserver->cell->vlport)
253 print_internet_address("afs: Lost contact with volume location server ",
256 print_internet_address("afs: Lost contact with file server ", sa, "", 1);
261 /* return true if we have any callback promises from this server */
262 static int HaveCallBacksFrom(struct server *aserver)
264 register afs_int32 now;
266 register struct vcache *tvc;
268 AFS_STATCNT(HaveCallBacksFrom);
269 now = osi_Time(); /* for checking for expired callbacks */
270 for(i=0;i<VCSIZE;i++) { /* for all guys in the hash table */
271 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
273 * Check to see if this entry has an unexpired callback promise
274 * from the required host
276 if (aserver == tvc->callback && tvc->cbExpires >= now
277 && ((tvc->states & CRO) == 0))
283 } /*HaveCallBacksFrom*/
286 static void CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
288 register struct server *aserver = sa->server;
289 register struct conn *tc;
290 register afs_int32 code;
292 AFS_STATCNT(CheckVLServer);
293 /* Ping dead servers to see if they're back */
294 if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN)) || (aserver->flags & SRVR_ISGONE))
297 return; /* can't do much */
299 tc = afs_ConnByHost(aserver, aserver->cell->vlport,
300 aserver->cell->cellNum, areq, 1, SHARED_LOCK);
303 rx_SetConnDeadTime(tc->id, 3);
306 code = VL_ProbeServer(tc->id);
308 rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
309 afs_PutConn(tc, SHARED_LOCK);
311 * If probe worked, or probe call not yet defined (for compatibility
312 * with old vlsevers), then we treat this server as running again
314 if (code == 0 || (code <= -450 && code >= -470)) {
315 if (tc->srvr == sa) {
316 afs_MarkServerUpOrDown(sa, 0);
317 print_internet_address("afs: volume location server ",
318 sa, " is back up", 2);
325 #ifndef AFS_MINCHANGE /* So that some can increase it in param.h */
326 #define AFS_MINCHANGE 2 /* min change we'll bother with */
328 #ifndef AFS_MAXCHANGEBACK
329 #define AFS_MAXCHANGEBACK 10 /* max seconds we'll set a clock back at once */
333 /*------------------------------------------------------------------------
334 * EXPORTED afs_CountServers
337 * Originally meant to count the number of servers and determining
338 * up/down info, this routine will now simply sum up all of the
339 * server record ages. All other up/down information is kept on the
349 * This routine locks afs_xserver for write for the duration.
352 * Set CM perf stats field sumOfRecordAges for all server record
354 *------------------------------------------------------------------------*/
356 void afs_CountServers(void)
358 int currIdx; /*Curr idx into srv table*/
359 struct server *currSrvP; /*Ptr to curr server record*/
360 afs_int32 currChainLen; /*Length of curr hash chain*/
361 osi_timeval_t currTime; /*Current time*/
362 osi_timeval_t *currTimeP; /*Ptr to above*/
363 afs_int32 srvRecordAge; /*Age of server record, in secs*/
364 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to current up/down
365 info being manipulated*/
368 * Write-lock the server table so we don't get any interference.
370 ObtainReadLock(&afs_xserver);
373 * Iterate over each hash index in the server table, walking down each
374 * chain and tallying what we haven't computed from the records there on
375 * the fly. First, though, initialize the tallies that will change.
377 afs_stats_cmperf.srvMaxChainLength = 0;
379 afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
380 afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
381 afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
382 memset((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
384 afs_stats_cmperf.fs_UpDown[1].sumOfRecordAges = 0;
385 afs_stats_cmperf.fs_UpDown[1].ageOfYoungestRecord = 0;
386 afs_stats_cmperf.fs_UpDown[1].ageOfOldestRecord = 0;
387 memset((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
389 afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges = 0;
390 afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
391 afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord = 0;
392 memset((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
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 memset((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
400 * Compute the current time, used to figure out server record ages.
402 currTimeP = &currTime;
403 osi_GetuTime(currTimeP);
406 * Sweep the server hash table, tallying all we need to know.
408 for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
410 for (currSrvP = afs_servers[currIdx]; currSrvP; currSrvP = currSrvP->next) {
412 * Bump the current chain length.
417 * Any further tallying for this record will only be done if it has
420 if ( (currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED) &&
421 currSrvP->addr && currSrvP->cell ) {
424 * Compute the current server record's age, then remember it
425 * in the appropriate places.
427 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
428 upDownP = GetUpDownStats(currSrvP);
429 upDownP->sumOfRecordAges += srvRecordAge;
430 if ((upDownP->ageOfYoungestRecord == 0) ||
431 (srvRecordAge < upDownP->ageOfYoungestRecord))
432 upDownP->ageOfYoungestRecord = srvRecordAge;
433 if ((upDownP->ageOfOldestRecord == 0) ||
434 (srvRecordAge > upDownP->ageOfOldestRecord))
435 upDownP->ageOfOldestRecord = srvRecordAge;
437 if (currSrvP->numDowntimeIncidents <=
438 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
439 (upDownP->downIncidents[0])++;
441 if (currSrvP->numDowntimeIncidents <=
442 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
443 (upDownP->downIncidents[1])++;
445 if (currSrvP->numDowntimeIncidents <=
446 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
447 (upDownP->downIncidents[2])++;
449 if (currSrvP->numDowntimeIncidents <=
450 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
451 (upDownP->downIncidents[3])++;
453 if (currSrvP->numDowntimeIncidents <=
454 AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
455 (upDownP->downIncidents[4])++;
457 (upDownP->downIncidents[5])++;
460 } /*Current server has been active*/
461 } /*Walk this chain*/
464 * Before advancing to the next chain, remember facts about this one.
466 if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
468 * We beat out the former champion (which was initially set to 0
469 * here). Mark down the new winner, and also remember if it's an
472 afs_stats_cmperf.srvMaxChainLength = currChainLen;
473 if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
474 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
475 } /*Update chain length maximum*/
476 } /*For each hash chain*/
479 * We're done. Unlock the server table before returning to our caller.
481 ReleaseReadLock(&afs_xserver);
483 } /*afs_CountServers*/
486 /* check down servers (if adown), or running servers (if !adown) */
487 void afs_CheckServers(int adown, struct cell *acellp)
489 struct vrequest treq;
495 afs_int32 start, end, delta;
501 struct srvAddr **addrs;
504 AFS_STATCNT(afs_CheckServers);
505 if ((code = afs_InitReq(&treq, &afs_osi_cred))) return;
506 ObtainReadLock(&afs_xserver); /* Necessary? */
507 ObtainReadLock(&afs_xsrvAddr);
510 for (i=0;i<NSERVERS;i++) {
511 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
516 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
518 for (i=0;i<NSERVERS;i++) {
519 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
520 if (j >= srvAddrCount) break;
525 ReleaseReadLock(&afs_xsrvAddr);
526 ReleaseReadLock(&afs_xserver);
528 for (i=0; i<j; i++) {
534 /* See if a cell to check was specified. If it is spec'd and not
535 * this server's cell, just skip the server.
537 if (acellp && acellp != ts->cell)
540 if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
541 (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
544 /* check vlserver with special code */
545 if (sa->sa_portal == AFS_VLPORT) {
546 CheckVLServer(sa, &treq);
550 if (!ts->cell) /* not really an active server, anyway, it must */
551 continue; /* have just been added by setsprefs */
553 /* get a connection, even if host is down; bumps conn ref count */
554 tu = afs_GetUser(treq.uid, ts->cell->cellNum, SHARED_LOCK);
555 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
556 1/*force*/, 1/*create*/, SHARED_LOCK);
557 afs_PutUser(tu, SHARED_LOCK);
560 if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
561 (tc->srvr->server == afs_setTimeHost)) {
562 if (sa->sa_flags & SRVADDR_ISDOWN) {
563 rx_SetConnDeadTime(tc->id, 3);
569 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
570 start = osi_Time(); /* time the gettimeofday call */
572 code = RXAFS_GetTime(tc->id, (afs_int32 *)&tv.tv_sec, (afs_int32 *)&tv.tv_usec);
577 * If we're supposed to set the time, and the call worked
578 * quickly (same second response) and this is the host we
579 * use for the time and the time is really different, then
580 * really set the time
582 if (code == 0 && start == end && afs_setTime != 0 &&
583 (tc->srvr->server == afs_setTimeHost ||
584 /* Sync only to a server in the local cell */
585 (afs_setTimeHost == (struct server *)0 &&
586 afs_IsPrimaryCell(ts->cell)))) {
588 char msgbuf[90]; /* strlen("afs: setting clock...") + slop */
590 delta = end - tv.tv_sec; /* how many secs fast we are */
591 /* see if clock has changed enough to make it worthwhile */
592 if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
593 if (delta > AFS_MAXCHANGEBACK) {
594 /* setting clock too far back, just do it a little */
595 tv.tv_sec = end - AFS_MAXCHANGEBACK;
597 afs_osi_SetTime(&tv);
599 strcpy(msgbuf, "afs: setting clock back ");
600 if (delta > AFS_MAXCHANGEBACK) {
601 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
602 afs_strcat(msgbuf, " seconds (of ");
603 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
604 afs_strcat(msgbuf, ", via ");
605 print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
607 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
608 afs_strcat(msgbuf, " seconds (via ");
609 print_internet_address(msgbuf, sa, ").", 0);
612 strcpy(msgbuf, "afs: setting clock ahead ");
613 afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
614 afs_strcat(msgbuf, " seconds (via ");
615 print_internet_address(msgbuf, sa, ").", 0);
618 afs_setTimeHost = tc->srvr->server;
621 rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
622 if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
624 print_internet_address("afs: file server ", sa, " is back up", 2);
626 ObtainWriteLock(&afs_xserver, 244);
627 ObtainWriteLock(&afs_xsrvAddr, 245);
628 afs_MarkServerUpOrDown(sa, 0);
629 ReleaseWriteLock(&afs_xsrvAddr);
630 ReleaseWriteLock(&afs_xserver);
632 if (afs_waitForeverCount) {
633 afs_osi_Wakeup(&afs_waitForever);
639 ForceNewConnections(sa); /* multi homed clients */
644 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
645 } /* Outer loop over addrs */
647 afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
649 } /*afs_CheckServers*/
652 /* find a server structure given the host address */
653 struct server *afs_FindServer (afs_int32 aserver, ushort aport,
654 afsUUID *uuidp, afs_int32 locktype)
660 AFS_STATCNT(afs_FindServer);
662 i = afs_uuid_hash(uuidp) % NSERVERS;
663 for (ts = afs_servers[i]; ts; ts = ts->next) {
664 if ( (ts->flags & SRVR_MULTIHOMED) &&
665 (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
666 (!ts->addr || (ts->addr->sa_portal == aport)) )
671 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
672 if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
682 /* some code for creating new server structs and setting preferences follows
683 * in the next few lines...
686 #define MAXDEFRANK 60000
687 #define DEFRANK 40000
689 /* Random number generator and constants from KnuthV2 2d ed, p170 */
695 a is 0.73m should be 0.01m .. 0.99m
696 c is more or less immaterial. 1 or a is suggested.
698 NB: LOW ORDER BITS are not very random. To get small random numbers,
699 treat result as <1, with implied binary point, and multiply by
701 NB: Has to be unsigned, since shifts on signed quantities may preserve
704 /* added rxi_getaddr() to try to get as much initial randomness as
705 possible, since at least one customer reboots ALL their clients
706 simultaneously -- so osi_Time is bound to be the same on some of the
707 clients. This is probably OK, but I don't want to see too much of it.
710 #define ranstage(x) (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
712 unsigned int afs_random(void)
714 static afs_int32 state = 0;
717 AFS_STATCNT(afs_random);
722 * 0xfffffff0 was changed to (~0 << 4) since it works no matter how many
723 * bits are in a tv_usec
725 state = (t.tv_usec & (~0 << 4) ) + (rxi_getaddr() & 0xff);
726 state += (t.tv_sec & 0xff);
737 /* returns int 0..14 using the high bits of a pseudo-random number instead of
738 the low bits, as the low bits are "less random" than the high ones...
739 slight roundoff error exists, an excercise for the reader.
740 need to multiply by something with lots of ones in it, so multiply by
741 8 or 16 is right out.
743 int afs_randomMod15(void)
747 temp = afs_random() >> 4;
748 temp = (temp *15) >> 28;
753 int afs_randomMod127(void)
757 temp = afs_random() >> 7;
758 temp = (temp *127) >> 25;
763 /* afs_SortOneServer()
764 * Sort all of the srvAddrs, of a server struct, by rank from low to high.
766 void afs_SortOneServer(struct server *asp)
768 struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
771 for (rootsa=&(asp->addr); *rootsa; rootsa=&(lowsa->next_sa)) {
773 lowsa = *rootsa; /* lowest sa is the first one */
774 lowrank = lowsa->sa_iprank;
776 for (tsa=*rootsa; tsa->next_sa; tsa=tsa->next_sa) {
777 rank = tsa->next_sa->sa_iprank;
778 if (rank < lowrank) {
780 lowsa = tsa->next_sa;
781 lowrank = lowsa->sa_iprank;
784 if (lowprev) { /* found one lower, so rearrange them */
785 lowprev->next_sa = lowsa->next_sa;
786 lowsa->next_sa = *rootsa;
793 * Sort the pointer to servers by the server's rank (its lowest rank).
794 * It is assumed that the server already has its IP addrs sorted (the
795 * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
797 void afs_SortServers(struct server *aservers[], int count)
802 AFS_STATCNT(afs_SortServers);
804 for (i=0; i<count; i++) {
805 if (!aservers[i]) break;
806 for (low=i,j=i+1; j<=count; j++) {
807 if ((!aservers[j]) || (!aservers[j]->addr))
809 if ((!aservers[low]) || (!aservers[low]->addr))
811 if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
817 aservers[i] = aservers[low];
821 } /*afs_SortServers*/
823 /* afs_SetServerPrefs is rather system-dependent. It pokes around in kernel
824 data structures to determine what the local IP addresses and subnet masks
825 are in order to choose which server(s) are on the local subnet.
827 As I see it, there are several cases:
828 1. The server address is one of this host's local addresses. In this case
829 this server is to be preferred over all others.
830 2. The server is on the same subnet as one of the this host's local
831 addresses. (ie, an odd-sized subnet, not class A,B,orC)
832 3. The server is on the same net as this host (class A,B or C)
833 4. The server is on a different logical subnet or net than this host, but
834 this host is a 'metric 0 gateway' to it. Ie, two address-spaces share
836 5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
838 6. This host and the server are disjoint.
840 That is a rough order of preference. If a point-to-point link has a high
841 metric, I'm assuming that it is a very slow link, and putting it at the
842 bottom of the list (at least until RX works better over slow links). If
843 its metric is 1, I'm assuming that it's relatively fast (T1) and putting
845 It's not easy to check for case #4, so I'm ignoring it for the time being.
847 BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
848 That could be used to prefer certain servers fairly easily. Maybe some
851 NOTE: this code is very system-dependent, and very dependent on the TCP/IP
852 protocols (well, addresses that are stored in uint32s, at any rate).
855 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
856 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
858 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
859 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
864 #define PPWEIGHT 4096
869 #if defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
870 #include <inet/common.h>
871 /* IP interface structure, one per local address */
872 typedef struct ipif_s { /**/
873 struct ipif_s * ipif_next;
874 struct ill_s * ipif_ill; /* Back pointer to our ill */
875 long ipif_id; /* Logical unit number */
876 u_int ipif_mtu; /* Starts at ipif_ill->ill_max_frag */
877 afs_int32 ipif_local_addr; /* Local IP address for this if. */
878 afs_int32 ipif_net_mask; /* Net mask for this interface. */
879 afs_int32 ipif_broadcast_addr; /* Broadcast addr for this interface. */
880 afs_int32 ipif_pp_dst_addr; /* Point-to-point dest address. */
881 u_int ipif_flags; /* Interface flags. */
882 u_int ipif_metric; /* BSD if metric, for compatibility. */
883 u_int ipif_ire_type; /* LOCAL or LOOPBACK */
884 mblk_t * ipif_arp_down_mp; /* Allocated at time arp comes up to
885 * prevent awkward out of mem condition
888 mblk_t * ipif_saved_ire_mp; /* Allocated for each extra IRE_SUBNET/
889 * RESOLVER on this interface so that
890 * they can survive ifconfig down.
893 * The packet counts in the ipif contain the sum of the
894 * packet counts in dead IREs that were affiliated with
897 u_long ipif_fo_pkt_count; /* Forwarded thru our dead IREs */
898 u_long ipif_ib_pkt_count; /* Inbound packets for our dead IREs */
899 u_long ipif_ob_pkt_count; /* Outbound packets to our dead IREs */
901 ipif_multicast_up : 1, /* We have joined the allhosts group */
905 typedef struct ipfb_s { /**/
906 struct ipf_s * ipfb_ipf; /* List of ... */
907 kmutex_t ipfb_lock; /* Protect all ipf in list */
910 typedef struct ilm_s { /**/
913 u_int ilm_timer; /* IGMP */
914 struct ipif_s * ilm_ipif; /* Back pointer to ipif */
915 struct ilm_s * ilm_next; /* Linked list for each ill */
918 typedef struct ill_s { /**/
919 struct ill_s * ill_next; /* Chained in at ill_g_head. */
920 struct ill_s ** ill_ptpn; /* Pointer to previous next. */
921 queue_t * ill_rq; /* Read queue. */
922 queue_t * ill_wq; /* Write queue. */
924 int ill_error; /* Error value sent up by device. */
926 ipif_t * ill_ipif; /* Interface chain for this ILL. */
927 u_int ill_ipif_up_count; /* Number of IPIFs currently up. */
928 u_int ill_max_frag; /* Max IDU. */
929 char * ill_name; /* Our name. */
930 u_int ill_name_length; /* Name length, incl. terminator. */
931 u_int ill_subnet_type; /* IRE_RESOLVER or IRE_SUBNET. */
932 u_int ill_ppa; /* Physical Point of Attachment num. */
934 int ill_sap_length; /* Including sign (for position) */
935 u_int ill_phys_addr_length; /* Excluding the sap. */
936 mblk_t * ill_frag_timer_mp; /* Reassembly timer state. */
937 ipfb_t * ill_frag_hash_tbl; /* Fragment hash list head. */
939 queue_t * ill_bind_pending_q; /* Queue waiting for DL_BIND_ACK. */
940 ipif_t * ill_ipif_pending; /* IPIF waiting for DL_BIND_ACK. */
942 /* ill_hdr_length and ill_hdr_mp will be non zero if
943 * the underlying device supports the M_DATA fastpath
947 ilm_t * ill_ilm; /* Multicast mebership for lower ill */
949 /* All non-nil cells between 'ill_first_mp_to_free' and
950 * 'ill_last_mp_to_free' are freed in ill_delete.
952 #define ill_first_mp_to_free ill_hdr_mp
953 mblk_t * ill_hdr_mp; /* Contains fastpath template */
954 mblk_t * ill_bcast_mp; /* DLPI header for broadcasts. */
955 mblk_t * ill_bind_pending; /* T_BIND_REQ awaiting completion. */
956 mblk_t * ill_resolver_mp; /* Resolver template. */
957 mblk_t * ill_attach_mp;
958 mblk_t * ill_bind_mp;
959 mblk_t * ill_unbind_mp;
960 mblk_t * ill_detach_mp;
961 #define ill_last_mp_to_free ill_detach_mp
964 ill_frag_timer_running : 1,
965 ill_needs_attach : 1,
968 ill_unbind_pending : 1,
970 ill_pad_to_bit_31 : 27;
971 MI_HRT_DCL(ill_rtime)
976 #ifdef AFS_USERSPACE_IP_ADDR
978 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
981 * The IP addresses and ranks are determined by afsd (in user space) and
982 * passed into the kernel at startup time through the AFSOP_ADVISEADDR
983 * system call. These are stored in the data structure
984 * called 'afs_cb_interface'.
986 * struct srvAddr *sa; remote server
987 * afs_int32 addr; one of my local addr in net order
988 * afs_uint32 subnetmask; subnet mask of local addr in net order
991 int afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr, afs_uint32 subnetmask)
993 afs_uint32 myAddr, myNet, mySubnet, netMask;
994 afs_uint32 serverAddr ;
996 myAddr = ntohl(addr); /* one of my IP addr in host order */
997 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
998 subnetmask = ntohl(subnetmask);/* subnet mask in host order */
1000 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1001 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1002 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1005 myNet = myAddr & netMask;
1006 mySubnet = myAddr & subnetmask;
1008 if ( (serverAddr & netMask ) == myNet ) {
1009 if ( (serverAddr & subnetmask ) == mySubnet) {
1010 if ( serverAddr == myAddr ) { /* same machine */
1011 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1012 } else { /* same subnet */
1013 sa->sa_iprank = afs_min(sa->sa_iprank, HI);
1015 } else { /* same net */
1016 sa->sa_iprank = afs_min(sa->sa_iprank, MED);
1020 #else /* AFS_USERSPACE_IP_ADDR */
1021 #if (! defined(AFS_SUN5_ENV)) && !defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1022 void afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
1024 struct sockaddr_in *sin;
1027 if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1028 if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1030 if ( SA2ULONG(sin) == ntohl(sa->sa_ip)) { /* ie, ME!!! */
1031 sa->sa_iprank = TOPR;
1033 t = HI + ifa->ia_ifp->if_metric; /* case #2 */
1034 if (sa->sa_iprank > t)
1038 t = MED + ifa->ia_ifp->if_metric;/* case #3 */
1039 if (sa->sa_iprank > t)
1043 #ifdef IFF_POINTTOPOINT
1044 /* check for case #4 -- point-to-point link */
1045 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1046 (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1047 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1050 t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1051 if (sa->sa_iprank > t)
1054 #endif /* IFF_POINTTOPOINT */
1056 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1057 #if defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1059 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
1062 afsi_SetServerIPRank(sa, ifa)
1066 struct sockaddr_in *sin;
1069 afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
1070 afs_uint32 serverAddr ;
1072 if (ifa->ifa_addr->sa_family != AF_INET)
1074 sin=(struct sockaddr_in *)ifa->ifa_addr;
1075 myAddr = ntohl(sin->sin_addr.s_addr); /* one of my IP addr in host order */
1076 serverAddr = ntohl(sa->sa_ip); /* server's IP addr in host order */
1077 sin=(struct sockaddr_in *)ifa->ifa_netmask;
1078 subnetmask = ntohl(sin->sin_addr.s_addr);/* subnet mask in host order */
1079 sin=(struct sockaddr_in *)ifa->ifa_dstaddr;
1081 myDstaddr=sin->sin_addr.s_addr;
1083 if ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
1084 else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
1085 else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
1088 myNet = myAddr & netMask;
1089 mySubnet = myAddr & subnetmask;
1091 if ( (serverAddr & netMask ) == myNet ) {
1092 if ( (serverAddr & subnetmask ) == mySubnet) {
1093 if ( serverAddr == myAddr ) { /* same machine */
1094 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1095 } else { /* same subnet */
1096 sa->sa_iprank = afs_min(sa->sa_iprank, HI + ifa->ifa_metric);
1098 } else { /* same net */
1099 sa->sa_iprank = afs_min(sa->sa_iprank, MED + ifa->ifa_metric);
1102 #ifdef IFF_POINTTOPOINT
1103 /* check for case #4 -- point-to-point link */
1104 if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT) &&
1105 (myDstaddr == serverAddr))) {
1106 if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1109 t = MED + (PPWEIGHT << ifa->->ifa_metric);
1110 if (sa->sa_iprank > t)
1113 #endif /* IFF_POINTTOPOINT */
1115 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR)*/
1116 #endif /* else AFS_USERSPACE_IP_ADDR */
1118 #ifdef AFS_SGI62_ENV
1120 afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1123 afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr*)h);
1124 return 0; /* Never match, so we enumerate everyone */
1126 #endif /* AFS_SGI62_ENV */
1128 static int afs_SetServerPrefs(struct srvAddr *sa)
1130 #if defined(AFS_USERSPACE_IP_ADDR)
1134 for (i=0; i<afs_cb_interface.numberOfInterfaces; i++) {
1135 afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1136 afs_cb_interface.subnetmask[i]);
1138 #else /* AFS_USERSPACE_IP_ADDR */
1139 #if defined(AFS_SUN5_ENV)
1140 extern struct ill_s *ill_g_headp;
1143 int subnet, subnetmask, net, netmask;
1144 long *addr = (long *) ill_g_headp;
1146 if (sa) sa->sa_iprank= 0;
1147 for (ill = (struct ill_s *)*addr /*ill_g_headp*/; ill; ill = ill->ill_next ) {
1148 #ifdef AFS_SUN58_ENV
1149 /* Make sure this is an IPv4 ILL */
1150 if (ill->ill_isv6) continue;
1152 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next ) {
1153 subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1154 subnetmask = ipif->ipif_net_mask;
1156 * Generate the local net using the local address and
1157 * whate we know about Class A, B and C networks.
1159 if (IN_CLASSA(ipif->ipif_local_addr)) {
1160 netmask = IN_CLASSA_NET;
1161 } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1162 netmask = IN_CLASSB_NET;
1163 } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1164 netmask = IN_CLASSC_NET;
1168 net = ipif->ipif_local_addr & netmask;
1171 if (ipif->ipif_local_addr != 0x7f000001) { /* ignore loopback */
1173 if (*cnt > 16) return;
1174 *addrp++ = ipif->ipif_local_addr;
1179 /* XXXXXX Do the individual ip ranking below XXXXX */
1180 if ((sa->sa_ip & netmask) == net) {
1181 if ((sa->sa_ip & subnetmask) == subnet) {
1182 if (ipif->ipif_local_addr == sa->sa_ip) { /* ie, ME! */
1183 sa->sa_iprank = TOPR;
1185 sa->sa_iprank = HI + ipif->ipif_metric; /* case #2 */
1188 sa->sa_iprank = MED + ipif->ipif_metric; /* case #3 */
1191 sa->sa_iprank = LO + ipif->ipif_metric; /* case #4 */
1193 /* check for case #5 -- point-to-point link */
1194 if ((ipif->ipif_flags & IFF_POINTOPOINT) &&
1195 (ipif->ipif_pp_dst_addr == sa->sa_ip )) {
1197 if (ipif->ipif_metric >= (MAXDEFRANK - MED)/PPWEIGHT)
1198 sa->sa_iprank = MAXDEFRANK;
1200 sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1207 struct ifnet *ifn = NULL;
1208 struct in_ifaddr *ifad = (struct in_ifaddr *) 0;
1209 struct sockaddr_in *sin;
1212 #ifdef notdef /* clean up, remove this */
1213 for (ifn = ifnet; ifn != NULL; ifn = ifn->if_next) {
1214 for (ifad = ifn->if_addrlist; ifad != NULL; ifad = ifad->ifa_next){
1215 if ((IFADDR2SA(ifad)->sa_family == AF_INET)
1216 && !(ifn->if_flags & IFF_LOOPBACK)) {
1218 if (*cnt > 16) return;
1219 *addrp++ = ((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr;
1228 ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1230 if (ifn) { /* local, more or less */
1232 if (ifn->if_flags & IFF_LOOPBACK) {
1233 sa->sa_iprank = TOPR;
1236 #endif /* IFF_LOOPBACK */
1237 sin = (struct sockaddr_in *) IA_SIN(ifad);
1238 if (SA2ULONG(sin) == sa->sa_ip) {
1239 sa->sa_iprank = TOPR;
1242 #ifdef IFF_BROADCAST
1243 if (ifn->if_flags & IFF_BROADCAST) {
1244 if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1249 #endif /* IFF_BROADCAST */
1250 #ifdef IFF_POINTOPOINT
1251 if (ifn->if_flags & IFF_POINTOPOINT) {
1252 if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1253 if (ifn->if_metric > 4) {
1257 else sa->sa_iprank = ifn->if_metric;
1260 #endif /* IFF_POINTOPOINT */
1261 sa->sa_iprank += MED + ifn->if_metric; /* couldn't find anything better */
1264 #else /* USEIFADDR */
1266 if (sa) sa->sa_iprank= LO;
1267 #ifdef AFS_SGI62_ENV
1268 (void) hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1270 #elif defined(AFS_DARWIN60_ENV)
1274 TAILQ_FOREACH(ifn , &ifnet, if_link) {
1275 TAILQ_FOREACH(ifa , &ifn->if_addrhead, ifa_link) {
1276 afsi_SetServerIPRank(sa, ifa);
1280 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1282 struct in_ifaddr *ifa;
1283 TAILQ_FOREACH(ifa , &in_ifaddrhead, ia_link) {
1284 afsi_SetServerIPRank(sa, ifa);
1287 #elif defined(AFS_OBSD_ENV)
1289 extern struct in_ifaddrhead in_ifaddr;
1290 struct in_ifaddr *ifa;
1291 for (ifa = in_ifaddr.tqh_first; ifa; ifa = ifa->ia_list.tqe_next)
1292 afsi_SetServerIPRank(sa, ifa);
1296 struct in_ifaddr *ifa;
1297 for ( ifa = in_ifaddr; ifa; ifa = ifa->ia_next ) {
1298 afsi_SetServerIPRank(sa, ifa);
1304 #endif /* USEIFADDR */
1305 #endif /* AFS_SUN5_ENV */
1306 #endif /* else AFS_USERSPACE_IP_ADDR */
1308 if (sa) sa->sa_iprank += afs_randomMod15();
1311 } /* afs_SetServerPrefs */
1319 /* afs_FlushServer()
1320 * The addresses on this server struct has changed in some way and will
1321 * clean up all other structures that may reference it.
1322 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1324 void afs_FlushServer(struct server *srvp)
1327 struct server *ts, **pts;
1329 /* Find any volumes residing on this server and flush their state */
1330 afs_ResetVolumes(srvp);
1332 /* Flush all callbacks in the all vcaches for this specific server */
1333 afs_FlushServerCBs(srvp);
1335 /* Remove all the callbacks structs */
1337 struct afs_cbr *cb, *cbnext;
1339 MObtainWriteLock(&afs_xvcb, 300);
1340 for (cb=srvp->cbrs; cb; cb=cbnext) {
1344 srvp->cbrs = (struct afs_cbr *)0;
1345 ReleaseWriteLock(&afs_xvcb);
1348 /* If no more srvAddr structs hanging off of this server struct,
1352 /* Remove the server structure from the cell list - if there */
1353 afs_RemoveCellEntry(srvp);
1355 /* Remove from the afs_servers hash chain */
1356 for (i=0; i<NSERVERS; i++) {
1357 for (pts=&(afs_servers[i]), ts=*pts; ts; pts=&(ts->next), ts=*pts) {
1358 if (ts == srvp) break;
1363 *pts = ts->next; /* Found it. Remove it */
1364 afs_osi_Free(ts, sizeof(struct server)); /* Free it */
1370 /* afs_RemoveSrvAddr()
1371 * This removes a SrvAddr structure from its server structure.
1372 * The srvAddr struct is not free'd because it connections may still
1373 * be open to it. It is up to the calling process to make sure it
1374 * remains connected to a server struct.
1375 * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1376 * It is not removed from the afs_srvAddrs hash chain.
1378 void afs_RemoveSrvAddr(struct srvAddr *sap)
1380 struct srvAddr **psa, *sa;
1386 /* Find the srvAddr in the server's list and remove it */
1387 for (psa=&(srv->addr), sa=*psa; sa; psa=&(sa->next_sa), sa=*psa) {
1388 if (sa == sap) break;
1395 /* Flush the server struct since it's IP address has changed */
1396 afs_FlushServer(srv);
1401 * Return an updated and properly initialized server structure
1402 * corresponding to the server ID, cell, and port specified.
1403 * If one does not exist, then one will be created.
1404 * aserver and aport must be in NET byte order.
1406 struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
1407 afs_int32 acell, u_short aport,
1408 afs_int32 locktype, afsUUID *uuidp,
1409 afs_int32 addr_uniquifier)
1411 struct server *oldts=0, *ts, *newts, *orphts=0;
1412 struct srvAddr *oldsa, *newsa, *nextsa, *orphsa;
1414 afs_int32 iphash, k, srvcount=0;
1415 unsigned int srvhash;
1417 AFS_STATCNT(afs_GetServer);
1419 ObtainSharedLock(&afs_xserver,13);
1421 /* Check if the server struct exists and is up to date */
1423 if (nservers != 1) panic("afs_GetServer: incorect count of servers");
1424 ObtainReadLock(&afs_xsrvAddr);
1425 ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1426 ReleaseReadLock(&afs_xsrvAddr);
1427 if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1428 /* Found a server struct that is not multihomed and has the
1429 * IP address associated with it. A correct match.
1431 ReleaseSharedLock(&afs_xserver);
1435 if (nservers <= 0) panic("afs_GetServer: incorrect count of servers");
1436 ts = afs_FindServer(0, aport, uuidp, locktype);
1437 if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1438 /* Found a server struct that is multihomed and same
1439 * uniqufier (same IP addrs). The above if statement is the
1440 * same as in InstallUVolumeEntry().
1442 ReleaseSharedLock(&afs_xserver);
1445 if (ts) oldts = ts; /* Will reuse if same uuid */
1448 UpgradeSToWLock(&afs_xserver,36);
1449 ObtainWriteLock(&afs_xsrvAddr,116);
1451 srvcount = afs_totalServers;
1453 /* Reuse/allocate a new server structure */
1457 newts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1458 if (!newts) panic("malloc of server struct");
1460 memset((char *)newts, 0, sizeof(struct server));
1462 /* Add the server struct to the afs_servers[] hash chain */
1463 srvhash = (uuidp ? (afs_uuid_hash(uuidp)%NSERVERS) : SHash(aserverp[0]));
1464 newts->next = afs_servers[srvhash];
1465 afs_servers[srvhash] = newts;
1468 /* Initialize the server structure */
1469 if (uuidp) { /* Multihomed */
1470 newts->sr_uuid = *uuidp;
1471 newts->sr_addr_uniquifier = addr_uniquifier;
1472 newts->flags |= SRVR_MULTIHOMED;
1474 if (acell) newts->cell = afs_GetCell(acell, 0);
1476 fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
1478 /* For each IP address we are registering */
1479 for (k=0; k<nservers; k++) {
1480 iphash = SHash(aserverp[k]);
1482 /* Check if the srvAddr structure already exists. If so, remove
1483 * it from its server structure and add it to the new one.
1485 for (oldsa=afs_srvAddrs[iphash]; oldsa; oldsa=oldsa->next_bkt) {
1486 if ( (oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport) ) break;
1488 if (oldsa && (oldsa->server != newts)) {
1489 afs_RemoveSrvAddr(oldsa); /* Remove from its server struct */
1490 oldsa->next_sa = newts->addr; /* Add to the new server struct */
1491 newts->addr = oldsa;
1494 /* Reuse/allocate a new srvAddr structure */
1498 newsa = (struct srvAddr *) afs_osi_Alloc(sizeof(struct srvAddr));
1499 if (!newsa) panic("malloc of srvAddr struct");
1500 afs_totalSrvAddrs++;
1501 memset((char *)newsa, 0, sizeof(struct srvAddr));
1503 /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1504 newsa->next_bkt = afs_srvAddrs[iphash];
1505 afs_srvAddrs[iphash] = newsa;
1507 /* Hang off of the server structure */
1508 newsa->next_sa = newts->addr;
1509 newts->addr = newsa;
1511 /* Initialize the srvAddr Structure */
1512 newsa->sa_ip = aserverp[k];
1513 newsa->sa_portal = aport;
1516 /* Update the srvAddr Structure */
1517 newsa->server = newts;
1518 if (newts->flags & SRVR_ISDOWN)
1519 newsa->sa_flags |= SRVADDR_ISDOWN;
1520 if (uuidp) newsa->sa_flags |= SRVADDR_MH;
1521 else newsa->sa_flags &= ~SRVADDR_MH;
1523 /* Compute preference values and resort */
1524 if (!newsa->sa_iprank) {
1525 if (aport == fsport) {
1526 afs_SetServerPrefs(newsa); /* new fileserver rank */
1528 newsa->sa_iprank = 10000 + afs_randomMod127(); /* new vlserver rank */
1532 afs_SortOneServer(newts); /* Sort by rank */
1534 /* If we reused the server struct, remove any of its srvAddr
1535 * structs that will no longer be associated with this server.
1537 if (oldts) { /* reused the server struct */
1538 for (orphsa=newts->addr; orphsa; orphsa=nextsa) {
1539 nextsa = orphsa->next_sa;
1540 for (k=0; k<nservers; k++) {
1541 if (orphsa->sa_ip == aserverp[k]) break; /* belongs */
1543 if (k < nservers) continue; /* belongs */
1545 /* Have a srvAddr struct. Now get a server struct (if not already) */
1547 orphts = (struct server *) afs_osi_Alloc(sizeof(struct server));
1548 if (!orphts) panic("malloc of lo server struct");
1549 memset((char *)orphts, 0, sizeof(struct server));
1552 /* Add the orphaned server to the afs_servers[] hash chain.
1553 * Its iphash does not matter since we never look up the server
1554 * in the afs_servers table by its ip address (only by uuid -
1555 * which this has none).
1557 iphash = SHash(aserverp[k]);
1558 orphts->next = afs_servers[iphash];
1559 afs_servers[iphash] = orphts;
1561 if (acell) orphts->cell = afs_GetCell(acell, 0);
1564 /* Hang the srvAddr struct off of the server structure. The server
1565 * may have multiple srvAddrs, but it won't be marked multihomed.
1567 afs_RemoveSrvAddr(orphsa); /* remove */
1568 orphsa->next_sa = orphts->addr; /* hang off server struct */
1569 orphts->addr = orphsa;
1570 orphsa->server = orphts;
1571 orphsa->sa_flags |= SRVADDR_NOUSE; /* flag indicating not in use */
1572 orphsa->sa_flags &= ~SRVADDR_MH; /* Not multihomed */
1576 srvcount = afs_totalServers - srvcount; /* # servers added and removed */
1578 struct afs_stats_SrvUpDownInfo *upDownP;
1579 /* With the introduction of this new record, we need to adjust the
1580 * proper individual & global server up/down info.
1582 upDownP = GetUpDownStats(newts);
1583 upDownP->numTtlRecords += srvcount;
1584 afs_stats_cmperf.srvRecords += srvcount;
1585 if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1586 afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1589 ReleaseWriteLock(&afs_xsrvAddr);
1590 ReleaseWriteLock(&afs_xserver);
1592 } /* afs_GetServer */
1594 void afs_ActivateServer(struct srvAddr *sap)
1596 osi_timeval_t currTime; /*Filled with current time*/
1597 osi_timeval_t *currTimeP; /*Ptr to above*/
1598 struct afs_stats_SrvUpDownInfo *upDownP; /*Ptr to up/down info record*/
1599 struct server *aserver = sap->server;
1601 if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1603 * This server record has not yet been activated. Go for it,
1604 * recording its ``birth''.
1606 aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1607 currTimeP = &currTime;
1608 osi_GetuTime(currTimeP);
1609 aserver->activationTime = currTime.tv_sec;
1610 upDownP = GetUpDownStats(aserver);
1611 if (aserver->flags & SRVR_ISDOWN) {
1612 upDownP->numDownRecords++;
1614 upDownP->numUpRecords++;
1615 upDownP->numRecordsNeverDown++;