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:
BOOLEAN ←
TRUE]
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: BOOLEAN ← FALSE;
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: BOOLEAN ← FALSE;
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.