-- File: PupRouterCold.mesa - last edit:
-- AOF 30-Jul-85 15:07:51
-- HGM 26-Nov-85 1:36:07
-- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved.
DIRECTORY
Buffer USING [
Buffer, AccessHandle, DataWordsPerPupBuffer, DestroyPool, Enqueue,
GetBuffer, MakePool, Queue, ReturnBuffer, Type],
CommFlags USING [doDebug],
CommHeap USING [zone],
CommunicationInternal USING [CommPackageGo, CommPackageOff],
CommUtil USING [GetEthernetHostNumber],
Driver USING [
ChangeNumberOfInputBuffers, GetInputBuffer, Glitch, Network,
PutOnGlobalDoneQueue, GetDeviceChain],
Frame USING [GetReturnFrame, ReadGlobalLink],
Heap USING [FreeNode, MakeNode],
Process USING [
EnableAborts, SetTimeout, MsecToTicks],
Protocol1 USING [
Action, MatrixRecord, EvictFamily, Family, FamilyUnit,
RegisterFamily, AddFamilyMember],
PupDefs USING [
defaultNumberOfNetworks, SetPupContentsWords, PupRouterBroadcastThis],
PupPktOps,
Pup10MBit USING [Capsulators, Create, Destroy],
PupRouterDefs USING [
PupRouterIn, PupRouterOut, PupChecksums, PupErrors, inThings, outThings,
checksum, routerIsActive, BeSurePupIsOn, Timeout, routingTable,
RoutingTableObject, RoutingTableEntry, GetRoutingTableEntry, ContextObject,
dataWordsPerPup, maxHop, PupInputer, PupBroadcaster, NetworkContext],
PupStream USING [],
PupTypes USING [PupHostID, gatewaySoc];
PupRouterCold: MONITOR LOCKS routerLock
IMPORTS
Frame, Heap, Process, Buffer, CommunicationInternal, CommUtil, Driver,
PupDefs, Pup10MBit, PupRouterDefs, Protocol1, CommHeap
EXPORTS Buffer, PupStream, PupDefs, PupRouterDefs, PupPktOps = PUBLIC
BEGIN
OPEN PupRouterDefs;
FreeQueueNotInitialized: ERROR = CODE;
QueueSealBroken: ERROR = CODE;
Network: PUBLIC TYPE = Driver.Network;
routerLock: PUBLIC MONITORLOCK;
routingTableUpdateTimeout: PUBLIC CONDITION;
probeResponse: PUBLIC CONDITION;
numberOfNetworks: PUBLIC CARDINAL ← PupDefs.defaultNumberOfNetworks;
pupUseCount: CARDINAL ← 0;
routerTimeoutFork: PROCESS;
pupBuffersToAllocate: CARDINAL ← 15;
pupBuffers: PUBLIC Buffer.AccessHandle ← NIL; -- For the entire pup package.
doDebug: BOOLEAN = CommFlags.doDebug;
pupProtocolFamily: PUBLIC Protocol1.FamilyUnit ← [
name: pup, status: dead, spy: NIL, state: NIL,
receive: PupInputer, broadcast: PupBroadcaster,
stateChanged: PupStateChanged];
CantChangeBuffersWhenActive: PUBLIC ERROR = CODE;
AdjustBufferParms: PUBLIC PROC[bufferPoolSize: CARDINAL] =
BEGIN
IF doDebug AND pupUseCount # 0 THEN
Driver.Glitch[CantChangeBuffersWhenActive];
IF bufferPoolSize # 0 THEN pupBuffersToAllocate ← bufferPoolSize;
END;
GetClumpOfPupBuffers: PUBLIC ENTRY PROC[
q: Buffer.Queue, n: CARDINAL, wait: BOOLEAN] =
BEGIN
ENABLE UNWIND => NULL;
b: Buffer.Buffer;
IF doDebug THEN
SELECT TRUE FROM
(pupUseCount = 0) => Driver.Glitch[FreeQueueNotInitialized];
(q.seal # queueSeal) => Driver.Glitch[QueueSealBroken];
ENDCASE;
THROUGH [0..n) DO
b ← Driver.GetInputBuffer[wait]; -- get a buffer without accounting.
IF b = NIL THEN EXIT;
b.type ← pup;
b.pup.pupType ← data;
IF CommFlags.doDebug THEN
b.debug ← Frame.ReadGlobalLink[Frame.GetReturnFrame[]];
Buffer.Enqueue[q, b];
ENDLOOP;
END; -- GetClumpOfPupBuffers
PupPackageMake: PUBLIC PROC RETURNS [Protocol1.Family] =
BEGIN
AlreadyStarted: ENTRY PROC RETURNS[BOOLEAN] = INLINE
{RETURN[(pupUseCount ← pupUseCount + 1) > 1]};
ProbeToStartTable: ENTRY PROC = --INLINE
BEGIN
ENABLE UNWIND => NULL;
FOR i: CARDINAL IN [0..10) DO
gotRoutingPup: BOOLEAN ← FALSE;
ProbeForRoutingInfo[];
WAIT probeResponse;
FOR i: CARDINAL IN [0..LENGTH[routing]) DO
IF routing[i].context # NIL AND routing[i].hop # 0 THEN
gotRoutingPup ← TRUE;
ENDLOOP;
IF gotRoutingPup THEN EXIT;
ENDLOOP;
END; --ProbeToStartTable
driver: Network;
matrix: Protocol1.MatrixRecord ← [
family: @pupProtocolFamily, context: NIL,
encapsulator: NIL, decapsulator: NIL];
routing: LONG DESCRIPTOR FOR ARRAY OF RoutingTableObject;
IF AlreadyStarted[] THEN RETURN[@pupProtocolFamily];
CommunicationInternal.CommPackageGo[];
Driver.ChangeNumberOfInputBuffers[TRUE];
routing ← DESCRIPTOR[ -- allocates network zero too
Heap.MakeNode[
z: CommHeap.zone, n: (numberOfNetworks + 1)*SIZE[RoutingTableObject]],
numberOfNetworks + 1];
FOR i: CARDINAL IN [0..LENGTH[routing]) DO
routing[i] ← [net: [i], hop: maxHop + 1, time: 210, route:, context: NIL];
ENDLOOP;
dataWordsPerPup ← Buffer.DataWordsPerPupBuffer[];
pupBuffers ← Buffer.MakePool[send: pupBuffersToAllocate, receive: 0];
routingTable ← routing; routerIsActive ← TRUE;
routerTimeoutFork ← FORK Timeout[];
BEGIN
OPEN context: LOOPHOLE[matrix.context, PupRouterDefs.NetworkContext];
Protocol1.RegisterFamily[@pupProtocolFamily]; --make pup known
FOR driver ← Driver.GetDeviceChain[], driver.next UNTIL driver = NIL DO
IF (driver.device # ethernet) OR ~driver.alive THEN LOOP;
matrix.context ← CommHeap.zone.NEW[PupRouterDefs.ContextObject];
context.protocol ← NIL;
context.pupNetNumber ← 0;
context.network ← driver;
context.pupHostNumber ← CommUtil.GetEthernetHostNumber[];
[matrix.decapsulator, matrix.encapsulator] ← Pup10MBit.Capsulators[];
Protocol1.AddFamilyMember[driver, @matrix];
ENDLOOP;
IF routingTable[0].context = NIL THEN routingTable[0] ← [
net: [0], hop: 0, time: 0, route: [0], context: matrix.context];
END;
pupProtocolFamily.status ← alive;
ProbeToStartTable[];
RETURN[@pupProtocolFamily];
END; --PupPackageMake
ProbeForRoutingInfo: PROC=
BEGIN
b: Buffer.Buffer;
b ← Buffer.GetBuffer[pup, pupBuffers, send, smallBuffer, FALSE];
IF b = NIL THEN RETURN;
b.bypassZeroNet ← FALSE;
b.pup.pupType ← gatewayRequest;
b.pup.pupID ← [0, 0];
b.pup.dest.socket ← b.pup.source.socket ← PupTypes.gatewaySoc;
PupDefs.SetPupContentsWords[b, 0];
PupDefs.PupRouterBroadcastThis[b];
END;
PupPackageDestroy: PUBLIC PROC=
BEGIN
IF doDebug THEN BeSurePupIsOn[];
IF PupPackageDestroyLocked[] THEN RETURN;
WaitTillDispatcherIdle[];
JOIN routerTimeoutFork;
Heap.FreeNode[z: CommHeap.zone, p: BASE[routingTable]];
Buffer.DestroyPool[pupBuffers];
Driver.ChangeNumberOfInputBuffers[FALSE];
CommunicationInternal.CommPackageOff[];
END;
PupPackageDestroyLocked: ENTRY PROC RETURNS [BOOLEAN] = INLINE
BEGIN
IF (pupUseCount ← pupUseCount - 1) # 0 THEN RETURN[TRUE];
pupProtocolFamily.status ← dead; --turn him off
Protocol1.EvictFamily[pup]; --stop dispatcher's access
routerIsActive ← FALSE;
NOTIFY routingTableUpdateTimeout;
RETURN[FALSE];
END;
WaitTillDispatcherIdle: ENTRY PROC=
BEGIN
ENABLE UNWIND => NULL;
hit: BOOLEAN ← FALSE;
arrived: CONDITION;
DispatcherCalledUs: ENTRY PROC[b: Buffer.Buffer] =
BEGIN
ENABLE UNWIND => NULL;
hit ← TRUE;
Buffer.ReturnBuffer[b];
NOTIFY arrived;
END;
b: Buffer.Buffer = Buffer.GetBuffer[pup, pupBuffers, send, smallBuffer];
Process.EnableAborts[@arrived];
b.requeueProcedure ← DispatcherCalledUs;
Driver.PutOnGlobalDoneQueue[b];
UNTIL hit DO WAIT arrived; ENDLOOP;
END;
GetPupPackageUseCount: PUBLIC PROC RETURNS [CARDINAL] =
BEGIN RETURN[pupUseCount]; END;
AddNetworkPup: PROC[driver: Network, context: PupRouterDefs.NetworkContext] =
BEGIN
rte: RoutingTableEntry;
IF context = NIL THEN RETURN;
IF driver.device = ethernet AND context.protocol = NIL THEN
context.protocol ← Pup10MBit.Create[driver, [context.pupHostNumber]];
rte ← GetRoutingTableEntry[[context.pupNetNumber]];
IF rte # NIL AND context.pupNetNumber # 0 THEN
rte↑ ← [
net: [context.pupNetNumber], hop: 0, time: 0,
route: [0], context: context];
rte ← GetRoutingTableEntry[[0]];
IF rte.context = NIL THEN
rte↑ ← [net: [0], hop: 0, time: 0, route: [0], context: context];
END; --AddNetworkPup
RemoveNetworkPup: PROC[driver: Network, context: LONG POINTER] =
BEGIN
OPEN c: LOOPHOLE[context, PupRouterDefs.NetworkContext];
probe: BOOLEAN ← FALSE;
IF ~routerIsActive THEN RETURN; -- Try to avoid ML tangle
FOR i: CARDINAL IN [0..LENGTH[routingTable]) DO
IF routingTable[i].context # context THEN LOOP;
routingTable[i] ← [
net: [i], hop: maxHop + 1, time: 210, route:, context: NIL];
probe ← TRUE;
ENDLOOP;
IF driver.device = ethernet THEN Pup10MBit.Destroy[c.protocol];
IF probe THEN ProbeForRoutingInfo[];
END; --RemoveNetworkPup
PupStateChanged: PROC[
driver: Network, context: LONG POINTER, why: Protocol1.Action] =
BEGIN
SELECT why FROM
add => AddNetworkPup[driver, context];
remove => RemoveNetworkPup[driver, context];
ENDCASE;
END; --StateChangedPup
-- Various junky routines that live here because this is very cold code
SetPupStormy: PUBLIC PROC[new: BOOLEAN] =
BEGIN outThings.outStormy ← inThings.inStormy ← new; END;
SetBadPupProc: PUBLIC PROC[proc: PROC[Buffer.Buffer]] =
BEGIN inThings.badChecksumProc ← proc; END;
InspectIncomingPups: PUBLIC PROC[
new: BOOLEAN, proc: PROC[CARDINAL, Buffer.Buffer]] =
BEGIN inThings.showIn ← new; inThings.inShower ← proc; END;
InspectOutgoingPups: PUBLIC PROC[
new: BOOLEAN, proc: PROC[CARDINAL, Buffer.Buffer]] =
BEGIN outThings.showOut ← new; outThings.outShower ← proc; END;
InspectStrayPups: PUBLIC PROC[
on, seeBroadcast: BOOLEAN,
proc: PROC[Buffer.Buffer] RETURNS [error: BOOLEAN]] =
BEGIN
inThings.watcherIsWatching ← on;
inThings.watcherSeesBroadcast ← seeBroadcast;
inThings.watcherCallsThis ← proc;
END;
UseNullChecksumMicrocode: PUBLIC PROC=
BEGIN PupRouterDefs.checksum ← none; END;
UseSoftwareChecksumMicrocode: PUBLIC PROC=
BEGIN PupRouterDefs.checksum ← software; END;
UseAltoChecksumMicrocode: PUBLIC PROC=
BEGIN PupRouterDefs.checksum ← alto; END;
UsePrincOpsChecksumMicrocode: PUBLIC PROC=
BEGIN PupRouterDefs.checksum ← princOps; END;
-- initialization
Process.EnableAborts[@routingTableUpdateTimeout];
Process.EnableAborts[@probeResponse];
START PupRouterDefs.PupRouterIn;
START PupRouterDefs.PupRouterOut;
START PupRouterDefs.PupChecksums;
START PupRouterDefs.PupErrors;
Process.SetTimeout[@routingTableUpdateTimeout, Process.MsecToTicks[30000]];
Process.SetTimeout[@probeResponse, Process.MsecToTicks[500]];
END.
LOG
9-Jul-84 9:59:13 AOF Post Klamath.