home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * $Header: ~eden/Kernel/DataStructs/bootKernel.c Rev. 1.0 11-Jun-85$
- *
- * $Log:$
- * Revision 2.0 June 1986 eric
- * Modified extensively for Emerald.
- *
- * Revision 1.0 11-Jun-85 oystr
- * Routines which perform the kernel boot protocol. Derived from
- * the original which was in initHots.c.
- *
- */
-
- #include <stdio.h>
- #include "Kernel/h/timerTypes.h"
-
- #ifdef xkernel
- #include "userupi.h"
- #endif
-
- #include "Kernel/h/system.h"
- #include "Kernel/h/assert.h"
- #include "Kernel/h/stdTypes.h"
- #include "Kernel/h/mmCodes.h"
- #include "Kernel/h/errMsgs.h"
- #include "Kernel/h/mmTypes.h"
- #include "Kernel/h/mmMsgTypes.h"
- #include "Kernel/h/kBootCodes.h"
- #include "Kernel/h/kEvents.h"
- #include "Kernel/h/dstCodes.h"
- #include "Kernel/h/hotsTypes.h"
- #include "Kernel/h/kBootTypes.h"
- #include "Kernel/h/kmdTypes.h"
-
- extern void AddHOTS(), ChangeHOTS();
-
- extern KKStatus HOTSSearchPtr();
- extern time_t nodeIncarnationId;
- extern char *mGetHostName();
- extern EtherNetAddress MMLocalEtherNet;
- extern long random();
- extern char *ctime();
-
- /* Forward declaration of snapshot */
- /* Forward */ void SendAlive();
-
- /*
- * Time to wait (in seconds) for replies to our broadcast
- * announcement that we are booting.
- */
-
- #define STARTWAIT 4
-
- /*
- * Global copy of node characteristics bit map.
- */
- BitMap32 MyNodeType;
-
- /*
- * "forward" declarations for Message Handlers.
- */
- HResult StartUpHandler(), ShutDownHandler(),
- SendStartUp(), BcastHandler();
-
- /***********************************************************************/
-
- BootKernel(nodetype)
- BitMap32 nodetype;
- {
- extern int srandom();
- TimerId dummy;
-
- KMDSetSnap(SendAlive);
-
- MyNodeType = nodetype;
-
- /*
- * Get ready to handle all those replies we expect to our broadcast.
- * Also handle startup messages from other booting nodes.
- */
- MMDefineMsgHandler(KMSG_Boot, BOOTM_Reply, (HandlerPtr) StartUpHandler,
- (HandlerPtr *)NULL);
- MMDefineMsgHandler(KMSG_Boot, BOOTM_StartUp, (HandlerPtr)StartUpHandler,
- (HandlerPtr *)NULL);
- MMDefineMsgHandler(KMSG_Boot, BOOTM_ShutDown, (HandlerPtr)ShutDownHandler,
- (HandlerPtr *)NULL);
- MMDefineMsgHandler(KMSG_Boot, BOOTM_Broadcast, (HandlerPtr) BcastHandler,
- (HandlerPtr *)NULL);
-
- /*
- * Initialize our BackOff generator.
- */
- #ifdef xsimul
- srandom( (int)(getpid() ^ time((time_t *) 0)) );
- #else
- srandom( (int)(314 ^ time((time_t *) 0)) ); /* anyone for some pi? */
- #endif
- /*
- * Put ourselves in the HOTS.
- * MM will fill in ethernet address (FIXME - a dangerous assumption).
- *
- */
- DebugMsg(5, "adding self to hots\n");
- AddHOTS(MMLocalEtherNet, GetLNN(), nodetype, Booting,
- nodeIncarnationId);
-
- /*
- * Send out a broadcast describing ourselves, and asking for
- * information about other nodes.
- */
- DebugMsg(5, "Sending boot message\n");
- SendBootMsg(GetLNN(), NULLNODE, MMLocalEtherNet,
- MyNodeType, (MessageSubtype) BOOTM_Broadcast);
-
- /*
- * After a suitable delay, send out the startup message.
- */
- MMSetTimer(STARTWAIT, (HandlerPtr)SendStartUp, 0, &dummy);
- }
-
- /***********************************************************************/
-
- HResult SendStartUp()
- {
- /*
- * Change ourselves from Booting to Alive.
- */
- ChangeHOTS(GetLNN(), Alive);
- printf(" Kernel fully booted.\n");
-
- /*
- * Send out a StartUp message, to tell everyone we've finished
- * booting.
- */
- SendBootMsg(GetLNN(), NULLNODE, MMLocalEtherNet,
- MyNodeType, (MessageSubtype) BOOTM_StartUp);
- }
-
- /***********************************************************************/
- /* Routine to Broadcast a message saying that I am alive. */
- /***********************************************************************/
-
- HResult SendAliveMsg()
- {
- KMDTrace("HOTSUpDown", 3, "Broadcasting Alive: LNN %d of %.15s\n",
- GetLNN(), 4+ctime(&nodeIncarnationId));
- SendBootMsg(GetLNN(), NULLNODE, MMLocalEtherNet, MyNodeType,
- (MessageSubtype) BOOTM_StartUp);
- }
-
- /***********************************************************************/
- /* Snapshot to Broadcast a message saying that I am alive. */
- /***********************************************************************/
- /* Snapshot */
- void SendAlive()
- {
- SendAliveMsg();
- }
-
- /***********************************************************************
- * Routine to send out a broadcast telling an imposter to die.
- * Retransmistted to ensure that it gets through
- */
-
- void KillImposter( fMsg )
- MessagePtr fMsg;
- {
- EtherNetAddress theEtherAddr;
-
- bcopy((char *)&fMsg->MsgHdr.SrcSinAddr, (char *)&theEtherAddr.sin_addr, 4);
-
- /* Kill the imposter by sending out an I am alive broadcast */
- KMDTrace("HOTSUpDown",4,"Sending Alive msg to imposter LNN %d of %.15s at %s\n",
- fMsg->MsgHdr.MsgSrc, 4+ctime(&fMsg->MsgHdr.SrcIncarnationId),
- mGetHostName(& theEtherAddr));
-
- SendBootMsg(GetLNN(), NULLNODE, MMLocalEtherNet, MyNodeType,
- (MessageSubtype) BOOTM_StartUp);
-
- /* Set a couple of timers so that we are sure to get him */
- MMSetMicroTimer(1, 0, (HandlerPtr)SendAliveMsg, 0, (TimerId *)NULL);
- MMSetMicroTimer(5, 0, (HandlerPtr)SendAliveMsg, 0, (TimerId *)NULL);
- }
-
- /***********************************************************************
- * Generate a "random" waiting time before we respond to a node's
- * booting message. We don't want to overwhelm the node with replies.
- */
-
- integer BackOff()
- {
- integer result;
- assert(STARTWAIT > 2);
- result = ((integer) random() & 0x7FFFFFF) % (1000000 *( STARTWAIT - 2));
- return( result+200 );
- }
-
- /***********************************************************************/
-
- /*ARGSUSED*/
- HResult SendBootReply( fNewNode, fTimerId )
- NodeNum fNewNode;
- integer fTimerId;
- {
- KMDTrace("HOTSUpDown", 4, "Replying to node %08x boot msg.\n",fNewNode);
- SendBootMsg( GetLNN(), fNewNode, MMLocalEtherNet,
- MyNodeType, (MessageSubtype) BOOTM_Reply);
- }
-
- /***********************************************************************/
- /*
- * Send out a reply to a bootup broadcast message.
- */
- HResult BcastHandler(fMsg)
- GenericKBootMsg *fMsg;
- {
- BootMsg *bmp;
- integer delay;
- KKStatus lStatus;
- TimerId dummy;
-
- bmp = &fMsg->Msgunion.Boot;
-
- KMDTrace("HOTSUpDown", 4, "BcastHandler: node %d booting, incarnationId %.15s\n",
- bmp->nodenum, 4+ctime(&fMsg->MsgHead.SrcIncarnationId));
-
- AddHOTS(bmp->nodeaddr, bmp->nodenum, bmp->nodetype, Booting,
- fMsg->MsgHead.SrcIncarnationId);
-
- /*
- * Don't deluge the booting node with a lot of replies at
- * the same time. Try to distrubute them a little more
- * randomly.
- */
- delay = BackOff();
- lStatus = MMSetMicroTimer( (int)(delay/1000000), (int)(delay % 1000000),
- (HandlerPtr)SendBootReply, bmp->nodenum, &dummy );
- if ( ! mSUCCESS( lStatus ) ) {
- ErrMsg("Can't set boot backoff: %08x.\n",lStatus);
- SendBootMsg(GetLNN(), bmp->nodenum, MMLocalEtherNet,
- MyNodeType, (MessageSubtype) BOOTM_Reply);
- } else
- KMDTrace("HOTSUpDown", 5, "Boot reply delay: %d.\n",delay);
-
- /*
- * Should also send info about other nodes we know about here.
- */
- MMDeallocateMsg((MessagePtr)fMsg);
- }
-
- /***********************************************************************/
- /* Send a boot reply to someone we just declared to be up */
- /***********************************************************************/
- void ScheduleBootReply(fLNN)
- NodeNum fLNN;
- {
- int delay;
- TimerId dummy;
- KKStatus lStatus;
-
- /*
- * Don't deluge the booting node with a lot of replies at
- * the same time. Try to distrubute them a little more
- * randomly.
- */
- delay = BackOff();
- lStatus = MMSetMicroTimer( (int)(delay/1000000), (int)(delay % 1000000),
- (HandlerPtr)SendBootReply, fLNN, &dummy );
- if ( ! mSUCCESS( lStatus ) ) {
- ErrMsg("Can't set boot backoff: %08x.\n",lStatus);
- SendBootMsg(GetLNN(), fLNN, MMLocalEtherNet,
- MyNodeType, (MessageSubtype) BOOTM_Reply);
- }
- else
- KMDTrace("HOTSUpDown", 5, "Boot reply delay: %d.\n",delay);
- }
-
-
-
- /***********************************************************************/
- /*
- * Add a node to the HOTS as a result of getting a startup message.
- * Note that this message is broadcast and we rely on the fact that
- * the message module filters out our own broadcasts (which we WILL
- * receive).
- */
-
- HResult StartUpHandler(fMsg)
- GenericKBootMsg *fMsg;
- {
- BootMsg *bmp;
- HOTSRecord *hp;
-
- bmp = &fMsg->Msgunion.Boot;
-
- KMDTrace("HOTSUpDown",4,"StartUpHandler: node %d now Alive\n", bmp->nodenum);
-
- if ( ( fMsg->MsgHead.MsgSubtype == BOOTM_Reply )
- && (bmp->nodenum == GetLNN()) ) {
- /*
- * Make sure we aren't trying to impersonate somebody
- * else.
- */
- ErrMsg(">>> Boot Panic - Duplicate LNN %04x.\n", bmp->nodenum);
- ErrMsg(">>> I'm @ %s\n",
- mGetHostName((EtherNetAddress *) &MMLocalEtherNet.sin_addr));
- ErrMsg(">>> It's @ %s\n",
- mGetHostName((EtherNetAddress *) &bmp->nodeaddr));
- ErrMsg(">>> Detected by LNN %d.\n",fMsg->MsgHead.MsgSrc);
- ErrMsg(">>> Duplicate node during boot protocol...\n");
- ErrMsg(">>> Shutting down.\n");
- exit( 1 );
- }
-
- if ( mSUCCESS( HOTSSearchPtr(bmp->nodenum, &hp) ) &&
- hp->NodeStat == Booting ) {
- /* The node is going from Booting to Alive. */
- ChangeHOTS(hp->LNN, Alive);
- } else {
- /* We missed the booting msg and/or a shutdown msg. */
- AddHOTS(bmp->nodeaddr, bmp->nodenum, bmp->nodetype, Alive,
- fMsg->MsgHead.SrcIncarnationId);
- };
- MMDeallocateMsg((MessagePtr)fMsg);
- }
-
- /***********************************************************************/
- /*
- * Mark a node dead as a result of getting a shutdown message.
- * Also call other routines interested in knowing about node death.
- */
- HResult ShutDownHandler(fMsg)
- GenericKBootMsg *fMsg;
- {
- BootMsg *bmp;
-
- bmp = &fMsg->Msgunion.Boot;
- KMDTrace("HOTSUpDown", 4, "ShutDownHandler: node %d shutting down\n", bmp->nodenum);
- ChangeHOTS(bmp->nodenum, Dead);
- MMDeallocateMsg((MessagePtr)fMsg);
- }
-
- /***********************************************************************/
- /*
- * Broadcast a shutdown message. Called by main when a crash is imminent.
- */
- SendShutDownMsg(fLNN)
- NodeNum fLNN;
- {
- SendBootMsg(fLNN, NULLNODE, MMLocalEtherNet,
- MyNodeType, (MessageSubtype) BOOTM_ShutDown);
- }
-
- /***********************************************************************/
- /*
- * Send out a boot message. "From" is not necessarily us, if we have
- * knowledge of some other node.
- */
-
- /*ARGSUSED*/
- static SendBootMsg(from, to, nodeaddr, nodetype, mtype)
- NodeNum from, to;
- EtherNetAddress nodeaddr;
- BitMap32 nodetype;
- MessageSubtype mtype;
- {
- GenericKBootMsg *fMsg;
- BootMsg *bmp;
-
- (void) MMAllocateMsg(sizeof( BootMsg ), (MessagePtr *)&fMsg);
- bmp = &fMsg->Msgunion.Boot;
- mEtherCopy(&nodeaddr, &(bmp->nodeaddr));
- bmp->nodenum = from;
- bmp->nodetype = MyNodeType;
- MMBuildMsg((MessagePtr)fMsg, KMSG_Boot, mtype, to, sizeof( BootMsg) );
- if (to == NULLNODE)
- (void) MMBroadcastMsg((MessagePtr) fMsg);
- else
- (void) MMSendMsg((MessagePtr) fMsg);
- MMDeallocateMsg((MessagePtr)fMsg);
- }
-
- #ifdef DEFUNCT
-
- /****************************************************************
- * Handle Node Status Requests *
- * This code is pretty much defunct. It used to be used by *
- * the old 'whatsup' utility. *
- ****************************************************************/
-
- HOTSRecord *HOTSTraverse();
-
- StatusHandler( fMsg )
- GenericKBootMsg *fMsg;
- {
- NetStatusMsg *nsmPtr;
- GenericKBootMsg fullReply;
- NetStatReplyMsg *statReply;
- integer hIndex;
- integer hPlace;
- HOTSRecord *hEntry;
- EdenPort replyPort;
- integer nIndex;
- KKStatus lStatus;
-
- hPlace = 0;
- hIndex = -1;
- nIndex = 0;
- statReply = &fullReply.Msgunion.NetStatReply;
- statReply->nodesIknow[0].thisNode = NULLNODE;
- nsmPtr = &fMsg->Msgunion.NetStatus;
- KMDTrace("HOTSUpDown", 5,"Received BOOTM_NetStatus.\n");
- MMBuildMsg(&fullReply, KMSG_Boot, BOOTM_NetStatReply, GetLNN(),
- sizeof( NetStatReplyMsg ) );
-
- while ( ( (hEntry = HOTSTraverse( &hIndex, &hPlace ) ) != NULL )
- && (nIndex < NODESPERSTATMSG) ) {
- statReply->nodesIknow[nIndex].thisNode = hEntry->LNN;
- statReply->nodesIknow[nIndex].statTime = hEntry->LastMsgTs;
- mEtherCopy(&(hEntry->EtherAddr),
- &(statReply->nodesIknow[nIndex].netAddr));
- statReply->nodesIknow[nIndex].thisStat = hEntry->NodeStat;
- nIndex++;
- }
- if ( nIndex < NODESPERSTATMSG )
- statReply->nodesIknow[nIndex].thisNode = NULLNODE;
-
- lStatus = MMConnectPort(nsmPtr->replyTo, &replyPort);
- if ( !mSUCCESS( lStatus ) ) {
- KMDTrace("HOTSUpDown", 2, "Can't connect to NetStat reply port (%08x): %s.\n",
- lStatus, nsmPtr->replyTo);
- goto exit_label;
- }
- lStatus = MMSendSynchMsg( replyPort, &fullReply, NULL );
- if ( !mSUCCESS( lStatus ) ) {
- KMDTrace("HOTSUpDown", 2,"Can't send NetStat reply (%08x): %s.\n",
- lStatus, nsmPtr->replyTo);
- }
- exit_label:
- (void) MMDeallocateMsg( fMsg );
- }
- #endif DEFUNCT
-