RoutingTableImpl.mesa - implementation module for the Pilot OISCP Router's routing table
Copyright © 1985 by Xerox Corporation. All rights reserved.
BLyon on: March 19, 1981 5:41 PM
DIRECTORY
BufferDefs USING [BufferAccessHandle, FreeBufferPool, MakeBufferPool, OisBuffer],
Checksums USING [IncrOisTransportControlAndUpdateChecksum, SetChecksum],
CommunicationInternal USING [],
CommFlags USING [doDebug, doStats],
DriverDefs USING [ChangeNumberOfInputBuffers, GetDeviceChain, GetInputBuffer, MaybeGetFreeOisBuffer, Glitch, Network, PutOnGlobalDoneQueue],
OISCP USING [allHostIDs, GetFreeSendOisBufferFromPool, SetOisPacketTextLength, unknownHostID, unknownNetID],
OISCPConstants USING [routingInformationSocket],
OISCPTypes USING [bytesPerPktHeader, maxBytesPerPkt, RoutingInfoTuple, RoutingInfoType, TransPortControl],
Process USING [Detach, MsecToTicks, SetTimeout],
Router USING [BroadcastThisPacket, checkIt, FindMyHostID, routersFunction, Nibble, primaryMDS, RoutingTableEntry, RoutingTableObject, SendErrorPacket, SendPacket, XmitStatus],
StatsDefs USING [StatIncr],
SpecialCommunication USING [RoutersFunction],
NSAddress USING [broadcastHostNumber, HostNumber, NetworkAddress, NetworkNumber, nullNetworkNumber];
RoutingTableImpl: MONITOR
IMPORTS BufferDefs, Checksums, DriverDefs, OISCP, Process, Router, StatsDefs
EXPORTS BufferDefs, CommunicationInternal, Router, SpecialCommunication
SHARES BufferDefs =
BEGIN OPEN OISCP, Router, StatsDefs, SpecialCommunication;
EXPORTed TYPEs
Network: PUBLIC TYPE = DriverDefs.Network;
Many of these variables must eventually live in outerspace so that multiple MDSs
access the same router variables. The modules in the primary MDS will have the
proceses and will perform the initialization of the "globals", while the others will not.
monitor data
myHostID: NSAddress.HostNumber; -- host ID of this system element
routing table constants and variables
network ids and now 32 bits. Therefore numberOfNets, LegalNets, destNet, net, will
have to change. Righrt now we will use the low order bits of the Network Number;
routingTableHead: RoutingTableEntry ← NIL;
routingTableSize: CARDINAL ← 0;
maxRoutingTableSize: CARDINAL = 50;
probeAnInternetRouterCounter: CARDINAL; -- keeps track of num of detached processes
initialTransportControl: OISCPTypes.TransPortControl =
[trace: FALSE, filler: 0, hopCount: 0];
oneHop: Nibble = 1; -- delay to local network is assumd to be one router hop.
updateCycles: Nibble = 4; -- timeUnits gets reset to this; number of routing table update cycles.
alternatePathTimeUnitThreshHold: CARDINAL = 3; -- we look for alternate routing path if timeUnits fall BELOW this value.
maxRouterDelay: CARDINAL = 15; -- max number of router hops
maxInternetrouterHops: CARDINAL = 15; -- max number of internetrouter hops
controlling the entry processes
inrBufferCount: CARDINAL ← 20; -- the number of buffers allocated by an INR.
inrRunning, iNRpleaseStop, pleaseStop: BOOLEAN; -- switch to tell the processes to stop
routingTableUpdateTimer, responseFromInternetRouter, internetRouterTimer:
CONDITION;
routingTableFork, internetRouterServerFork: PROCESS;
various Glitches generated by the Router
RoutingTableScrambled: PUBLIC ERROR = CODE;
routingTableSanityChecking: BOOLEAN = FALSE;
Hot Procedures
Routing list manipulation Routines
used only for debugging
SanityCheck: PROCEDURE = INLINE
BEGIN
e: RoutingTableEntry ← routingTableHead;
WHILE e#NIL DO
IF e.delay=0 THEN ERROR;
e ← e.next;
ENDLOOP;
END;
This procedure searches for an entry with destNetwork field equal to num and returns
that entry. If the entry cannot be found then e is NIL .
FindNetworkNumber: PROCEDURE [num: NSAddress.NetworkNumber, advanceEntry: BOOLEANTRUE]
RETURNS [e: RoutingTableEntry] =
BEGIN
prev: RoutingTableEntry ← e ← routingTableHead;
UNTIL e=NIL DO
IF e.destNetwork=num THEN
BEGIN
IF advanceEntry AND (prev#routingTableHead) THEN
BEGIN
prev.next ← e.next;
e.next ← routingTableHead;
routingTableHead ← e;
END;
RETURN;
END;
prev ← e;
e ← e.next;
ENDLOOP;
END;
This procedure searches for an entry with network field equal to net and returns
that entry. If the entry cannot be found then e is NIL.
FindNetwork: PROCEDURE [net: Network]
RETURNS [e: RoutingTableEntry] =
BEGIN
prev: RoutingTableEntry ← e ← routingTableHead;
UNTIL e=NIL DO
IF e.network=net THEN
BEGIN
IF prev#routingTableHead THEN
BEGIN
prev.next ← e.next;
e.next ← routingTableHead;
routingTableHead ← e;
END;
RETURN;
END;
prev ← e;
e ← e.next;
ENDLOOP;
END;
This procedure removes RoutingTableEntry e from the list. prev is the previous entry
to e. If prev is not known then its value is NIL.
RemoveEntry: PROCEDURE [e: RoutingTableEntry] =
BEGIN
prev: RoutingTableEntry ← NIL;
temp: RoutingTableEntry ← routingTableHead;
UNTIL (temp = NIL) OR (temp = e) DO
prev ← temp;
temp ← temp.next;
ENDLOOP;
IF CommFlags.doDebug AND (temp = NIL) THEN DriverDefs.Glitch[RoutingTableScrambled];
IF prev = NIL THEN routingTableHead ← e.next
ELSE
BEGIN
IF CommFlags.doDebug AND (prev.next # e) THEN DriverDefs.Glitch[RoutingTableScrambled];
IF CommFlags.doDebug AND (prev.next = NIL) THEN DriverDefs.Glitch[RoutingTableScrambled];
prev.next ← e.next;
END;
e.next ← NIL;
routingTableSize ← routingTableSize - 1;
IF CommFlags.doDebug AND routingTableSize>maxRoutingTableSize THEN DriverDefs.Glitch[RoutingTableScrambled];
END;
This procedure adds an entry to the beginning of the Routingtable list.
AddEntry: PROCEDURE [e: RoutingTableEntry] =
BEGIN
e.next ← routingTableHead;
routingTableHead ← e;
routingTableSize ← routingTableSize + 1;
IF CommFlags.doDebug AND routingTableSize>maxRoutingTableSize THEN DriverDefs.Glitch[RoutingTableScrambled];
END;
EnumerateRoutingTable: PUBLIC ENTRY PROCEDURE [
proc: PROCEDURE [RoutingTableEntry]] =
BEGIN
e: RoutingTableEntry ← routingTableHead;
WHILE (e # NIL) DO proc[e]; e ← e.next; ENDLOOP;
END; -- EnumerateRoutingTable
RoutingTableCacheFault: PROCEDURE [destNetNumber: NSAddress.NetworkNumber] =
BEGIN
b: BufferDefs.OisBuffer;
e: RoutingTableEntry ← NEW[RoutingTableObject];
e^ ← RoutingTableObject[
next: , destNetwork: destNetNumber, delay: maxRouterDelay,
timeUnits: updateCycles, route: unknownHostID, network: NIL];
AddEntry[e];
IF routingTableSanityChecking THEN SanityCheck[];
IF (b ← LOOPHOLE[DriverDefs.GetInputBuffer[TRUE], BufferDefs.OisBuffer])=NIL THEN RETURN;
GetInputBuffer is used to reliably get a buffer;
we need some like "get ois system buffer"
b.type ← ois;
b.ois.transCntlAndPktTp ← [initialTransportControl, routingInformation];
SetOisPacketTextLength[b, 2]; -- just one word of data
b.ois.routingType ← routingInfoRequest;
Router.BroadcastThisPacket[b];
END; -- RoutingTableCacheFault
This procedure fills in some routing information and sends the buffer out on the
appropriate network. The send is asynchronous; the caller owns the buffer and
receives its back from the the dispatcher via b.requeueProcedure (when the send
is completed).
FindNetworkAndTransmit: PUBLIC ENTRY PROCEDURE [b: BufferDefs.OisBuffer]
RETURNS [stat: XmitStatus] =
BEGIN
ENABLE UNWIND => NULL;
destHost: NSAddress.HostNumber ← b.ois.destination.host;
nextHost: NSAddress.HostNumber;
destNetNumber: NSAddress.NetworkNumber;
network: Network;
e: RoutingTableEntry ← FindNetworkNumber[destNetNumber ← b.ois.destination.net];
IF e=NIL OR (network𡤎.network)=NIL THEN
BEGIN -- outgoing packet for unknown net,
return b to the system buffer pool
b.status ← LOOPHOLE[stat ← XmitStatus[noRouteToNetwork]];
DriverDefs.PutOnGlobalDoneQueue[b];
IF e=NIL THEN RoutingTableCacheFault[destNetNumber];
IF CommFlags.doStats THEN StatIncr[statOisSentNowhere];
RETURN;
END;
outgoing packet to be transmitted over the correct network
IF (nextHost ← e.route) = unknownHostID
THEN nextHost ← destHost; -- intranet
b.status ← LOOPHOLE[stat ← XmitStatus[goodCompletion]];
network.encapsulateOis[b, nextHost];
synchronous buffer send
network.sendBuffer[b];
END; -- FindNetworkAndTransmit
ForwardPacket: PUBLIC PROCEDURE [b: BufferDefs.OisBuffer] =
BEGIN
ENABLE UNWIND => NULL;
nextHost: NSAddress.HostNumber;
e: RoutingTableEntry;
network: Network;
NotFoundDestinationNetworkLocked: ENTRY PROCEDURE RETURNS [BOOLEAN] = INLINE
{RETURN[(e ← FindNetworkNumber[b.ois.destination.net])=NIL OR (network ← e.network)=NIL]};
see if we have traversed max number of internet routers already
IF b.ois.transCntlAndPktTp.transportControl.hopCount >= maxInternetrouterHops THEN
BEGIN
Router.SendErrorPacket[b, excessHopsOisErrorCode, 0];
return b to the system buffer pool
DriverDefs.PutOnGlobalDoneQueue[b];
IF CommFlags.doStats THEN StatsDefs.StatIncr[statOisNotForwarded];
RETURN;
END;
IF NotFoundDestinationNetworkLocked[] THEN
BEGIN -- outgoing packet for unknown net
Router.SendErrorPacket[b, cantGetThereOisErrorCode, 0];
IF CommFlags.doStats THEN StatIncr[statOisNotForwarded];
b.status ← LOOPHOLE[XmitStatus[noRouteToNetwork]];
return b to the system buffer pool
DriverDefs.PutOnGlobalDoneQueue[b];
END
ELSE
BEGIN -- outgoing packet
Checksums.IncrOisTransportControlAndUpdateChecksum[b];
now transmit it over the correct network
IF (nextHost ← e.route) = unknownHostID THEN nextHost ← b.ois.destination.host;
same net
network.encapsulateOis[b, nextHost];
network.sendBuffer[b];
IF CommFlags.doStats THEN StatIncr[statOisForwarded];
END;
END; -- ForwardPacket
Cool Procedures
This procedure tell the OISCP Router about a new network.
AddNetwork: PUBLIC ENTRY PROCEDURE [newNetwork: Network] =
BEGIN
AddNetworkLocked[newNetwork];
END; -- AddNetwork
This procedure tell the OISCP Router about a new network.
AddNetworkLocked: PRIVATE PROCEDURE [newNetwork: Network] =
BEGIN
unknownNetIdEntry, e: RoutingTableEntry;
IF NOT newNetwork.alive THEN RETURN;
network must be alive to be added to table
e ← FindNetworkNumber[newNetwork.netNumber, FALSE];
do not add a network of unknown number if an unknown number network already exists
IF e = NIL THEN
BEGIN
e ← NEW[RoutingTableObject];
AddEntry[e];
IF newNetwork.netNumber = unknownNetID THEN
BEGIN
probeAnInternetRouterCounter ← probeAnInternetRouterCounter + 1;
Process.Detach[FORK ProbeAnInternetRouter[newNetwork]];
this will help find the net number
END; -- of null network number non-existant
END; -- of entry not found
e^ ← RoutingTableObject[
next: e.next, destNetwork: newNetwork.netNumber, delay: oneHop,
timeUnits: updateCycles, route: unknownHostID, network: newNetwork];
IF routingTableSanityChecking THEN SanityCheck[];
if an unKnownNetID network does not exist, then then make an entry for it
using this network.
IF FindNetworkNumber[unknownNetID, FALSE]=NIL THEN
BEGIN
unknownNetIdEntry ← NEW[RoutingTableObject];
unknownNetIdEntry^ ← RoutingTableObject[
next:, destNetwork: unknownNetID, delay: oneHop, timeUnits: updateCycles,
route: unknownHostID, network: newNetwork];
AddEntry[unknownNetIdEntry];
END;
END; -- AddNetworkLocked
This procedure removes a network from the OISCP Router's tables.
RemoveNetwork: PUBLIC ENTRY PROCEDURE [oldNetwork: Network] =
BEGIN
unknownNetwork: Network;
RemoveNetworkLocked[oldNetwork];
we may have removed the unknownNetID network; if so replace it
IF FindNetworkNumber[unknownNetID, FALSE]=NIL AND
(unknownNetwork ← DriverDefs.GetDeviceChain[])#NIL THEN
AddNetworkLocked[unknownNetwork];
END; -- RemoveNetwork
This procedure removes a network from the OISCP Router's tables.
RemoveNetworkLocked: PRIVATE PROCEDURE [oldNetwork: Network] =
BEGIN
e: RoutingTableEntry;
DO
IF (e ← FindNetwork[oldNetwork])=NIL THEN EXIT;
RemoveEntry[e];
Heap.FreeNode[p: e];--
ENDLOOP;
END; -- RemoveNetworkLocked
StateChanged: PUBLIC ENTRY PROCEDURE [network: Network] =
BEGIN
unknownNetwork: Network;
RemoveNetworkLocked[network];
AddNetworkLocked[network];
if the state changed on the unknownNetID network then that entry was
possibly deleted and NOT added back in; therefore, a new one must be found.
IF FindNetworkNumber[unknownNetID, FALSE]=NIL AND
(unknownNetwork ← DriverDefs.GetDeviceChain[])#NIL THEN
AddNetworkLocked[unknownNetwork];
IF routingTableSanityChecking THEN SanityCheck[];
END; -- StateChanged
RoutingInformationPacket: PUBLIC ENTRY PROCEDURE [b: BufferDefs.OisBuffer] =
BEGIN
newDelay: INTEGER;
objectNetID: NSAddress.NetworkNumber;
sameRoute, betterDelay, awfulDelay, newNetwork: BOOLEAN;
localRouterDelay: INTEGER = 1;
newRoute: NSAddress.HostNumber = b.ois.source.host;
e: RoutingTableEntry;
tricky, incomingNetwork must not become a dangling pointer while we don't have
the monitor locked. This could happen if the network over which the packet arrived
was removed. Sigh...
incomingNetwork: Network = b.network;
routingPacketType: OISCPTypes.RoutingInfoType = b.ois.routingType;
routingInfoLength: CARDINAL = b.ois.pktLength - OISCPTypes.bytesPerPktHeader - 2; -- first word
routingInfo: LONG POINTER TO OISCPTypes.RoutingInfoTuple ← @b.ois.routingTuple[0];
UpdateUnnumberedNetTable: INTERNAL PROCEDURE =
BEGIN
IF incomingNetwork.netNumber # unknownNetID THEN RETURN;
incomingNetwork.netNumber ← b.ois.source.net;
AddNetworkLocked[incomingNetwork];
END; -- UpdateUnnumberedNetTable
UpdateRoutingTable: INTERNAL PROCEDURE =
BEGIN
changed: BOOLEANFALSE;
THROUGH [0..routingInfoLength/(2*SIZE[OISCPTypes.RoutingInfoTuple])) DO
newDelay ← routingInfo.interrouterDelay + localRouterDelay;
awfulDelay ← newDelay > maxRouterDelay;
objectNetID ← routingInfo.objectNetID;
routingInfo ← routingInfo + SIZE[OISCPTypes.RoutingInfoTuple];
IF newDelay = oneHop THEN LOOP;
IF (e ← FindNetworkNumber[objectNetID, FALSE])=NIL THEN
IF (routersFunction=vanillaRouting) OR awfulDelay THEN LOOP
ELSE -- INR - keeps a large table of info that doesn't have an awful delay
BEGIN
e ← NEW[RoutingTableObject];
e^ ← [next: , destNetwork: objectNetID, delay: newDelay, timeUnits: updateCycles, route: newRoute, network: incomingNetwork];
AddEntry[e];
changed ← TRUE;
END;
sameRoute ← e.route = newRoute AND e.network = incomingNetwork;
betterDelay ← newDelay < e.delay;
newNetwork ← (e.timeUnits < alternatePathTimeUnitThreshHold) OR (e.network = NIL);
Note: the value of sameRoute must be tested before the value of newNetwork
IF sameRoute THEN
BEGIN
IF awfulDelay THEN
BEGIN
timeUnits is NOT updated because the net is unreachable.
newDelay is set to avoid Nibble arithmetic wrap-around.
newDelay ← maxRouterDelay;
END
ELSE
BEGIN
e.timeUnits ← updateCycles;
END;
IF e.delay#newDelay THEN changed ← TRUE;
e.delay ← newDelay;
END
ELSE
IF (newNetwork AND NOT awfulDelay) OR (NOT newNetwork AND betterDelay) THEN
BEGIN
changed ← TRUE;
e^ ← RoutingTableObject[
next: e.next, destNetwork: objectNetID, delay: newDelay,
timeUnits: updateCycles, route: newRoute, network: incomingNetwork];
END;
ENDLOOP;
if we are a INR and something has changes then progate the information
IF routersFunction=interNetworkRouting AND changed THEN NOTIFY internetRouterTimer;
END; -- UpdateRoutingTabler
main body of the procedure
IF routingTableSanityChecking THEN SanityCheck[];
IF b.ois.transCntlAndPktTp.packetType # routingInformation
OR (b.ois.source.host=myHostID AND routingPacketType=routingInfoResponse) -- don't need to listen to myself
OR newRoute = unknownHostID
OR incomingNetwork = NIL THEN RETURN;
IF CommFlags.doStats THEN StatIncr[statOisGatewayPacketsRecv];
IF routersFunction = interNetworkRouting AND routingPacketType =
routingInfoRequest THEN
BEGIN
e: RoutingTableEntry;
netNumber: NSAddress.NetworkNumber = b.ois.source.net;
net: Network ← incomingNetwork;
host: NSAddress.HostNumber ← b.ois.source.host;
we hope at this point that incomingNetwork isn't a dangling pointer
IF netNumber#unknownNetID THEN
BEGIN
e ← FindNetworkNumber[netNumber, FALSE];
IF e=NIL OR (net𡤎.network)=NIL THEN RETURN; -- can't find route back to requestor
IF e.route#unknownHostID THEN host ← e.route;
END;
SendRoutingInfoResponse[b.ois.source, host, net];
RETURN;
END;
IF routingPacketType = routingInfoResponse THEN
BEGIN
Examine Packet
UpdateUnnumberedNetTable[];
UpdateRoutingTable[];
END;
IF routingTableSanityChecking THEN SanityCheck;
END; -- RoutingInformationPacket
This procedure sends out Routing Information Protocol Request packets when
a new network is added to the OISCP Router's tables. If the Network were to
go away while we probe, we are in trouble, because we release the monitor when
we do a wait. In general this is a bad thing, but we asume that broadcast networks
like the Ethernet will be the only ones over which we can bind the network number
dynamically and they will be permenantish!
ProbeAnInternetRouter: PROCEDURE [network: Network] =
BEGIN
myBufferAccessHandle: BufferDefs.BufferAccessHandle ←
BufferDefs.MakeBufferPool[total: 1, send: 1, forSystemUse: FALSE];
b: BufferDefs.OisBuffer;
ExitFromProbeAnInternetRouter: ENTRY PROCEDURE = INLINE
BEGIN
WHILE myBufferAccessHandle.sendInUse#0 DO -- wait for all async sends to complete
WAIT responseFromInternetRouter;
ENDLOOP;
probeAnInternetRouterCounter ← probeAnInternetRouterCounter - 1;
BROADCAST responseFromInternetRouter
END;
ResponseFromInternetRouterPositive: ENTRY PROCEDURE RETURNS [BOOLEAN] = INLINE
BEGIN
WAIT responseFromInternetRouter;
RETURN[network.netNumber # unknownNetID];
END; -- ResponseFromInternetRouterPositive
THROUGH [0..30) UNTIL pleaseStop DO
b ← OISCP.GetFreeSendOisBufferFromPool[myBufferAccessHandle];
b.ois.transCntlAndPktTp ← [initialTransportControl, routingInformation];
SetOisPacketTextLength[b, 2]; -- just one word of data
b.ois.source ← b.ois.destination ←
[net: unknownNetID, host: allHostIDs, socket: OISCPConstants.routingInformationSocket];
b.ois.source.host ← myHostID;
b.ois.routingType ← routingInfoRequest;
Router.SendPacket[b];
IF CommFlags.doStats THEN StatsDefs.StatIncr[statOisBroadcast];
IF ResponseFromInternetRouterPositive[] THEN EXIT;
ENDLOOP;
ExitFromProbeAnInternetRouter[];
BufferDefs.FreeBufferPool[myBufferAccessHandle];
END; -- ProbeAnInternetRouter
This procedure sends out Routing Information Protocol Response packet on request.
Note that this is not an (network) ENTRY procedure even though we are touching a
Network. RouterSee had a pointer to the Network, and we hope that this hasn't become a
dangling pointer.
NOTE: this should be called from inside an ENTRY procedure.
'to' is the ultimate destination, 'host' is the encapsulation destination.
SendRoutingInfoResponse: PROCEDURE [to: NSAddress.NetworkAddress, host: NSAddress.HostNumber, network: Network] =
BEGIN
maxBytesPerRoutingPacket: CARDINAL = OISCPTypes.maxBytesPerPkt - 2*SIZE[OISCPTypes.RoutingInfoTuple];
nextRoutingEntry: RoutingTableEntry ← routingTableHead;
sendBuf: BufferDefs.OisBuffer ← NIL;
nextResponseEntry: INTEGER;
IF routingTableSanityChecking THEN SanityCheck[];
UNTIL nextRoutingEntry=NIL DO
IF nextRoutingEntry.destNetwork # NSAddress.nullNetworkNumber
AND nextRoutingEntry.network # NIL THEN -- bypass the null network entry or a nil entry
BEGIN
IF sendBuf=NIL THEN
BEGIN
IF (sendBuf ← DriverDefs.MaybeGetFreeOisBuffer[])=NIL THEN RETURN; -- give up!
sendBuf.ois.transCntlAndPktTp ← [initialTransportControl, routingInformation];
sendBuf.ois.routingType ← routingInfoResponse;
sendBuf.ois.source ← [network.netNumber, myHostID, OISCPConstants.routingInformationSocket];
sendBuf.ois.destination ← to;
sendBuf.ois.pktLength ← OISCPTypes.bytesPerPktHeader + 2;
sendBuf.network ← network;
sendBuf.allNets ← (host = NSAddress.broadcastHostNumber);
nextResponseEntry ← 0;
END; -- of getting a new send buffer
sendBuf.ois.routingTuple[nextResponseEntry] ← [nextRoutingEntry.destNetwork, nextRoutingEntry.delay];
nextResponseEntry ← nextResponseEntry + 1;
sendBuf.ois.pktLength ← sendBuf.ois.pktLength+2*SIZE[OISCPTypes.RoutingInfoTuple];
END;
nextRoutingEntry ← nextRoutingEntry.next;
IF (sendBuf#NIL) AND ((nextRoutingEntry=NIL)
OR (sendBuf.ois.pktLength>=maxBytesPerRoutingPacket)) THEN
BEGIN
IF ~network.alive THEN
BEGIN
DriverDefs.PutOnGlobalDoneQueue[sendBuf];
END
ELSE
BEGIN
IF checkIt THEN Checksums.SetChecksum[sendBuf] ELSE sendBuf.ois.checksum ← 177777B;
network.encapsulateOis[sendBuf, host];
network.sendBuffer[sendBuf];
END;
sendBuf ← NIL;
END; -- of sending a full routing buffer
ENDLOOP; -- end of send loop
END; -- SendRoutingInfoResponse
This process wakes up every 30 seconds and sends out Routing Information
- Protocol Response packets gratuitously, if this system element is an internet router.
InternetRouterServer: ENTRY PROCEDURE =
BEGIN
inrAccessHandle: BufferDefs.BufferAccessHandle;
inrRunning ← TRUE;
inrAccessHandle ← BufferDefs.MakeBufferPool[inrBufferCount, 0, 0, 0, TRUE];
since we are an INR, make sure the drivers have plenty of buffers
and get a few of out own too.
DriverDefs.ChangeNumberOfInputBuffers[TRUE];
UNTIL pleaseStop OR iNRpleaseStop DO
WAIT internetRouterTimer;
IF pleaseStop OR iNRpleaseStop THEN EXIT;
SendRoutingInfoResponse[[unknownNetID, NSAddress.broadcastHostNumber, OISCPConstants.routingInformationSocket], NSAddress.broadcastHostNumber, DriverDefs.GetDeviceChain[]];
ENDLOOP;
undo the buffer allocated for the INR
DriverDefs.ChangeNumberOfInputBuffers[FALSE];
BufferDefs.FreeBufferPool[inrAccessHandle];
inrRunning ← FALSE;
END; -- InternetRouterServer
This process wakes up every 60 seconds. On awakening it goes through the
routing table entries decrementing by one the time since the entry was last
updated. If the time is zero, then the destination net is deemed unreachable.
RoutingTableUpdater: ENTRY PROCEDURE =
BEGIN
rte: RoutingTableEntry;
UNTIL pleaseStop DO
IF routingTableSanityChecking THEN SanityCheck[];
no need to probe an internet router, since they broadcast every 30 secs.
rte ← routingTableHead;
WHILE (rte # NIL) DO
IF rte.delay # oneHop THEN
BEGIN
IF rte.timeUnits = 0 THEN
BEGIN
temp: RoutingTableEntry ← rte;
rte ← rte.next;
RemoveEntry[temp];
Heap.FreeNode[p: temp];--
LOOP;
END
ELSE rte.timeUnits ← rte.timeUnits - 1;
END;
rte ← rte.next;
ENDLOOP;
WAIT routingTableUpdateTimer;
ENDLOOP;
END; -- RoutingTableUpdater
This returns the ID of the locally connected networkmost suitable to get to the
destination network.
FindDestinationRelativeNetID: PUBLIC ENTRY PROCEDURE [destNet: NSAddress.NetworkNumber]
RETURNS [netNumber: NSAddress.NetworkNumber] =
BEGIN
e: RoutingTableEntry;
IF (e ← FindNetworkNumber[destNet])=NIL OR (e.network=NIL) THEN RETURN[unknownNetID];
netNumber ← e.network.netNumber;
IF netNumber=unknownNetID THEN
BEGIN
since unknownNetID is uniformative find the first network with a known
network Number and use it.
n: Network ← DriverDefs.GetDeviceChain[];
DO
IF (netNumber ← n.netNumber)#unknownNetID THEN EXIT; -- gotIt!
IF (n ← n.next)=NIL THEN EXIT; -- a non - unknownNetID network does not exist!
ENDLOOP;
END; -- find non - unknownNetID network clause
END; -- FindDestinationRelativeNetID
This procedure returns what the router is.
GetRouterFunction: PUBLIC ENTRY PROCEDURE RETURNS [RoutersFunction] =
BEGIN RETURN[routersFunction]; END;
Cold Procedures
The router must be told which function to perform.
Race condition with RoutingTableOn and RoutingTableOff concerning
FORKing and JOINing internetRouterServerFork. Races should not occur
because all of these are very Cold and only this procedure is exported
out of Pilot.
SetRouterFunction: PUBLIC PROCEDURE [newFunction: RoutersFunction, numberINRBuffers: CARDINAL]
RETURNS [oldFunction: RoutersFunction] =
BEGIN
joinTheINRServer: BOOLEANFALSE;
zombieINRServer: PROCESS;
SetFunction: ENTRY PROCEDURE =
BEGIN
temp: CONDITION;
oldFunction ← routersFunction;
routersFunction ← newFunction;
IF primaryMDS THEN
BEGIN
IF oldFunction=interNetworkRouting THEN
BEGIN
Process.SetTimeout[@temp, Process.MsecToTicks[500]];
joinTheINRServer ← iNRpleaseStop ← TRUE;
zombieINRServer ← internetRouterServerFork;
WHILE inrRunning DO
NOTIFY internetRouterTimer;
WAIT temp;
ENDLOOP;
END;
IF newFunction=interNetworkRouting THEN
BEGIN
iNRpleaseStop ← FALSE;
inrBufferCount ← numberINRBuffers;
internetRouterServerFork ← FORK InternetRouterServer[];
END;
END; -- primaryMDS clause
END; -- inline of SetFunction
mainline code of SetRouterFunction
SetFunction[];
IF joinTheINRServer THEN JOIN zombieINRServer;
END;
This procedure turns the router on. The Communication software is written with the
idea of eventually turning the code on and off during execution, and so we should
get the latest values of netID when being turned back on. The processes asociated
with the routing table should be created only if this module is in the primary MDS.
RoutingTableOn: PUBLIC PROCEDURE =
BEGIN
inrRunning ← iNRpleaseStop ← pleaseStop ← FALSE;
IF primaryMDS THEN
BEGIN
network: Network ← DriverDefs.GetDeviceChain[];
RoutingTableActivate[];
FOR network ← network, network.next UNTIL network = NIL DO
AddNetwork[network]; ENDLOOP;
IF routersFunction = interNetworkRouting THEN
internetRouterServerFork ← FORK InternetRouterServer[];
routingTableFork ← FORK RoutingTableUpdater[];
END;
END; -- RoutingTableOn
RoutingTableActivate: ENTRY PROCEDURE = INLINE
BEGIN routingTableHead ← NIL;
myHostID ← Router.FindMyHostID[];
probeAnInternetRouterCounter ← 0;
routingTableSize ← 0;
END; -- RoutingTableActivate
RoutingTableOff: PUBLIC PROCEDURE =
BEGIN
IF primaryMDS THEN
BEGIN
RoutingTableDeactivate[];
JOIN routingTableFork[];
IF routersFunction = interNetworkRouting THEN JOIN internetRouterServerFork;
CleanUpRoutingTable[];
END;
END; -- RoutingTableOff
RoutingTableDeactivate: ENTRY PROCEDURE = INLINE
BEGIN
iNRpleaseStop ← pleaseStop ← TRUE;
NOTIFY routingTableUpdateTimer;
BROADCAST responseFromInternetRouter;
IF routersFunction = interNetworkRouting THEN NOTIFY internetRouterTimer;
clean up all the detached ProbeAnInternetRouter(s)
WHILE (probeAnInternetRouterCounter>0) DO
BROADCAST responseFromInternetRouter;
WAIT responseFromInternetRouter;
ENDLOOP;
END; -- RoutingTableDeactivate
CleanUpRoutingTable: ENTRY PROCEDURE = INLINE
BEGIN
e, temp: RoutingTableEntry;
e ← routingTableHead;
WHILE e # NIL DO temp ← e; e ← e.next; --Heap.FreeNode[p: temp];-- ENDLOOP;
routingTableSize ← 0;
END; -- RoutingTableDeactivate
initialization (Cold)
Process.SetTimeout[@routingTableUpdateTimer, Process.MsecToTicks[60000]];
Process.SetTimeout[@responseFromInternetRouter, Process.MsecToTicks[1000]];
Process.SetTimeout[@internetRouterTimer, Process.MsecToTicks[30000]];
END. -- RoutingTableImpl module.
LOG
Time: January 19, 1980 4:05 PM By: Dalal Action: Split OISCPRouter into two.
Time: March 13, 1980 5:11 PM By: BLyon Action: FindNetworkAndTransmit synchronously sends non-system buffers and asynchronously sends system buffers.
Time: July 31, 1980 11:53 AM By: BLyon Action: replaced internetRouter with routersFunction and added Get/SetRoutersFunction.
Time: August 5, 1980 4:25 PM By: BLyon Action: RoutingTable is now linked list and no such concept as primaryNetID.
Time: September 13, 1980 6:15 PM By: HGM Action: Add StateChanged.
Time: September 18, 1980 3:16 PM By: BLyon Action: modified StateChanged, Add/Delete Network .., removed FindPrimaryNetID.
Time: January 5, 1981 4:00 PM By: BLyon Action: added EnumerateRoutingTable.
Time: February 24, 1981 2:58 PM By: BLyon Action: added stuff to tell INR how many buffers to use.
Time: March 19, 1981 10:38 AM By: BLyon Action: Modified FindDestinationRelativeNetID to try and not return unknownNetID if at all possible.