-- Copyright (C) 1984 by Xerox Corporation. All rights reserved.
--INRImpl.mesa last edited by: HGM on: 16-Dec-84 10:24:27, Yetch: NewInrFriends
--INRImpl.mesa last edited by: HGM on: 24-Oct-84 1:35:07
--INRImpl.mesa last edited by: Leong on: 23-Oct-84 15:54:08
--Function: The implementation module for the NS INR.
DIRECTORY
Buffer USING [AccessHandle, MakePool, DestroyPool, Buffer,
GetBuffer],
Checksums USING [IncrNSTransportControlAndUpdateChecksum, SetChecksum],
CommFlags USING [doStats],
CommSvcFlags USING [doDebug],
CommSvcHeap USING [FreeNode, MakeNode, GetInrHeap],
CommunicationInternal USING [],
CourierInternal USING [ExchWords],
Driver USING [
ChangeNumberOfInputBuffers, GetDeviceChain, GetInputBuffer,
Glitch, Network, PutOnGlobalDoneQueue],
NSConstants USING [routingInformationSocket],
NSTypes USING [
bytesPerIDPHeader, RoutingInfoTuple, RoutingInfoType,
TransportControl, maxIDPDataBytes],
Process USING [MsecToTicks, Pause, SetTimeout, DisableTimeout,
SecondsToTicks, Abort, Detach, EnableAborts],
RoutingTable USING [Object, Handle, Register, FlushCacheProc],
Router USING [FindMyHostID, NoTableEntryForNet, RoutersFunction],
RouterInternal USING [
BroadcastThisPacket, checkIt, SendErrorPacket,
XmitStatus, SendPacket],
Runtime USING [CallDebugger],
Inr USING [],
InrFriends USING [RoutingTableObject, HopCount, RoutingTableEntry,
DriverDetails, Method],
InrStats USING [Stats, RoutingTableSearch, tupleIndexTableSize],
Inline USING [LowHalf, BITAND],
Socket USING [ChannelHandle, Create, Delete, GetPacket, SetWaitTime,
ReturnBuffer, infiniteWaitTime, GetBufferPool],
Stats USING [StatIncr],
SpecialSystem USING [HostNumber, NetworkNumber, SocketNumber],
System USING [broadcastHostNumber, GetClockPulses, GetGreenwichMeanTime,
gmtEpoch, GreenwichMeanTime, HostNumber, NetworkAddress, NetworkNumber,
nullNetworkNumber, nullHostNumber, nullSocketNumber, nullNetworkAddress,
Pulses],
RoutingFudges USING [];
INRImpl: MONITOR
IMPORTS
Buffer, Inline, Checksums, CommSvcHeap, CourierInternal, Driver,
Process, Router, RouterInternal, Socket, Stats,
System, RoutingTable, Runtime
EXPORTS Inr, InrFriends, InrStats, Buffer, System, RoutingFudges =
BEGIN
doNSStats: BOOLEAN = TRUE OR CommFlags.doStats; --tied to TRUE for now
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
--EXPORTed TYPEs
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
Network: PUBLIC TYPE = Driver.Network;
NetworkNumber: PUBLIC TYPE = SpecialSystem.NetworkNumber;
HostNumber: PUBLIC TYPE = SpecialSystem.HostNumber;
SocketNumber: PUBLIC TYPE = SpecialSystem.SocketNumber;
RoutingTableObject: TYPE = InrFriends.RoutingTableObject;
RoutingTableEntry: TYPE = InrFriends.RoutingTableEntry;
HopCount: TYPE = InrFriends.HopCount;
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
-- CONSTANTS that make it all happen
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
unknownHostID: HostNumber = System.nullHostNumber;
extraBuffersForForwarding: CARDINAL = 40;
mask: CARDINAL = 31; -- for masking out the high eleven bits of the incoming
-- delay, as we don't use them (yet).
anyNetNetworkNumber: NetworkNumber = [177777B, 177777B];
anyNetNetworkNumberFor860: NetworkNumber = [0AAFFH, 0FFFFH];
nullNetworkNumber: NetworkNumber = System.nullNetworkNumber;
-- routing info request network number that indicates all networks
initialTransportControl: NSTypes.TransportControl = [
trace: FALSE, filler: 0, hopCount: 0];
localHop: InrFriends.HopCount = 0; -- rte delay for attached network(s) is zero hops.
updateCycles: InrFriends.HopCount = 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.
maxInternetrouterHops: CARDINAL = 15;
infinityHopCount: CARDINAL = 16;
decrementTO: CARDINAL = 40; -- seconds for decrementing table entries
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
-- VARIABLES or semi-Variables
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
myHostID: HostNumber; --host ID of this system element
nullEnum: NetworkNumber ← nullNetworkNumber;
-- Routing table constants and variables
routingTableHead: RoutingTableEntry ← NIL;
routingTableSize: CARDINAL ← 0;
pleaseStop: BOOLEAN ← TRUE; << controls the processes. TRUE if we are OFF,
FALSE if we are ON >>
internetRouterTimer, -- times out to send gratuitous routing packets
routingTableChanged, -- notified to send info on routes that have changed
auxInternetRouterTimer: -- times out by a random amount so we don't all send the gratuitous packets at the same time.
CONDITION;
routingInformationSupplierFork, internetRouterServerFork,
decrementRoutingTableEntriesFork, routingTableChangedFork: PROCESS ← NIL;
stats: LONG POINTER TO InrStats.Stats ← NIL;
lastGetStats: System.GreenwichMeanTime ← System.gmtEpoch;
--mark the last time a snap of the statistics was taken
--various Glitches generated by the Router
RoutingTableScrambled: ERROR = CODE;
--Routing Table Object
rto: PUBLIC RoutingTable.Object ← [
type: interNetworkRouting, start: Start, stop: Stop,
startEnumeration: nullEnum, endEnumeration: nullEnum,
enumerate: EnumerateByDistance, fillTable: Fill,
getDelay: GetDelay, transmit: Transmit,
forward: Forward, findNetwork: FindNetID,
addNetwork: AddNet, removeNetwork: RemoveNet,
flushCache: FlushCacheNoOp, stateChanged: ChangedState];
ptrToRto:RoutingTable.Handle ← @rto;
extraHops: CARDINAL ← 0; -- fudge factor on the hop count to trick other
-- routers into using another path for forwarding packets
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
-- Routing Table (list) handling Routines
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This procedure adds an entry to the beginning of the Routingtable list.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
AddEntry: INTERNAL PROCEDURE [e: RoutingTableEntry] =
BEGIN
e.nextRTE ← routingTableHead;
routingTableHead ← e;
routingTableSize ← routingTableSize + 1;
StatIncr [@stats.destNetsAdded];
END; -- of AddEntry
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- AddNet
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
AddNet: ENTRY PROCEDURE [net: Network] =
BEGIN ENABLE UNWIND => NULL;
AddNetworkInternal[net]; --AddNet
-- send out gratuitous routing response so inrs learn about each other
NOTIFY routingTableChanged;
END;
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This procedure tells the NS Router about a new network.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
AddNetworkInternal: INTERNAL PROCEDURE [newNetwork: Network] =
BEGIN
IF NOT newNetwork.alive THEN RETURN;
IF newNetwork.netNumber # nullNetworkNumber THEN
BEGIN
-- the driver already knows the number of its net, add or modify a rte
e: RoutingTableEntry ← FindNetworkNumber[
newNetwork.netNumber, FALSE];
IF e = NIL THEN
BEGIN
e ← CommSvcHeap.MakeNode[n: SIZE[RoutingTableObject]];
AddEntry[e];
END;
e↑ ← RoutingTableObject[
nextRTE: e.nextRTE, nextNSE: NIL, destNetwork: newNetwork.netNumber, delay: localHop,
timeUnits: updateCycles, route: unknownHostID,
network: newNetwork, changed: TRUE];
END;
IF FindNetworkNumber[nullNetworkNumber, FALSE] = NIL THEN
BEGIN
-- there is no "default" rte, add one
e: RoutingTableEntry ← CommSvcHeap.MakeNode[
n: SIZE[RoutingTableObject]];
e↑ ← RoutingTableObject[
nextRTE: NIL, nextNSE: NIL, destNetwork: nullNetworkNumber, delay: localHop,
timeUnits: updateCycles, route: unknownHostID,
network: newNetwork, changed: FALSE];
AddEntry[e];
END;
END; --AddNetworkInternal
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- RemoveEntry
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RemoveEntry: INTERNAL PROCEDURE [e: RoutingTableEntry] =
BEGIN
prev: RoutingTableEntry ← NIL;
temp: RoutingTableEntry ← routingTableHead;
UNTIL (temp = NIL) OR (temp = e) DO prev ← temp; temp ← temp.nextRTE; ENDLOOP;
IF CommSvcFlags.doDebug AND (temp = NIL) THEN
Driver.Glitch[RoutingTableScrambled];
IF prev = NIL THEN routingTableHead ← e.nextRTE
ELSE
BEGIN
IF CommSvcFlags.doDebug AND (prev.nextRTE # e) THEN
Driver.Glitch[RoutingTableScrambled];
IF CommSvcFlags.doDebug AND (prev.nextRTE = NIL) THEN
Driver.Glitch[RoutingTableScrambled];
prev.nextRTE ← e.nextRTE;
END;
e.nextRTE ← NIL;
routingTableSize ← routingTableSize - 1;
StatIncr [@stats.destNetsDeleted];
END; -- of RemoveEntry
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This procedure removes a network from the NS Router's tables.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RemoveNet: PROCEDURE [net: Network] =
BEGIN
unknownNetwork: Network;
FindNetworkNumberLocked: ENTRY PROCEDURE [n: NetworkNumber]
RETURNS [e: RoutingTableEntry] = INLINE
BEGIN ENABLE UNWIND => NULL;
e ← FindNetworkNumber[n, FALSE-- don't reorder chain--]; END;
RemoveNetworkLocked[net];
--we may have removed the nullNetworkNumber network; if so replace it
IF FindNetworkNumberLocked[nullNetworkNumber] = NIL THEN
BEGIN
unknownNetwork ← Driver.GetDeviceChain[];
UNTIL (unknownNetwork # net) OR (unknownNetwork = NIL) DO
unknownNetwork ← unknownNetwork.next;
ENDLOOP; --try to find another network
IF (unknownNetwork # NIL) THEN AddNet[unknownNetwork];
END; -- of replacing the net 0 rte
END; --RemoveNet
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This procedure removes a network from the NS Router's tables.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RemoveNetworkLocked: ENTRY PROCEDURE [oldNetwork: Network] =
BEGIN
ENABLE UNWIND => NULL;
e: RoutingTableEntry;
anyChanges: BOOLEAN ← FALSE;
DO
IF (e ← FindNetwork[oldNetwork]) = NIL THEN EXIT;
-- mark the rte as pointing to an obsolete network driver
e↑ ← [destNetwork: e.destNetwork, delay: infinityHopCount,
timeUnits: updateCycles, -- so we keep the rte entry around for awhile
nextRTE: e.nextRTE, nextNSE: NIL, route: unknownHostID, network: NIL, changed: TRUE];
anyChanges ← TRUE;
ENDLOOP;
IF anyChanges THEN
-- send out gratuitous routing response for the new info
NOTIFY routingTableChanged;
END; --RemoveNetworkLocked
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- CleanUpRoutingTable
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
CleanUpRoutingTable: ENTRY PROCEDURE = INLINE
BEGIN ENABLE UNWIND => NULL;
e, temp: RoutingTableEntry;
e ← routingTableHead;
WHILE (e # NIL) DO
temp ← e;
e ← e.nextRTE;
CommSvcHeap.FreeNode[p: temp];
ENDLOOP;
routingTableSize ← 0;
END; -- of CleanUpRoutingTable
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This procedure 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.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
DecrementRoutingTableEntries: ENTRY PROCEDURE =
BEGIN ENABLE UNWIND => NULL;
rte: RoutingTableEntry;
timer: CONDITION;
Process.SetTimeout [@timer, Process.SecondsToTicks [decrementTO]];
Process.EnableAborts [@timer];
UNTIL pleaseStop DO
ENABLE ABORTED => EXIT;
WAIT timer;
rte ← routingTableHead;
WHILE (rte # NIL) DO
IF (rte.delay # localHop) THEN
BEGIN
IF rte.timeUnits = 0 THEN
BEGIN -- remove the dead entry
temp: RoutingTableEntry ← rte;
rte ← rte.nextRTE;
RemoveEntry[temp];
CommSvcHeap.FreeNode[p: temp];
LOOP;
END
ELSE rte.timeUnits ← rte.timeUnits - 1;
END;
rte ← rte.nextRTE;
ENDLOOP;
ENDLOOP;
END; -- of DecrementRoutingTableEntries
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- EnumerateByDistance
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
EnumerateByDistance: ENTRY PROCEDURE [
previous: NetworkNumber, delay: CARDINAL]
RETURNS [net: NetworkNumber] =
--Start enumeration with nullNetworkNumber and finish with lastNetworkNumber
--enumeration happens in order of net #, so table can change between calls
BEGIN
ENABLE UNWIND => NULL;
test: NetworkNumber;
n: RoutingTableEntry ← routingTableHead;
foundOne: BOOLEAN ← FALSE;
pulses: System.Pulses ← System.GetClockPulses[]; --for time duration
IF (n = NIL) THEN {net ← nullEnum; RETURN};
UNTIL (n = NIL) DO
test ← n.destNetwork;
IF (n.delay = delay) --within the desired hop count
AND NetAgtNetB[test, previous] --greater than the one he has now
AND (~NetAgtNetB[test, net] OR ~foundOne)
--less than any we know about since
AND (n.network # NIL)
THEN --is interesting-- {net ← test; foundOne ← TRUE};
n ← n.nextRTE; --but continue looking for an even better one
ENDLOOP;
IF ~foundOne THEN net ← nullEnum;
SearchDurationBump[pulses, enumerateByDistance]; --increments duration
END; -- of EnumerateByDistance
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- EnumerateByNetNumber
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
EnumerateByNetNumber: ENTRY PROCEDURE [previous: NetworkNumber]
RETURNS [net: NetworkNumber, delay: HopCount] =
--Start enumeration with nullNetworkNumber and finish with lastNetworkNumber
--enumeration happens in order of net #, so table can change between calls
BEGIN
ENABLE UNWIND => NULL;
test: NetworkNumber;
n: RoutingTableEntry ← routingTableHead;
foundOne: BOOLEAN ← FALSE;
pulses: System.Pulses ← System.GetClockPulses[]; --for time duration
IF (n = NIL) THEN {net ← nullEnum; RETURN};
UNTIL (n = NIL) DO
test ← n.destNetwork;
IF NetAgtNetB[test, previous] --greater than the one he has now
AND (~NetAgtNetB[test, net] OR ~foundOne)
--less than any we know about since
AND (n.network # NIL)
THEN --is interesting-- {net ← test; delay ← n.delay;
foundOne ← TRUE};
n ← n.nextRTE; --but continue looking for an even better one
ENDLOOP;
IF ~foundOne THEN net ← nullEnum;
SearchDurationBump[pulses, enumerateByNetNumber]; --increments duration
END; -- of EnumerateByNetNumber
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- EnumerateRoutes
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
EnumerateRoutes: PUBLIC PROCEDURE [previousNet: NetworkNumber,
previousDelay: HopCount, method: InrFriends.Method,
alwaysDetermineViaNet: BOOLEAN ← FALSE]
RETURNS [net: NetworkNumber,
delay: HopCount, details: InrFriends.DriverDetails]=
BEGIN
<< Stateless enumerator starts
with nullNetworkNumber and zeroHopCount. Ends with nullNetworkNumber >>
SELECT method FROM
byNetNumber =>
BEGIN
[net, delay] ← EnumerateByNetNumber [previousNet];
IF (net = nullEnum) THEN RETURN;
details ← GetRouteDetails[net, alwaysDetermineViaNet!
Router.NoTableEntryForNet => {net ← nullEnum; CONTINUE}].details;
END;
byDistance =>
BEGIN
ENABLE Router.NoTableEntryForNet => RETRY;
net ← EnumerateByDistance [previousNet, previousDelay];
UNTIL (net # nullEnum) OR (previousDelay = maxInternetrouterHops) DO
previousDelay ← previousDelay + 1;
previousNet ← nullEnum; -- start over
net ← EnumerateByDistance [previousNet, previousDelay];
ENDLOOP;
IF (net = nullEnum) THEN RETURN;
delay ← previousDelay;
previousNet ← net;
details ← GetRouteDetails[net, alwaysDetermineViaNet].details;
END;
ENDCASE => NULL; -- we handled all of the enumerated type's values
END; -- of EnumerateRoutes
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
--Client requests that we gather routing table information.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
Fill: PROCEDURE [maxDelay: CARDINAL] =
BEGIN
<< Since we are already an inr this proc. is a NOP, (we leave it in for the time being because its part of the routing object). >>
END; -- of Fill
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This returns the ID of the locally connected networkmost suitable to get
-- to the destination network.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
FindNetID: ENTRY PROCEDURE [net: NetworkNumber]
RETURNS [NetworkNumber] =
BEGIN ENABLE UNWIND => NULL;
RETURN[FindNetIDInternal[net]];
END; -- of FindNetID
FindNetIDInternal: INTERNAL PROCEDURE [
destNet: NetworkNumber] RETURNS [netNumber: NetworkNumber] =
BEGIN
e: RoutingTableEntry;
netNumber ←
IF destNet = nullNetworkNumber OR -- accelerator so we don't search
-- for the net zero rte
(e ← FindNetworkNumber[destNet]) = NIL OR (e.network = NIL) THEN
nullNetworkNumber ELSE e.network.netNumber;
IF netNumber = nullNetworkNumber THEN
BEGIN
--since nullNetworkNumber is uninformative find the first network
--with a known network Number and use it.
FOR n: Network ← Driver.GetDeviceChain[], n.next UNTIL n = NIL DO
IF (netNumber ← n.netNumber) # nullNetworkNumber THEN EXIT;
ENDLOOP;
END; --find non - nullNetworkNumber network clause
END; --FindNetIDInternal
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This procedure searches for an entry with network field equal to net and
-- returns that entry. It also reorders the rte chain. If the entry cannot
-- be found then e is NIL.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
FindNetwork: INTERNAL PROCEDURE [net: Network]
RETURNS [e: RoutingTableEntry] =
BEGIN
prev: RoutingTableEntry ← e ← routingTableHead;
pulses: System.Pulses ← System.GetClockPulses[]; --for time duration
UNTIL (e = NIL) DO
IF (e.network = net) THEN
BEGIN
IF (prev # routingTableHead) THEN
BEGIN
prev.nextRTE ← e.nextRTE;
e.nextRTE ← routingTableHead;
routingTableHead ← e;
END;
EXIT; --exit from until-do loop
END;
prev ← e;
e ← e.nextRTE;
ENDLOOP;
SearchDurationBump[pulses, findByNetworkDriver]; --increments duration
END; -- of FindNetwork
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This hot procedure fills in some routing information and sends the buffer
-- out on the appropriate network. The send is asynchronous; the caller
-- owns the buffer andreceives its back from the the dispatcher via
-- b.requeueProcedure (when the send is completed).
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
Transmit: PROCEDURE[b: Buffer.Buffer] =
BEGIN
destHost: HostNumber ← b.ns.destination.host;
nextHost: HostNumber;
destNetNumber: NetworkNumber ← b.ns.destination.net;
network: Network;
e: RoutingTableEntry;
FindNetworkNumberLocked: ENTRY PROCEDURE [n: NetworkNumber]
RETURNS [e: RoutingTableEntry] = INLINE
BEGIN
ENABLE UNWIND => NULL;
e ← FindNetworkNumber[n];
END; -- of FindNetworkNumberLocked
-- start of procedure
e ← FindNetworkNumberLocked[destNetNumber];
IF (e = NIL) OR (network ← e.network) = NIL THEN
BEGIN --outgoing packet for unknown net
--return b to the system buffer pool
b.status ← LOOPHOLE[RouterInternal.XmitStatus[noRouteToNetwork]];
Driver.PutOnGlobalDoneQueue[b];
IF doNSStats THEN Stats.StatIncr[statNSSentNowhere];
RETURN;
END;
--outgoing packet to be transmitted over the correct network
nextHost ← IF e.route # unknownHostID THEN
e.route -- next inr's address
ELSE destHost; -- we are attached to the destination net
b.status ← LOOPHOLE[RouterInternal.XmitStatus[goodCompletion]];
b.network ← network; -- mark the network being used
b.type ← ns;
--synchronous buffer send
network.encapsulateAndSendNS [b, nextHost];
StatIncr [@stats.pktsTransmitted];
END; --Transmit
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This hot 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: INTERNAL PROCEDURE [
num: NetworkNumber, advanceEntry: BOOLEAN ← TRUE]
RETURNS [e: RoutingTableEntry] =
BEGIN
prev: RoutingTableEntry ← e ← routingTableHead;
pulses: System.Pulses ← System.GetClockPulses[]; --for time duration
i: CARDINAL ← 0;
UNTIL (e = NIL) DO
IF (e.destNetwork = num) THEN
BEGIN
IF advanceEntry AND (i > 4) THEN
BEGIN
--advance entry to the beginning of the list
prev.nextRTE ← e.nextRTE;
e.nextRTE ← routingTableHead;
routingTableHead ← e;
END;
IF advanceEntry THEN StatIncr [@stats.tupleIndexTable[
MIN[i, InrStats.tupleIndexTableSize-1]]];
EXIT; --exit the until-do loop
END;
prev ← e;
e ← e.nextRTE;
i ← i + 1;
ENDLOOP;
SearchDurationBump[pulses, findByNetNumber]; --increments duration
END; -- of FindNetworkNumber
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- FlushCacheNoOp is a no operation routine.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
FlushCacheNoOp: RoutingTable.FlushCacheProc = {};
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- Forward
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
Forward: PROCEDURE [b: Buffer.Buffer] =
BEGIN
ENABLE UNWIND => NULL;
nextHost: HostNumber;
e: RoutingTableEntry;
network: Network;
NotFoundDestinationNetworkLocked: ENTRY PROCEDURE RETURNS [BOOLEAN] = INLINE
BEGIN ENABLE UNWIND => NULL;
RETURN[
(e ← FindNetworkNumber[b.ns.destination.net]) = NIL
OR (network ← e.network) = NIL];
END; -- of NotFoundDestinationNetworkLocked
--see if we have traversed max number of internet routers already
SELECT TRUE FROM
(maxInternetrouterHops <= b.ns.transportControl.hopCount) =>
-- note that it is "<=" - this prevents a packet from being
-- forwarded past the farthest net a source knows about (15 hops)
BEGIN
RouterInternal.SendErrorPacket[b, excessHopsErrorCode, 0];
IF doNSStats THEN Stats.StatIncr[statNSNotForwarded];
StatIncr [@stats.tooManyHops]
END;
(NotFoundDestinationNetworkLocked[]) =>
BEGIN --outgoing packet for unknown net
IF b.ns.source.host # myHostID THEN
RouterInternal.SendErrorPacket[b, cantGetThereErrorCode, 0]
ELSE
{b.status ← LOOPHOLE[RouterInternal.XmitStatus[noRouteToNetwork]];
--return b to the system buffer pool
Driver.PutOnGlobalDoneQueue[b]};
IF doNSStats THEN Stats.StatIncr[statNSNotForwarded];
StatIncr [@stats.unknownNet];
END;
ENDCASE =>
BEGIN --outgoing packet
Checksums.IncrNSTransportControlAndUpdateChecksum[b];
--now transmit it over the correct network
IF (nextHost ← e.route) = unknownHostID THEN
nextHost ← b.ns.destination.host;
b.network ← network; -- mark the network being used
b.type ← ns;
--maintain the crude counters of packets and bytes forwarded
StatIncr [@stats.statNSForwarded];
StatBump [@stats.bytesForwarded, b.ns.pktLength];
network.encapsulateAndSendNS[b, nextHost]; --same net
IF doNSStats THEN Stats.StatIncr[statNSForwarded];
END;
END; --Forward
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- Provide the crude couters of packets forwarded by the router
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
ForwardingStats: PUBLIC PROCEDURE RETURNS [packets, bytes: LONG CARDINAL] =
BEGIN
IF (stats = NIL) THEN RETURN [0, 0]; --forwarding hasn't been activated
packets ← stats.statNSForwarded;
bytes ← stats.bytesForwarded;
END; --ForwardingStats
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- GetDelay
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
GetDelay: PROCEDURE [net: NetworkNumber] RETURNS [delay: CARDINAL] =
BEGIN
LockedFindNet: ENTRY PROC = INLINE
{ENABLE UNWIND => NULL; e ← FindNetworkNumber[net, FALSE]};
e: RoutingTableEntry;
LockedFindNet[]; --try searching first time
IF (e = NIL) OR (e.network = NIL) THEN
ERROR Router.NoTableEntryForNet; -- a net is not accessible unless we have a
-- rte AND a network pointer
delay ← e.delay; --value of interest
END; --GetDelay
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- GetRouteDetails
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
GetRouteDetails: PROCEDURE [destNet: NetworkNumber,
alwaysDetermineViaNet: BOOLEAN]
RETURNS [details: InrFriends.DriverDetails, delay: HopCount] =
BEGIN
e: RoutingTableEntry;
net: Driver.Network;
host: HostNumber;
LockedFindNet: ENTRY PROC = INLINE
{ENABLE UNWIND => NULL; e ← FindNetworkNumber[destNet, FALSE]};
LockedFindFarNet: ENTRY PROCEDURE [net: Driver.Network]
RETURNS [farNet: NetworkNumber] =
BEGIN ENABLE UNWIND => NULL;
<< net is a network driver that is anonyomous--it isn't assigned
its own network number. Point to Point connections between INRs
are anonymous E.g. a phoneline between two INRs.
This procedure searches to find the rte in the table
that uses <net> and has the lowest delay to a destination net of
all the rtes that use <net>. That rte's destNetwork should be
a viable network for reaching the INR at the far end of the anonymous
driver.
We make only one pass through the rtes. >>
bestHopsSoFar: HopCount ← infinityHopCount;
oneAway: HopCount ← localHop + 1;
farNet ← nullNetworkNumber;
FOR e: RoutingTableEntry ← routingTableHead, e.nextRTE
UNTIL e = NIL OR bestHopsSoFar = oneAway DO
IF e.network # net OR e.destNetwork = nullNetworkNumber
THEN LOOP; -- ignore
IF e.delay < bestHopsSoFar THEN
BEGIN
farNet ← e.destNetwork;
bestHopsSoFar ← e.delay;
END;
ENDLOOP;
END; --of LockedFindFarNet
-- Mainline of the procedure ...
LockedFindNet[]; --try searching first time
IF (e = NIL) OR (e.network = NIL) THEN
ERROR Router.NoTableEntryForNet; --no such entry in table
net ← e.network;
delay ← e.delay;
host ← e.route;
details.driverType ← net.device;
details.driverNetwork ← net.netNumber;
IF details.driverType = phonenet THEN
BEGIN
PhoneNetInternalState: TYPE = LONG POINTER TO PhoneNetInternalObject;
-- This better be the same as the first two fields of StateObject in
-- PhoneNetInternal def.
PhoneNetInternalObject: TYPE = MONITORED RECORD [
clientData: LONG UNSPECIFIED,
lineNumber: CARDINAL];
-- this LOOPHOLE-ing between the inr and a specific driver is both
-- amazingly yucky and useful. Sigh.
details.clientData ← LOOPHOLE [net.statsLevel0,
PhoneNetInternalState].clientData;
details.lineNumber ← LOOPHOLE [net.statsLevel0,
PhoneNetInternalState].lineNumber;
END;
IF details.driverType = x25 THEN
details.clientData ← net.statsLevel0;
IF delay # localHop THEN
BEGIN
details.via.socket ← System.nullSocketNumber;
details.via.host ← host;
details.via.net ← IF alwaysDetermineViaNet AND
net.netNumber = nullNetworkNumber THEN LockedFindFarNet [net] ELSE
net.netNumber;
END
ELSE details.via ← System.nullNetworkAddress;
END; -- of GetRouteDetails
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- GetRouteInfo
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
GetRouteInfo: PUBLIC PROCEDURE [net: System.NetworkNumber]
RETURNS [delay: HopCount, details: InrFriends.DriverDetails] =
BEGIN
[delay: delay, details: details] ← GetRouteDetails [destNet: net,
alwaysDetermineViaNet: TRUE];
END;
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- MisnumberedNetTrap
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
MisnumberedNetTrap: PROCEDURE = {Runtime.CallDebugger ["Misnumbered net trap."L]};
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- 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: PROCEDURE =
BEGIN
InternetRouterServerLocked: ENTRY PROCEDURE = INLINE
BEGIN
ENABLE UNWIND => NULL;
bufferHandle: Buffer.AccessHandle;
--create extra buffers because we are an inr
bufferHandle ← Buffer.MakePool [send: 0,
receive: extraBuffersForForwarding];
UNTIL pleaseStop DO
ENABLE ABORTED => EXIT;
WAIT internetRouterTimer;
IF pleaseStop THEN EXIT;
-- wait a random amount of time [0..7] seconds before sending out the
-- gratuitous response packet. This will help prevent all inrs
-- from sending at the same time.
Process.SetTimeout[@auxInternetRouterTimer,
Process.SecondsToTicks[Inline.LowHalf[System.GetClockPulses[]] MOD 8]];
WAIT auxInternetRouterTimer;
IF pleaseStop THEN EXIT;
SendGratuitousResponse [[nullNetworkNumber, System.broadcastHostNumber,
NSConstants.routingInformationSocket]];
StatIncr [@stats.gratuitousRoutingResponseSent];
ENDLOOP;
SendGratuitousResponse [to: [nullNetworkNumber, System.broadcastHostNumber,
NSConstants.routingInformationSocket], b: NIL,
allAreUnreachable: TRUE]; -- tell everyone not to use us as a route anymore
StatIncr [@stats.gratuitousRoutingResponseSent];
-- delete the buffers allocated for the INR
Buffer.DestroyPool [bufferHandle];
END; -- of InternetRouterServerLocked
-- start of procedure, when this process is first started it waits a while to allow
-- the routing table to be built by the incoming routing response packets.
Process.Pause[Process.MsecToTicks[100]];
Driver.ChangeNumberOfInputBuffers[TRUE];
InternetRouterServerLocked[];
Driver.ChangeNumberOfInputBuffers[FALSE];
END; --InternetRouterServer
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- NetAgtNetB
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
NetAgtNetB: PROC [a, b: NetworkNumber] RETURNS [BOOLEAN] = INLINE
BEGIN
--RETURNS[a > b];
RETURN[LOOPHOLE[CourierInternal.ExchWords[LOOPHOLE[a]], LONG CARDINAL] >
LOOPHOLE[CourierInternal.ExchWords[LOOPHOLE[b]], LONG CARDINAL] ];
END;
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- RoutingInformationPacket either sends or examine the packet depending
-- on if the packet is a routingInfoRequest or routingInfoResponse. As part
-- of an examination of a routingInfoResponse packet, the routing table is
-- updated.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RoutingInformationPacket: PROCEDURE [b: Buffer.Buffer]
RETURNS [bufferWasReturned: BOOLEAN] =
BEGIN
newRoute: HostNumber = b.ns.source.host;
routingPacketType: NSTypes.RoutingInfoType = b.ns.routingType;
incomingNetwork: Driver.Network ← b.network; -- check before using since
-- we aren't always holding the monitor
ExamineResponsePacket: ENTRY PROCEDURE =
BEGIN ENABLE UNWIND => NULL;
networkStillExists: BOOLEAN ← FALSE;
IF CommSvcFlags.doDebug AND
(b.ns.source.socket # NSConstants.routingInformationSocket) THEN
ERROR; -- why isn't the response pkt's source socket 1?
IF (b.ns.source.socket # NSConstants.routingInformationSocket) THEN
RETURN; -- don't use
IF b.ns.transportControl.hopCount > 0 THEN
BEGIN
-- routing response packets should never be forwarded
StatIncr [@stats.forwardedRoutingResponsesRecv];
RETURN; -- don't use
END;
IF NOT incomingNetwork.alive THEN RETURN; -- don't use
IF UpdateUnnumberedNetTable [b].use THEN
UpdateRoutingTable [b];
END; -- of ExamineResponsePacket
UpdateUnnumberedNetTable: INTERNAL PROC [b: Buffer.Buffer]
RETURNS [use: BOOLEAN] =
BEGIN << Sets a null network number. b.ns.source.net is the field to use
for setting the incomingNetwork.netNumber because we know this is a routing
response which came from the INR on this net! >>
use ← TRUE;
SELECT TRUE FROM
(incomingNetwork.netNumber = b.ns.source.net) => NULL; -- we know our net number and it matches with the routing response
(incomingNetwork.netNumber = nullNetworkNumber) =>
BEGIN -- our driver wants the new net number
incomingNetwork.netNumber ← b.ns.source.net; -- update
AddNetworkInternal[incomingNetwork];
END;
(b.ns.source.net # nullNetworkNumber) => -- since the incoming net number is interesting ('cause it isn't zero) and it didn't match, then the network has two different, non-zero net numbers. Log the occurance and crash.
BEGIN
StatIncr [@stats.misnumberedNetTrapHits];
MisnumberedNetTrap[];
ERROR; -- MisnumberedNetTrap should never return; but if it does ...
END;
ENDCASE => NULL;
END; --UpdateUnnumberedNetTable
-- START of procedure's main body
IF CommSvcFlags.doDebug AND (b.ns.source.host # myHostID)
AND incomingNetwork = NIL THEN ERROR;
-- driver didn't note the incoming network in the object?
-- do we handle this packet?
IF (b.ns.packetType # routingInformation)
OR (b.ns.source.host = myHostID
AND routingPacketType = routingInfoResponse)
--don't need to listen to myself
OR (newRoute = unknownHostID) -- would be unhelpful
OR (incomingNetwork = NIL AND b.ns.source.host # myHostID) -- driver didn't note the network in the object?
THEN RETURN [FALSE];-- NO, don't use this pkt
-- YES, a routingInfo packet for us (Yeah!)
IF doNSStats THEN Stats.StatIncr[statNSGatewayPacketsRecv];
SELECT TRUE FROM
(routingPacketType = routingInfoRequest) =>
BEGIN
SendRoutingInfoResponse[b.ns.source, b]; -- we respond to request
bufferWasReturned ← TRUE; -- SendRoutingInfoResponse proc
-- always returns the buffer that it is given
StatIncr [@stats.routingRequestRecv];
END;
(routingPacketType = routingInfoResponse) =>
BEGIN
pulses: System.Pulses ← System.GetClockPulses[];
ExamineResponsePacket[];
bufferWasReturned ← FALSE; -- we merely examined it
pulses ← System.Pulses[System.GetClockPulses[] - pulses];
PulsesBump [@stats.pulsesProcessingRoutingResponse, pulses];
StatIncr [@stats.routingResponseRecv];
END;
ENDCASE => bufferWasReturned ← FALSE; -- we should never get to this arm
END; --RoutingInformationPacket
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This process handles packets that come in over Socket # 1
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RoutingInformationSupplier: PROCEDURE =
BEGIN
BEGIN -- extra begin is to put the Enable within <timedOut>'s scope
myAddr: System.NetworkAddress = [
FindNetID[nullNetworkNumber],
myHostID, NSConstants.routingInformationSocket];
cH: Socket.ChannelHandle;
b: Buffer.Buffer;
cH ← Socket.Create [local: myAddr, send: 1, receive: 5];
Socket.SetWaitTime [cH, Socket.infiniteWaitTime];
Process.Detach [FORK BroadcastRoutingRequest[cH]]; --to build routing table.
UNTIL pleaseStop DO
ENABLE ABORTED => EXIT; -- the condition
-- variable that we would get aborted on is in the Socket.Get
b ← Socket.GetPacket [cH];
IF NOT RoutingInformationPacket[b].bufferWasReturned THEN
Socket.ReturnBuffer [b]; -- if the buffer wasn't returned, then we
-- return it here. Driver.PutOnGlobalDoneQueue would be overkill since
-- we know that we got the buffer through the Socket.Get procedure.
ENDLOOP;
Socket.Delete [cH];
END; -- extra end is because of the extra begin
END; -- of RoutingInformationSupplier
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- RoutingTableChanged
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RoutingTableChanged: PROCEDURE =
BEGIN
<< This process sends out gratuitous routing response packets for tuples that have changed. It will not send out packets faster than once per second >>
Wait: ENTRY PROCEDURE =
INLINE BEGIN ENABLE UNWIND => NULL;
WAIT routingTableChanged;
END;
UNTIL pleaseStop DO
ENABLE ABORTED => EXIT;
Wait [];
Process.Pause [Process.SecondsToTicks [1]];
SendGratuitousResponseLocked [to: [nullNetworkNumber,
System.broadcastHostNumber, NSConstants.routingInformationSocket],
b: NIL, allAreUnreachable: FALSE, onlyChangedEntries: TRUE];
StatIncr [@stats.gratuitousRoutingResponseSent];
ENDLOOP;
END; -- of RoutingTableChanged
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- SendGratuitousResponse
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
SendGratuitousResponse: INTERNAL PROCEDURE [to: System.NetworkAddress,
b: Buffer.Buffer ← NIL, allAreUnreachable, onlyChangedEntries: BOOLEAN ← FALSE] =
BEGIN ENABLE UNWIND => NULL;
-- This procedure will send a gratuitous type of routing response (information
-- will be sent on all of the entries we know about). Most often, this proc
-- called to send a broadcast gratuitous reponse to everyone every 30 seconds
-- or so. But it is also called when a request for information comes in that
-- asks for info on all the nets we know about.
-- If we are supplied with a buffer, then we'll use it and use its b.network
-- if the destination net address is the nullNetNumber.
-- If allAreUnreachable is TRUE, then the delay we'll use in all the tuples
-- will be <infinityHopCount>. This tells all listeners that we
-- are not a good route for any destinatination nets
-- This proc will send two or more pkts if there are too many tuples for one
-- packet.
nextRoutingEntry: RoutingTableEntry ← routingTableHead;
maxTuplesPerRoutingPacket: CARDINAL =
(NSTypes.maxIDPDataBytes - 2*SIZE[NSTypes.RoutingInfoType]) /
(2*SIZE[NSTypes.RoutingInfoTuple]);
tupleNumber: CARDINAL ← 0;
destNetwork: Driver.Network ← NIL;
IF b # NIL THEN
BEGIN
destNetwork ← b.network;
b.ns.destination ← to;
b.ns.pktLength ← NSTypes.bytesPerIDPHeader + 2*SIZE[NSTypes.RoutingInfoType];
END;
UNTIL nextRoutingEntry = NIL DO
SELECT TRUE FROM
nextRoutingEntry.destNetwork = nullNetworkNumber,
onlyChangedEntries AND (NOT nextRoutingEntry.changed) => NULL;
ENDCASE =>
BEGIN
-- handle this valid rte; Do we have a buffer?
IF b = NIL THEN
BEGIN
-- get and set a new buffer. Other fields of buffer are set by
-- RoutAndSendRoutingInfoResponse proc
b ← Driver.GetInputBuffer[!ABORTED => {b ← NIL; CONTINUE}];
IF b = NIL THEN RETURN; -- give up!
b.ns.destination ← to;
b.network ← destNetwork; -- RoutAndSendRoutingInfoResponse proc will
-- check that the b.network is valid, and set it if we are
-- broadcasting this response.
b.ns.pktLength ← NSTypes.bytesPerIDPHeader +
2*SIZE[NSTypes.RoutingInfoType];
tupleNumber ← 0;
END; -- of getting a new buffer
b.ns.routingTuple[tupleNumber] ← [nextRoutingEntry.destNetwork,
IF allAreUnreachable THEN infinityHopCount ELSE
MIN [nextRoutingEntry.delay + 1 + extraHops, infinityHopCount]]; -- we increment here!
nextRoutingEntry.changed ← FALSE; -- reset
tupleNumber ← tupleNumber + 1;
b.ns.pktLength ←
b.ns.pktLength + 2*SIZE[NSTypes.RoutingInfoTuple];
END; -- of handling a valid rte
nextRoutingEntry ← nextRoutingEntry.nextRTE;
IF b # NIL AND (
nextRoutingEntry = NIL --we have done all of the rte's-- OR
tupleNumber >= maxTuplesPerRoutingPacket --pkt is full--) THEN
BEGIN
IF NOT RoutAndSendRoutingInfoResponse[b] THEN
Driver.PutOnGlobalDoneQueue[b];
b ← NIL;
END; --of sending a routing buffer
ENDLOOP; --end of send loop
END; --SendGratuitousResponse
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- SendGratuitousResponseLocked
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
SendGratuitousResponseLocked: ENTRY PROCEDURE [
to: System.NetworkAddress, b: Buffer.Buffer ← NIL, allAreUnreachable,
onlyChangedEntries: BOOLEAN ← FALSE] = INLINE {
ENABLE UNWIND => NULL;
SendGratuitousResponse [to, b, allAreUnreachable, onlyChangedEntries];
};
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- SendRoutingInfoResponse
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
SendRoutingInfoResponse: PROCEDURE [
to: System.NetworkAddress, b: Buffer.Buffer] =
-- This proc will send out a response packet. It is given the incoming
-- routing request packet, which it will properly handle. It will set the
-- destination to be <to>.
BEGIN
maxTuplesPerRoutingPacket: CARDINAL =
(NSTypes.maxIDPDataBytes - 2*SIZE[NSTypes.RoutingInfoType]) /
(2*SIZE[NSTypes.RoutingInfoTuple]);
numberOfTuples: CARDINAL = (b.ns.pktLength - NSTypes.bytesPerIDPHeader -
2*SIZE[NSTypes.RoutingInfoType]) /
(2*SIZE[NSTypes.RoutingInfoTuple]);
SendRoutingInfoResponseLocked: ENTRY PROCEDURE
RETURNS [sent: BOOLEAN ← TRUE] =
BEGIN ENABLE UNWIND => NULL;
e: RoutingTableEntry;
FOR i: CARDINAL IN [0..numberOfTuples) DO
IF (b.ns.routingTuple[i].objectNetID = anyNetNetworkNumber) OR
(b.ns.routingTuple[i].objectNetID = anyNetNetworkNumberFor860)
-- Hack for the dumb 860!
THEN
RETURN [FALSE]; -- we'll send him a gratitous packet with all the rte's
e ← FindNetworkNumber [b.ns.routingTuple[i].objectNetID, FALSE];
b.ns.routingTuple[i].interrouterDelay ←
IF (e = NIL) OR (e.network = NIL) THEN infinityHopCount -- no route
ELSE MIN [e.delay + 1, infinityHopCount]; -- we increment the count here!
ENDLOOP;
b.ns.pktLength ← NSTypes.bytesPerIDPHeader + 2*SIZE[NSTypes.RoutingInfoType]
+ numberOfTuples*2*SIZE[NSTypes.RoutingInfoTuple];
b.ns.destination ← to;
IF NOT RoutAndSendRoutingInfoResponse[b] THEN
Socket.ReturnBuffer[b];
<< Driver.PutOnGlobalDoneQueue would be overkill since we know that
we got the buffer through the Socket.Get procedure. We don't
return[False] since the source would then be sent a gratuitous
type of packet. >>
END; -- of SendRoutingInfoResponseLocked
-- start of procedure
IF (numberOfTuples = 0) OR (numberOfTuples > maxTuplesPerRoutingPacket)
OR NOT SendRoutingInfoResponseLocked[] THEN
SendGratuitousResponseLocked [to, b];
StatIncr [@stats.specificRoutingResponseSent];
END; -- of SendRoutingInfoResponse
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- This routine routs a routing inforamtion response packet for its
-- destination and sends it. A few of the packet's field should already be
-- set coming into here. Note the two special case: sending to self and
-- sending to everyone.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RoutAndSendRoutingInfoResponse: INTERNAL PROCEDURE [b: Buffer.Buffer]
RETURNS [success: BOOLEAN ← TRUE] =
BEGIN
-- Routs and sends a routing information response.
-- Should be called from inside the monitor.
-- The incoming b.network, b.destination, and b.ns.pktLength should
-- be already set. Source net is set to be the network's, unless = 0 and
-- destination socket not #1 - then it's set to a more informative number.
-- Note the special case handling when the destination is us!
network: Network ← b.network;
immediateHost: HostNumber ← b.ns.destination.host;
e: RoutingTableEntry;
destinationIsMe: BOOLEAN ← b.ns.destination.host = myHostID;
b.type ← ns;
b.ns.packetType ← routingInformation;
b.ns.transportControl ← initialTransportControl;
b.ns.routingType ← routingInfoResponse;
b.ns.source ← [IF (network # NIL) THEN network.netNumber ELSE
nullNetworkNumber, myHostID, NSConstants.routingInformationSocket];
IF (b.ns.destination.socket # NSConstants.routingInformationSocket) AND
(b.ns.source.net = nullNetworkNumber) THEN
-- give them better information
b.ns.source.net ← FindNetIDInternal [nullNetworkNumber];
IF destinationIsMe THEN
BEGIN
RouterInternal.SendPacket [b];
RETURN;
END;
-- destination is someone else, determine correct network
IF b.allNets ← (b.ns.destination.host = System.broadcastHostNumber) THEN
BEGIN
network ← b.network ← Driver.GetDeviceChain[];
b.ns.source.net ← b.ns.destination.net ← network.netNumber;
END; -- broadcast on all attached networks, start with the first one.
IF NOT network.alive THEN RETURN [FALSE];
IF NOT b.allNets AND (b.ns.destination.net # nullNetworkNumber) THEN
-- if the dest. is net 0, use immediateHost's default
BEGIN -- find the route to this guy
e ← FindNetworkNumber [b.ns.destination.net, FALSE];
IF (e = NIL) OR ((network ← b.network ← e.network) = NIL)
THEN RETURN [FALSE];
-- no route to destination (assume we already know about all routes
-- since we are an internetwork router)
immediateHost ← IF (e.route = unknownHostID) THEN
b.ns.destination.host -- we are attached to destination net --
ELSE e.route -- send to next inr on path to destination net;
END;
IF RouterInternal.checkIt THEN Checksums.SetChecksum[b]
ELSE b.ns.checksum ← 177777B;
network.encapsulateAndSendNS[b, immediateHost]; -- IF this buffer is a
-- broadcast, the buffer is first broadcast on this network and then
-- put on the done queue. The Dispatcher will reset buffer's network
-- to the next network on the driver chain and then resend the buffer
-- on this next network. This process happens recursively until the
-- buffer has been broadcast on all the networks on the driver chain.
-- The Dispatcher knows to do this by the allNets flag.
END; -- of RoutAndSendRoutingInfoResponse
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- UpdateRoutingTable
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
UpdateRoutingTable: INTERNAL PROCEDURE [b: Buffer.Buffer] =
BEGIN
i: CARDINAL;
e: RoutingTableEntry ← NIL;
newDelay: CARDINAL;
changed: BOOLEAN ← FALSE;
t: NSTypes.RoutingInfoTuple;
tuples: CARDINAL = -- number of tuples in the packet.
(b.ns.pktLength - NSTypes.bytesPerIDPHeader -
2*SIZE [NSTypes.RoutingInfoType]) / (2*SIZE[NSTypes.RoutingInfoTuple]);
FOR i IN [0..tuples) DO
<< this is all reasonably hairy. See page 28 of Yogen's Internet Transport Protocols book for further information>>
t ← b.ns.routingTuple[i];
newDelay ← Inline.BITAND[mask, t.interrouterDelay];
-- ignore high bits.
IF newDelay = localHop THEN IF CommSvcFlags.doDebug THEN ERROR ELSE LOOP; -- misleading tuple
IF (e ← FindNetworkNumber[t.objectNetID, FALSE]) # NIL THEN
BEGIN -- update an already present tuple
IF e.route = b.ns.source.host -- new info from our supplier (case 2 from the spec)
OR e.timeUnits < alternatePathTimeUnitThreshHold -- time to get better info (case 3)
OR e.network = NIL -- need better info
OR newDelay < e.delay -- better route (case 4)
THEN
BEGIN
e.changed ← e.delay # newDelay;
changed ← changed OR e.changed;
-- to the outside world (who hear via routing info packets), there has been a change only if the <delay> has changed. Or if a destination net has been added
e.delay ← newDelay;
e.route ← b.ns.source.host;
e.network ← b.network;
IF e.delay < infinityHopCount THEN e.timeUnits ← updateCycles
ELSE
BEGIN
e.delay ← infinityHopCount; -- be sure that it isn't > infinityHopCount
e.network ← NIL;
e.route ← System.nullHostNumber;
END;
END;
END -- End of update of existing tuple.
ELSE -- no tuple so far
-- collect new info because, as an INR, we know about every net
IF newDelay < infinityHopCount -- is it accessable?
AND t.objectNetID # anyNetNetworkNumber -- Paranoia
AND t.objectNetID # System.nullNetworkNumber -- Paranoia
THEN
BEGIN
e ← CommSvcHeap.MakeNode[n: SIZE[RoutingTableObject]];
e↑ ← [
nextRTE: NIL, nextNSE: NIL, destNetwork: t.objectNetID, delay: newDelay,
timeUnits: updateCycles, route: b.ns.source.host,
network: b.network, changed: TRUE];
AddEntry[e];
changed ← TRUE;
END;
ENDLOOP; --FOR i IN [0..tuples) do
--if something has changed then propagate the information
IF changed THEN NOTIFY routingTableChanged;
END; --UpdateRoutingTable
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- ChangedState
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
ChangedState: PROCEDURE [network: Network] =
BEGIN
--used by driver when a network changes.
RemoveNetworkLocked[network];
AddNet[network];
END; --ChangedState
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- Start-up/ Shut-down routines. When a new INR is register with Pilot
-- with the routine RoutingTable.Register[], the old INR is automatically
-- unregistered. Upon the call to register, Pilot calls the stop routine
-- for the previously registered INR and then subsequently calls the start
-- routine of the newly registered INR.
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
ActivateINR: PUBLIC PROCEDURE =
BEGIN --will be called by IRS to start INR
IF pleaseStop THEN RoutingTable.Register[ptrToRto];
END;
DeactivateINR: PUBLIC PROCEDURE =
BEGIN --will be called by IRS to stop INR.
IF NOT pleaseStop THEN RoutingTable.Register[NIL];
END;
SetNSFudge: PUBLIC PROCEDURE [hops: CARDINAL] =
BEGIN
extraHops ← hops;
END;
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- BroadcastRoutingRequest
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
BroadcastRoutingRequest: PROCEDURE
[cH: Socket.ChannelHandle, net: NetworkNumber ← anyNetNetworkNumber] =
BEGIN
-- broadcasts a routing information request on all attached networks.
-- If <net> is supplied, the request will be for info on that net only, else
-- information will be requested for information on all networks the routing
-- information suppliers know about.
b: Buffer.Buffer;
FOR i:CARDINAL IN [1..3) DO
IF (b ← Buffer.GetBuffer [type: ns, aH: Socket.GetBufferPool[cH],
function: send, size: smallBuffer, wait: TRUE]) # NIL THEN
BEGIN
b.type ← ns;
b.ns.packetType ← routingInformation;
b.ns.transportControl ← initialTransportControl;
b.ns.source.host ← myHostID;
b.ns.destination.socket ← b.ns.source.socket ←
NSConstants.routingInformationSocket;
b.ns.pktLength ← NSTypes.bytesPerIDPHeader +
2*(SIZE[NSTypes.RoutingInfoType]+SIZE[NSTypes.RoutingInfoTuple]);
b.ns.routingType ← routingInfoRequest;
b.ns.routingTuple[0] ← [net, infinityHopCount];
RouterInternal.BroadcastThisPacket[b];
END;
Process.Pause [Process.SecondsToTicks [1]];
ENDLOOP;
END; -- of BroadcastRoutingRequest
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- Stop
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
Stop: PROCEDURE =
BEGIN
RoutingTableDeactivate[];
JOIN routingInformationSupplierFork;
JOIN internetRouterServerFork;
JOIN decrementRoutingTableEntriesFork;
CleanUpRoutingTable[];
StopStats[];
END; --Stop
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- Start
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
Start: PROCEDURE =
BEGIN
pleaseStop ← FALSE; << FALSE shows that we are ON >>
StartStats[];
RoutingTableActivate[];
FOR n: Network ← Driver.GetDeviceChain[], n.next UNTIL n = NIL DO
AddNet[n]; ENDLOOP;
routingInformationSupplierFork ← FORK RoutingInformationSupplier [];
internetRouterServerFork ← FORK InternetRouterServer[];
decrementRoutingTableEntriesFork ← FORK DecrementRoutingTableEntries [];
routingTableChangedFork ← FORK RoutingTableChanged [];
END; --Start
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- RoutingTableActivate
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RoutingTableActivate: ENTRY PROCEDURE =
BEGIN ENABLE UNWIND => NULL;
routingTableHead ← NIL;
myHostID ← Router.FindMyHostID[];
routingTableSize ← 0;
END; --RoutingTableActivate
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
-- RoutingTableDeactivate
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
RoutingTableDeactivate: ENTRY PROCEDURE = INLINE
BEGIN ENABLE UNWIND => NULL;
pleaseStop ← TRUE; << TRUE shows that we are OFF >>
Process.Abort [routingInformationSupplierFork];
-- poke him out of the Socket.Get on socket # 1
Process.Abort [internetRouterServerFork];
-- poke him out of WAITing to send a gratuitous pkt
Process.Abort [decrementRoutingTableEntriesFork];
-- poke him out of the WAIT timer statement
Process.Abort [routingTableChangedFork];
-- poke him out of the WAIT routingTableChanged statement
END; --RoutingTableDeactivate
--**************** Statistics ****************
GetRoutingTableSize: PUBLIC PROCEDURE RETURNS [LONG POINTER TO
READONLY CARDINAL] = {RETURN [LONG [@routingTableSize]]};
GetStats: PUBLIC PROCEDURE RETURNS [
LONG POINTER TO READONLY InrStats.Stats, System.GreenwichMeanTime] =
{RETURN [stats, lastGetStats ← System.GetGreenwichMeanTime[]]};
SearchDurationBump: PROCEDURE [
pulses: System.Pulses, search: InrStats.RoutingTableSearch] = INLINE
BEGIN
IF (stats = NIL) THEN RETURN;
pulses ← System.Pulses[System.GetClockPulses[] - pulses];
StatBump [@stats.searchTable[search].totalSearches, 1];
PulsesBump [@stats.searchTable[search].pulsesSearching, pulses];
END; --of SearchDurationBump
StartStats: PROCEDURE =
BEGIN
z: UNCOUNTED ZONE = CommSvcHeap.GetInrHeap [];
stats ← z.NEW [InrStats.Stats ← [System.GetGreenwichMeanTime[]]];
END;
StopStats: PROCEDURE =
BEGIN
z: UNCOUNTED ZONE = CommSvcHeap.GetInrHeap [];
z.FREE [@stats];
stats ← NIL;
END;
StatIncr: PROCEDURE [counter: LONG POINTER TO LONG CARDINAL] = INLINE
--add one to counter
BEGIN
--locals
counter↑ ← (counter↑ + 1) MOD (LAST[LONG CARDINAL] - 1);
END;
StatBump: PROCEDURE [
counter: LONG POINTER TO LONG CARDINAL, bumpAmount: CARDINAL] = INLINE
BEGIN
--locals
<<
--add bumpAmount to counter; if bumpAmount < 10000, there will never
--be overflow
counter↑ ← (counter↑ + bumpAmount) MOD (LAST[LONG CARDINAL] - 10000);
>>
counter↑ ← MIN[(counter↑ + bumpAmount), (LAST[LONG CARDINAL] - 10000)];
END;
PulsesBump: PROCEDURE [
counter: LONG POINTER TO System.Pulses, bumpAmount: System.Pulses] = INLINE
BEGIN
overflow: System.Pulses = LOOPHOLE[LAST[LONG CARDINAL]];
counter↑ ← System.Pulses[MIN[(counter↑ + bumpAmount), overflow]];
END;
--**************** Main Program ****************
--initialization (Cold)
Process.SetTimeout[@internetRouterTimer, Process.MsecToTicks[25500]];
-- set for 26.5 seconds so that when the extra random wait [0..7] seconds
-- is added, the average time between gratuitous pkts is 30 seconds
Process.SetTimeout[@auxInternetRouterTimer, Process.MsecToTicks[500]];
Process.DisableTimeout [@routingTableChanged];
Process.EnableAborts [@internetRouterTimer];
Process.EnableAborts [@auxInternetRouterTimer];
Process.EnableAborts [@routingTableChanged];
END. --RoutingTableImpl module.
<<
LOG
30-Dec-82 10:17:11 AOF Allow for SendErrorPacket consuming errored buffer.
17-Mar-83 13:03:09 AOF Separate from Pilot.
18-Mar-83 16:57:40 SRB Made into an INR. Added Activate/DeactivateINR procs to register/unregister INR rto with Router. Deleted GetRoutingEntry, RoutingTableCacheFault, BroadcastRoutingRequest. Fill proc. has become a NOP, also GetDelay raises an ERROR if destNet is not found in INR table
22-Mar-83 16:07:11 SRB Deleted ProbeAnInternetRouter and all the counters & timers that go with it. Simplified FindNetworkNumberLocked
22-Mar-83 18:21:48 SRB Re-introduced BroadcastRoutingRequest(needed to set up the Routing Table on activation of the INR). Simplified RoutingInformationPacket (deleted tests of "are we an INR?")
23-Mar-83 13:33:01 SRB Deleted SanityCheck(it was incorrect to say destNets with 0 delay were an ERROR)
24-Mar-83 11:58:37 SRB BroadcastRoutingRequest returns immediately. Deleted maxRouterDelay & associated checks. Fixed up Start sequence of events. ActivateINR now takes as input param. the number of buffers to be allocated for internet.routing.
6-Jun-83 14:54:53 SRB Replaced CommHeap with CommSvcHeap. Detached BroadcastRoutingRequest procedure in order to build up routing table. BroadcastRoutingRequest now continues broadcasting (up to a maximum of 15 times) until it finds that UpadateRoutingTable has set routingTableChanged to TRUE - meaning that at least one routingInfo packet was received and the routing table is not empty anymore.
Open issues at start-up time: 1) Should we wait after detaching BroadcastRoutingRequest. 2) How do we acquire a network number - through IRS, drivers added by IRS, Pilot, etc. there needs to be some careful synchronization between IRS, Drivers and INR.
25-Jul-83 18:12:46 LSK Don't check that a driver is in driver chain when responding to routing info request since a) driver may be part of clusternet (not on global chaion) b) AOF says checking the alive bit is all that is needed
7-Oct-83 15:38:09 LSK Update to Klamath
7-Oct-83 18:54:35 LSK Forwarding stats doesn't all reset now
9-Oct-83 15:55:13 LSK Created buffer pool with 40 pkts for forwarding. Use small pkts for broadcasting routing request. Now have three processes alive: 1 to age table entries. Second to handle pkts that come in on socket # 1, and the third process sends gratuitous pkts.
10-Oct-83 13:22:05 LSK Update to new InrFriends def
13-Oct-83 18:35:27 LSK Only Activate if we are stopped, only deactivate if we are started
14-Oct-83 18:21:57 LSK Redo Route enumeration
16-Oct-83 14:19:21 LSK Added InrFriends.GetRouteInfo
17-Oct-83 15:22:13 LSK Fix byDistance case of EnumerateRoutes
17-Oct-83 19:10:16 LSK Initialize a couple of variables (sigh.)
18-Oct-83 13:32:44 LSK Supply phonenetwork clientData in GetDetails procedure
27-Nov-83 18:51:26 LSK Updated to new PhoneNet driver
29-Nov-83 21:44:56 LSK Use PhoneNetFriends instead of PhoneNetInternal
3-Dec-83 13:52:00 LSK Added FlushCacheProc field to RoutingTable.Object, send out routing response when new network is added
16-Dec-83 17:55:19 LSK Don't use routing responses that aren't from socket 1 or that are forwarded. Don't crash with misnumbered net trap unless during doDebug
5-Jan-84 11:42:24 LSK Added some unwind catch code. Initialize stats counters.
9-Feb-84 16:28:54 LSK Bug fix noticed by Hal.
16-Feb-84 16:55:50 LSK Use CommFlags.doStats where appropriate; Added 1 Sec delay before sending routing packet; adjusted internetRouterTimer; If a driver does go away, set the delay to be 16, not 15. Send out routing responses with max delay of 16; Munged UpdateRoutingTable
17-Feb-84 17:50:00 LSK Only send out information on changed routes when a route changes. (Send information on all routes about every 30 sec.)
17-Feb-84 18:56:39 LSK Set clientData for X25 routes
22-Mar-84 23:06:44 LSK Added unwind catch phrases so the inr would deactivate instead of hang; added stats; depend on PhoneNetInternal at compile time instead of PhoneNetFriends at runtime. (The Phonenet is not included in the bootfile.)
23-Mar-84 18:42:45 LSK Start the stats sooner in the Start proc
25-Mar-84 15:36:41 LSK Don't scribble over memory; set the stats.timeActivated field
28-Mar-84 17:02:28 LSK Respond to the 860's idea of the anyNet network number in routing request pkt's
28-Mar-84 17:47:18 LSK Don't send out routing info pkts larger than IDP max length
5-Jun-84 19:50:03 LSK Always crash if we hit a misnumbered net trap
6-Jun-84 16:53:53 LSK okay to receive a RoutingInfo response that comes from a driver not on the global chain. (Such is the case for INR's attached to our clusternet.)
6-Jun-84 19:34:16 LSK/DMT Broke dependency on PhoneNetInternal by LOOPHOLE.
10-Sep-84 10:31:10 Leong bump stats.bytesForwarded by b.ns.pktLength which is ALREADY in bytes (was incremented by b.ns.pktLength*2)
10-Sep-84 11:45:19 Leong GetStats now also returns a snap time
10-Sep-84 16:04:33 Leong stats.tupleIndexTable is now properly incremented
12-Sep-84 14:13:46 Leong stats initialized to NIL and ForwardingStats checks for NIL (Bug fix noticed by Hal)
13-Sep-84 17:19:40 Leong Added stats.msSearchingRoutingTable
19-Sep-84 15:21:32 Leong Changed stats.msSearchingRoutingTable to searchTable
19-Oct-84 15:22:30 Leong Add fudge hops when sending RoutingReponse packets; export RoutingFudges.SetNSFudge; remove SHARE clause
22-Oct-84 13:00:39 Leong Keep track of pulses instead of milliseconds
23-Oct-84 15:54:04 Leong StatBump uses MIN instead of MOD; always collect NS stats (ignore CommFlags.doStats)
>>