-- Copyright (C) 1983, 1985  by Xerox Corporation. All rights reserved. 
-- ForwarderStats.mesa, HGM,  6-Aug-85 21:00:57

DIRECTORY
  Buffer USING [],
  Driver USING [GetDeviceChain, Network],
  ForwarderDefs USING [
    Counters, GetPointerToPupGateStats, ForwardStatsEntry, TransitMatrixEntry,
    statGateInfoReplies, forwardVersion, forwarderStatsReply],
  Stats USING [StatCounterIndex, StatsGetCounters],
  Protocol1 USING [GetContext],
  PupWireFormat USING [MesaToBcplLongNumber],
  PupDefs USING [PupBuffer, ReturnPup],
  PupRouterDefs USING [NetworkContext],
  PupTypes USING [maxDataWordsPerGatewayPup];

ForwarderStats: PROGRAM
  IMPORTS PupWireFormat, Stats, ForwarderDefs, Protocol1, PupDefs, Driver
  EXPORTS Buffer, ForwarderDefs =
  BEGIN OPEN PupDefs;

  Network: PUBLIC TYPE = Driver.Network;

  stats: LONG POINTER TO ARRAY Stats.StatCounterIndex OF LONG CARDINAL =
    Stats.StatsGetCounters[];

  -- This may be too soon (before initialization), and/or too late (page fault)
  firstNetwork: Driver.Network ← Driver.GetDeviceChain[];

  ForwarderStats: PUBLIC PROCEDURE [b: PupBuffer] =
    BEGIN OPEN ForwarderDefs;
    packets: LONG POINTER TO ForwarderDefs.Counters;
    bytes: LONG POINTER TO ForwarderDefs.Counters;
    nets: CARDINAL;
    limit: CARDINAL;
    AddStat: PROCEDURE [s, d: CARDINAL, n: LONG CARDINAL] =
      BEGIN
      IF n = 0 THEN RETURN;
      IF t = limit THEN RETURN;  -- Buffer full
      t ← t + 1;
      tme↑ ← [s, d, PupWireFormat.MesaToBcplLongNumber[n]];
      tme ← tme + SIZE[TransitMatrixEntry];
      END;
    n, t, length: CARDINAL ← 0;
    fse: LONG POINTER TO ForwardStatsEntry;
    tme: LONG POINTER TO TransitMatrixEntry;
    [packets, bytes, nets] ← ForwarderDefs.GetPointerToPupGateStats[];
    fse ← LOOPHOLE[@b.pup.pupWords];
    length ← SIZE[ForwardStatsEntry];
    FOR from: Driver.Network ← firstNetwork, from.next UNTIL from = NIL DO
      fromContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[from, pup];
      b.pup.pupWords[length + n] ← fromContext.pupNetNumber;
      n ← n + 1;
      ENDLOOP;
    length ← length + n;
    limit ← (PupTypes.maxDataWordsPerGatewayPup - SIZE[ForwardStatsEntry] - n)/
      SIZE[TransitMatrixEntry];
    tme ← LOOPHOLE[@b.pup.pupWords + length];
    IF packets # NIL THEN
      BEGIN
      FOR from: Driver.Network ← firstNetwork, from.next UNTIL from = NIL DO
	fromContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[from, pup];
        AddStat[fromContext.pupNetNumber, 0, packets[from.index + 0*nets]];
        FOR to: Driver.Network ← firstNetwork, to.next UNTIL to = NIL DO
	  toContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[to, pup];
          AddStat[
            fromContext.pupNetNumber, toContext.pupNetNumber, packets[
            from.index + to.index*nets]];
          ENDLOOP;
        ENDLOOP;
      END;
    IF bytes # NIL THEN
      BEGIN
      FOR from: Driver.Network ← firstNetwork, from.next UNTIL from = NIL DO
	fromContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[from, pup];
        AddStat[fromContext.pupNetNumber, 0, bytes[from.index + 0*nets]];
        FOR to: Driver.Network ← firstNetwork, to.next UNTIL to = NIL DO
	  toContext: PupRouterDefs.NetworkContext ← Protocol1.GetContext[to, pup];
          AddStat[
            fromContext.pupNetNumber, toContext.pupNetNumber, bytes[
            from.index + to.index*nets]];
          ENDLOOP;
        ENDLOOP;
      END;
    length ← length + t*SIZE[TransitMatrixEntry];
    fse↑ ← [
      version: forwardVersion,
      routingInfoRequests: PupWireFormat.MesaToBcplLongNumber[
      stats[statGateInfoReplies]], numberOfNetworks: n, numberOfTMEs: t];
    ReturnPup[b, forwarderStatsReply, 2*length];
    END;

  END.