// ==++== // // 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