package SSF.Net; import SSF.OS.*; import com.renesys.raceway.SSF.*; import com.renesys.raceway.DML.*; /** A simple FIFO packet queue. */ public class droptailQueue implements packetQueue { private long lastTransmitTime = 0; private long queueingDelay = 0; // in ticks private long maxQueueingDelay = Long.MAX_VALUE; private NIC forNIC; private Host localHost; public boolean pktDropped; int tcpdrops=0; int udpdrops=0; int udppkts=0; int tcppkts=0; /** auxiliary monitoring variable */ public int pktCount = 0; /** auxiliary monitoring variable */ public int pktDropCount = 0; public int tcpDropCount=0; private PacketQueueMonitor myMonitor = null; public static Net topnet; public droptailQueue() {} /** Called by NIC if DML attribute interface.queue is omitted; * then droptailQueue is the default packetQueue installed. */ public droptailQueue(NIC nic) { forNIC = nic; maxQueueingDelay = (long)((new Long(nic.buffersize)).longValue()*8./nic.bitrate()); } /** Does not accept any user-defined Configuration, required by interface packetQueue. * Obtains values of attributes buffer and bitrate * from the instance of SSF.Net.NIC that constructs this droptailQueue. */ public void config(SSF.Net.NIC nic, Configuration cfg) { forNIC = nic; maxQueueingDelay = (long)((new Long(nic.buffersize)).longValue()*8./nic.bitrate()); topnet = ((Host)forNIC.inGraph()).net; // set a reference to the top-level Net } private class WrapupThread implements Runnable { public void run() { System.out.println("fornic="+ (forNIC.ipAddr)+" localhost.nhi="+localHost.nhi+" udppkts="+udppkts+" tcppkts="+tcppkts+" pktCount ="+pktCount +" pktdropcount="+pktDropCount+" tcpdrops="+tcpdrops+" udpdrops="+udpdrops); } } /** Required by interface packetQueue. Called by NIC.init(). */ public void init() { localHost = (Host)forNIC.inGraph(); } /** Set reference to a correctly configured class implementing * the Java interface PacketQueueMonitor. */ public void setMonitor(PacketQueueMonitor mon) { myMonitor = mon; } /** * Logical model: The Buffer holds N bits max; bits go out one * by one at the NIC bitrate. If attempt to enqueue a message * whose size is larger than the currently available free buffer space, * drop it. * queueingDelay is measured in integer multiples of simulated time "ticks". * Warning: if Net.frequency (ticks per second) is smaller than * NIC's bitrate (bits/sec) the delay calculations are not * accurate enough to obtain correct value of number of bits * in the buffer. * Transmit a message. Each interface tracks its "queueing delay," * which accumulates as packets are written out. Each packet * contributes its transmission time (size in bits / bitrate) to the * queueing delay of future packets. This guarantees that the * interface will never exceed the local configured bitrate.

* Fairness among competing flows is an entirely separate * issue; without buffering and write-behind interleaving, latecomers * will be delayed by early arrivals, even if they were written * "simultaneously" by different traffic sources and should therefore * compete for timeslots.

* If the buffer is full (that is, the number of bytes that have * already been transmitted in this timeslot would fill the configured * buffer size), then drop the packet rather than scheduling it.

* Return true if a packet is successfully enqueued, or false if the * queue rejects the packet. */ public boolean enqueue(ProtocolMessage msg) { boolean tcp=false; boolean udp=false; pktDropped = false; pktCount++; IpHeader ipHeader = (IpHeader) msg; String pktpayload=ipHeader.payload().toString(); if (pktpayload.indexOf("TCP")!=-1){ tcp=true; tcppkts++; } if ( pktpayload.indexOf("UDP")!=-1){ udp=true; udppkts++; } long qdelay= calibrate(); long testqueueingDelay = queueingDelay + (long)(8.*msg.size() / forNIC.bitrate()); int seqno=0; if (udp) seqno=(int)(Integer.parseInt(pktpayload.substring( pktpayload.indexOf("seqno=")+6, pktpayload.indexOf("sendtime")-1))); if (!tcp && (udp && (0!=seqno))) { if (testqueueingDelay>maxQueueingDelay) { if (((localHost.nhi.equals("0:1"))|| (forNIC.buffersize==199)) && ((localHost.now()/(double)SSF.Net.Net.seconds(1.0))>=150.00) ) { if (!tcp) pktDropCount++; if (tcp) tcpDropCount++; } forNIC.drop(msg); pktDropped = true; if (pktpayload.indexOf("TCP")!=-1) tcpdrops++; else if (pktpayload.indexOf("UDP")!=-1) udpdrops++; } if (myMonitor != null) myMonitor.receive(msg); if (pktDropped) { return false; } }//tcp queueingDelay = testqueueingDelay; PacketEvent pevt = new PacketEvent(msg); if (forNIC.dumpTo!=null) forNIC.dumpTo.dump(pevt); forNIC.link_hw.transmit(forNIC,pevt,queueingDelay); return true; } /** If we have moved forward in time, recalibrate the * accumulated delay so that it remains relative to "now". * Re-calibrate before every transmission. Returns the * recalibrated accumulated queueing delay. */ private long calibrate() { long now = localHost.now(); if (now!=lastTransmitTime) { queueingDelay -= (now-lastTransmitTime); if (queueingDelay<0) queueingDelay = 0; lastTransmitTime = now; } return queueingDelay; } /** Returns queue size in bits at the moment of calling. * Queue size is calculated as queueing delay * (long, in tick units) times interface bitrate (double, in bits/tick) * therefore it is rounded down to nearest long integer value. */ public long getNumberOfBitsInQueue() { return (long)(forNIC.bitrate()*calibrate()); } } /*= =*/ /*= Copyright (c) 1997--2000 SSF Research Network =*/ /*= =*/ /*= SSFNet is open source software, distributed under the GNU General =*/ /*= Public License. See the file COPYING in the 'doc' subdirectory of =*/ /*= the SSFNet distribution, or http://www.fsf.org/copyleft/gpl.html =*/ /*= =*/