singrdk/base/Services/NetStack/Runtime/Mux.cs

142 lines
4.7 KiB
C#

// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//#define DEBUG_MUX
using NetStack.Common;
using System;
using System.Collections;
using System.Net.IP;
using Drivers.Net;
using NetStack.NetDrivers;
using Microsoft.Singularity;
namespace NetStack.Runtime
{
// This class provides the basic multiplexing of packets as
// they go out to a network device. This component of the
// system is critical for several reasons. First, it must
// handle two modes of operation (where the NIC is faster
// than the computer, and where the computer is faster
// than the NIC). Second, it is the place in the
// system where we do bandwidth resource sharing, possibly
// including non-best-effort behaviour (such as weighted
// share or CBR).
public class Multiplexer
{
// We should of course have multiple queues and schedule
// them cleverly.
private Queue q;
private IAdapter! ad;
public IAdapter! Adapter { get {return ad;} }
private NetPacket [] txBuffer;
private int maxSlotsFree;
private int maxBackLog;
private int directs; // Packets sent with SendDirect that
// may be shoved into the queue at any time - we should
// ditch SendDirect ASAP and add sessions for ARP and ICMP.
public Multiplexer(Queue q, IAdapter! ad)
{
this.q = q;
this.ad = ad;
int capacity = ad.TxSlotsFree;
this.txBuffer = new NetPacket [capacity];
this.maxSlotsFree = ad.TxSlotsFree;
this.maxBackLog = ad.TxSlotsFree;
base();
DebugPrint("TxBuffer capacity: {0}\n", capacity);
DebugStub.Assert(capacity > 0);
}
[ System.Diagnostics.Conditional("DEBUG_MUX") ]
private static void DebugPrint(string format, params object[] args)
{
DebugStub.Print("Mux: {0}",
__arglist(String.Format(format, args))
);
}
public bool IsBackLogged
{
get { return this.q.Count >= this.maxBackLog; }
}
public int FreeBufferSpace
{
get { return Math.Max(this.maxBackLog - this.q.Count, 0); }
}
public void SendBuffered(NetPacket! packet)
{
// This is the preferred way of sending packets as it
// allows us to gather up larger groups of packets to
// send.
DebugStub.Assert(packet.Length <= 1514);
q.Enqueue(packet);
DebugPrint("SendBuffered free = {0} queued = {1}\n",
ad.TxSlotsFree, q.Count);
DebugStub.Assert(q.Count <= this.maxBackLog + directs);
}
public void PushSendBuffer()
{
int txCount = Math.Min(ad.TxSlotsFree, q.Count);
DebugPrint("PushSendBuffer free = {0} queued = {1}\n",
ad.TxSlotsFree, q.Count);
if (txCount > 0) {
for (int i = 0; i < txCount; i++) {
txBuffer[i] = (NetPacket)q.Dequeue();
}
for (int i = txCount; i < txBuffer.Length; i++) {
// Paranoia (if it's wrong lower down, it might send
// a duplicate).
txBuffer[i] = null;
}
ad.PopulateTxRing(txBuffer, (uint)txCount);
// If stack has placed packets directly in buffer for
// send decrement counter, we only count directs to check
// the queue does not grow unbounded.
directs -= Math.Max(0, directs - txCount);
}
}
// Simpler function for sending a single packet
public void SendDirect(NetPacket! packet)
{
// This method should be deprecated
// Everything should have an associated session and be
// sent from the outgoing queues handler.
directs ++;
SendBuffered(packet);
DebugPrint("SendDirect\n");
PushSendBuffer();
}
public NetStatus OnAdapterSendComplete(Dispatcher.CallbackArgs unused)
{
ad.GetTransmittedPackets();
DebugPrint("OnAdapterSendComplete free = {0} queued = {1}\n",
ad.TxSlotsFree, q.Count);
Core.Instance().SignalOutboundPackets();
return NetStatus.Code.RT_OK;
}
} // Multiplexer
} // NetStack.Runtime
// End