|
From: <bro...@us...> - 2008-02-19 02:42:51
|
Revision: 113
http://gridsim.svn.sourceforge.net/gridsim/?rev=113&view=rev
Author: brobergj
Date: 2008-02-18 18:42:56 -0800 (Mon, 18 Feb 2008)
Log Message:
-----------
*FlowRouter simulates a flow network router with RIP as the advertising
protocol (adapted from RIPRouter.java)
*It still depends on a scheduler although it performs no useful function, and this dependency will be remove ASAP
Added Paths:
-----------
branches/gridsim4.0-branch2/source/gridsim/net/flow/FlowRouter.java
Added: branches/gridsim4.0-branch2/source/gridsim/net/flow/FlowRouter.java
===================================================================
--- branches/gridsim4.0-branch2/source/gridsim/net/flow/FlowRouter.java (rev 0)
+++ branches/gridsim4.0-branch2/source/gridsim/net/flow/FlowRouter.java 2008-02-19 02:42:56 UTC (rev 113)
@@ -0,0 +1,735 @@
+/*
+ * ** Network and Service Differentiation Extensions to GridSim 3.0 **
+ *
+ * Author: James Broberg
+ *
+ * Author: Gokul Poduval & Chen-Khong Tham
+ * Computer Communication Networks (CCN) Lab
+ * Dept of Electrical & Computer Engineering
+ * National University of Singapore
+ * August 2004
+ *
+ * Licence: GPL - http://www.gnu.org/copyleft/gpl.html
+ *
+ * FlowRouter.java - Simulates a flow network router with RIP as the advertising
+ * protocol (adapted from RIPRouter.java)
+ *
+ */
+package gridsim.net.flow;
+
+import eduni.simjava.*;
+import gridsim.*;
+import gridsim.net.*;
+import gridsim.util.*;
+import java.util.*;
+
+
+/**
+ * This class implements a Router using a form of RIP for routing. The routing
+ * protocol used here is similar to <a
+ * href="http://www.ietf.org/rfc/rfc1058.txt">Routing Information Protocol
+ * (RIP) </a>. The routing protocol is run before Gridlets etc. can be
+ * submitted.
+ * <p>
+ * In case there are more than two routes to a destination, the
+ * route with the lower hopcount is used. Since in this simulation routers
+ * relay perfect information and links do not break down, RIP should be a
+ * reliable protocol to use.
+ *
+ * @invariant $none
+ * @since GridSim Toolkit 3.1
+ * @author Gokul Poduval & Chen-Khong Tham, National University of Singapore
+ */
+public class FlowRouter extends Router
+{
+ private Hashtable linkTable;
+ private Hashtable schedTable; // table of schedulers
+ private Hashtable hostTable;
+ private Hashtable routerTable;
+ private Hashtable forwardTable;
+ private int id;
+ private static final int BITS = 8; // 1 byte in bits
+
+
+ /**
+ * Creates a new RIPRouter object.
+ * By default, <b>no recording or logging</b>
+ * is done for packets' activities. If you want to log operations of this
+ * entity, please use {@link #RIPRouter(String, boolean)}.
+ *
+ * @param name Name of this router
+ * @throws NullPointerException This happens when name is empty or null
+ * @see #RIPRouter(String, boolean)
+ * @pre name != null
+ * @post $none
+ */
+ public FlowRouter(String name) throws NullPointerException {
+ this(name, false);
+ }
+
+ /**
+ * Creates a new RIPRouter object with logging facility if it is turned on.
+ * <br>
+ * NOTE: If logging facility is turned on, there are some overheads
+ * in terms of performance and memory consumption.
+ *
+ * @param name Name of this router
+ * @param trace <tt>true</tt> if you want to record this router's
+ * activity, <tt>false</tt> otherwise
+ * @throws NullPointerException This happens when name is empty or null
+ * @pre name != null
+ * @post $none
+ */
+ public FlowRouter(String name, boolean trace) throws NullPointerException
+ {
+ super(name, trace);
+ init();
+ }
+
+ /**
+ * Initialises all variables
+ * @pre $none
+ * @post $none
+ */
+ private void init()
+ {
+ this.id = super.get_id();
+ linkTable = new Hashtable();
+ hostTable = new Hashtable();
+ routerTable = new Hashtable();
+ forwardTable = new Hashtable();
+ schedTable = new Hashtable();
+ }
+
+ /**
+ * Informs the registered entities regarding to the end of a simulation.
+ * @pre $none
+ * @post $none
+ */
+ protected void processEndSimulation() {
+ // ... empty - maybe need to clean up all the hashtables
+ }
+
+ /**
+ * Joins two routers with a Link.
+ * @param router The router on the other side to which this one will
+ * be attached.
+ * @param link This is the link that will be used to connect the two
+ * routers.
+ * @param thisSched The scheduling policy used on this routers egress port
+ * when sending data through it.
+ * @param otherSched The scheduling policy that will be used on the
+ * egress port of the router being connected to when
+ * sending data to this router.
+ * @pre router != null
+ * @pre link != null
+ * @pre thisSched != null
+ * @pre otherSched != null
+ * @post $none
+ */
+ public void attachRouter(Router router, Link link,
+ PacketScheduler thisSched, PacketScheduler otherSched)
+ {
+ String msg = super.get_name() + ".attachRouter(): Error - ";
+ if (router == null)
+ {
+ System.out.println(msg + "the router is null.");
+ return;
+ }
+
+ if (link == null)
+ {
+ System.out.println(msg + "the link is null.");
+ return;
+ }
+
+ if (thisSched == null || otherSched == null)
+ {
+ System.out.println(msg +
+ "the one or more packet schedulers are null.");
+ return;
+ }
+
+ thisSched.setBaudRate( link.getBaudRate() );
+ otherSched.setBaudRate( link.getBaudRate() );
+
+ link.attach(this, router);
+ this.attachRouter(router, link, thisSched);
+ router.attachRouter(this, link, otherSched);
+ }
+
+ /**
+ * Joins two routers together. This is called by the routers themselves
+ * and should not be called by other entities.
+ *
+ * @param router The Router to which this router will be connected.
+ * @param link The Link that will be used to join these routers.
+ * @param sched The scheduling policy used on the egress port of the
+ * router when sending data through this route.
+ * @pre router != null
+ * @pre link != null
+ * @pre sched != null
+ * @post $none
+ */
+ public void attachRouter(Router router, Link link, PacketScheduler sched)
+ {
+ String msg = super.get_name() + ".attachRouter(): Error - ";
+ if (router == null)
+ {
+ System.out.println(msg + "the router is null.");
+ return;
+ }
+
+ if (link == null)
+ {
+ System.out.println(msg + "the link is null.");
+ return;
+ }
+
+ if (sched == null)
+ {
+ System.out.println(msg + "the packet scheduler is null.");
+ return;
+ }
+
+ linkTable.put(router.get_name(), link.get_name());
+
+ if (!schedTable.containsKey( link.get_name()) ) {
+ schedTable.put(link.get_name(), sched);
+ }
+
+ routerTable.put( link.get_name(), router.get_name() );
+ hostTable.put( link.get_name(), router.get_name() );
+
+ // logging or recording ...
+ if (reportWriter_ != null)
+ {
+ StringBuffer sb = null;
+ sb = new StringBuffer("attach this ROUTER, with router, ");
+ sb.append( router.get_name() );
+ sb.append(", with link, ");
+ sb.append( link.get_name() );
+ sb.append(", with packet scheduler, ");
+ sb.append( sched.getSchedName() );
+
+ super.write( sb.toString() );
+ }
+ }
+
+ /**
+ * Attaches an entity to this router. The link between the router and the
+ * entity being attached is taken from
+ * {@link gridsim.GridSimCore#getLink()}.
+ *
+ * @param entity The entity to be attached.
+ * @param sched The scheduling policy that will be used on the egress
+ * port when the router sends data to the entity being
+ * joined.
+ * @see gridsim.GridSimCore#getLink()
+ * @pre entity != null
+ * @pre sched != null
+ * @post $none
+ */
+ public void attachHost(GridSimCore entity, PacketScheduler sched)
+ {
+ String msg = super.get_name() + ".attachHost(): Error - ";
+ if (entity == null)
+ {
+ System.out.println(msg + "the entity is null.");
+ return;
+ }
+
+ if (sched == null)
+ {
+ System.out.println(msg + "the packet scheduler is null.");
+ return;
+ }
+
+ Link link = entity.getLink();
+ sched.setBaudRate( link.getBaudRate() );
+ link.attach(this, entity);
+ linkTable.put( entity.get_name(), link.get_name() );
+
+ if (!schedTable.containsKey( link.get_name() )) {
+ schedTable.put(link.get_name(), sched);
+ }
+
+ hostTable.put( link.get_name(), entity.get_name() );
+
+ // recording ...
+ if (reportWriter_ != null)
+ {
+ StringBuffer sb = null;
+ sb = new StringBuffer("attach this ROUTER, to entity, ");
+ sb.append( entity.get_name() );
+ sb.append(", with packet scheduler, ");
+ sb.append( sched.getSchedName() );
+
+ super.write( sb.toString() );
+ }
+ }
+
+ /**
+ * Processes incoming events
+ * @param ev a Sim_event object
+ * @pre ev != null
+ * @post $none
+ */
+ protected synchronized void processEvent(Sim_event ev)
+ {
+
+ System.out.println("Event was scheduled for " + ev.event_time());
+
+ switch ( ev.get_tag() )
+ {
+
+ case GridSimTags.PKT_FORWARD:
+ case GridSimTags.JUNK_PKT:
+ System.out.println(super.get_name() + ".processEvent(): processNetPacket() + at time = " + GridSim.clock());
+ processNetPacket(ev, ev.get_tag());
+ break;
+
+ //case GridSimTags.FLOW_FORWARD:
+ // processFlowPacket(ev, ev.get_tag());
+ // break;
+
+ case GridSimTags.ROUTER_AD:
+ receiveAd(ev);
+ break;
+
+ case GridSimTags.INSIGNIFICANT:
+ System.out.println(super.get_name() + ".processEvent(): processInternalEvent() + at time = " + GridSim.clock());
+ processInternalEvent(ev);
+ break;
+
+ default:
+ System.out.println(super.get_name() + ".body(): Unable to " +
+ "handle request from GridSimTags " +
+ "with constant number " + ev.get_tag() );
+ break;
+ }
+ }
+
+ /**
+ * Processes incoming network packets, one at a time.
+ * The incoming packet will be split up into smaller pieces if
+ * the packet size > MTU of the other end.
+ *
+ * @param ev a Sim_event object
+ * @pre ev != null
+ * @post $none
+ */
+ private synchronized void processNetPacket(Sim_event ev, int tag)
+ {
+ //double nextTime = 0;
+ Packet pkt = (Packet) ev.get_data();
+ PacketScheduler sched = getScheduler(pkt);
+ System.out.println("Packet id is " + pkt.getID());
+
+ // if a packet scheduler is not found, then try reschedule this packet
+ // in the future
+ if (sched == null)
+ {
+ System.out.println(super.get_name() + ".processNetPacket(): " +
+ "Warning - can't find a packet scheduler for " + pkt);
+ System.out.println("-> Will reschedule it again in the future.");
+
+ super.sim_schedule(super.get_id(), Router.DELAY, tag, pkt);
+ return;
+ }
+
+ // process ping() request
+ if (pkt instanceof InfoPacket)
+ {
+ ((InfoPacket) pkt).addHop(id);
+ ((InfoPacket) pkt).addEntryTime( GridSim.clock() );
+ ((InfoPacket) pkt).addBaudRate(sched.getBaudRate());
+ }
+
+ if (pkt instanceof FlowPacket && pkt.getTag() == GridSimTags.FLOW_SUBMIT ) {
+ ((FlowPacket)pkt).addBaudRate( ((Link)Sim_system.get_entity(getLinkName(pkt.getDestID()))).getBaudRate() );
+ ((FlowPacket)pkt).addLatency( ((Link)Sim_system.get_entity(getLinkName(pkt.getDestID()))).getDelay() );
+
+ }
+
+ // check downlink MTU, and split accordingly
+ //String linkName = getLinkName( pkt.getDestID() );
+ //Link downLink = (Link) Sim_system.get_entity(linkName);
+ //int MTU = downLink.getMTU();
+ //int numPackets = (int) Math.ceil(pkt.getSize() / (MTU * 1.0));
+
+ System.out.println(super.get_name() + ".processNetPacket() check sched Time now " + GridSim.clock());
+ // if no packets at the moment
+ if (sched.size() == 0)
+ {
+ System.out.println(super.get_name() + ".processNetPacket() #packets " +
+ " size " + pkt.getSize()*BITS + " baud sched " + sched.getBaudRate() +
+ " largest double " + Double.MAX_VALUE);
+
+ //if (numPackets == 1) {
+ // nextTime = (pkt.getSize() * BITS) / sched.getBaudRate();
+ //}
+ //else {
+ // nextTime = (MTU * BITS * 1.0) / sched.getBaudRate();
+ //}
+ System.out.println(super.get_name() + ".processNetPacket() set internal event to " +
+ "fire");
+ // Fire internal event without delay (delay is incurred entirely at source
+ // of Flow
+ sendInternalEvent(GridSimTags.SCHEDULE_NOW, sched);
+ }
+ System.out.println(super.get_name() + ".processNetPacket() done sched Time now " +
+ GridSim.clock());
+
+ // log / record ....
+ if (super.reportWriter_ != null)
+ {
+ super.write("");
+ super.write("receive incoming, " + pkt + ", delay, " + 0.0);
+ //super.write("break this packet into, " + numPackets);
+ }
+
+ // break a large packet into smaller ones that fit into MTU
+ // by making null or empty packets except for the last one
+ /*for (int i = 0; i < numPackets - 1; i++)
+ {
+ NetPacket np = new NetPacket(null, pkt.getID(), MTU, tag,
+ pkt.getSrcID(), pkt.getDestID(),
+ pkt.getNetServiceType(),i+1,numPackets);
+
+ np.setLast(id);
+ super.write("enqueing, " + np);
+ sched.enque(np); // put the packet into the scheduler
+ }*/
+
+ // put the actual packet into the last one and resize it accordingly
+ pkt.setLast(id);
+ pkt.setSize(pkt.getSize());
+ super.write("enqueing, " + pkt);
+ sched.enque(pkt); // put the packet into the scheduler
+ }
+
+
+ /**
+ * Gets the link's name for a given id
+ * @param destID a destination id
+ * @return the link's man
+ * @pre destID > 0
+ * @post $none
+ */
+ private synchronized String getLinkName(int destID)
+ {
+ String destName = GridSim.getEntityName(destID);
+ String linkName = null;
+
+ //directly connected
+ if (hostTable.containsValue(destName)) {
+ linkName = (String)linkTable.get(destName);
+ }
+ else
+ {
+ // need to forward to another router
+ Object[] data = (Object[]) forwardTable.get(destName);
+ String router = (String) data[0];
+ linkName = (String) linkTable.get(router);
+ }
+
+ return linkName;
+ }
+
+ /**
+ * Returns the Scheduler associated with a packet.
+ *
+ * @param np NetPacket for which the associated scheduler is to be returned
+ * @return the packet's scheduler or <tt>null</tt> if the packet is empty
+ * @pre np != null
+ * @post $none
+ */
+ public PacketScheduler getScheduler(Packet np)
+ {
+ if (np == null) {
+ return null;
+ }
+
+ String destName = GridSim.getEntityName( np.getDestID() );
+ return getScheduler(destName);
+ }
+
+ /**
+ * Returns the Scheduler that the router would use to reach a particular
+ * destination. This can be used to set weigths, priorities etc. as the
+ * case may be on the Scheduler
+ *
+ * @param dest id of the destination for which the Scheduler is required.
+ * @return the destination's packet scheduler
+ * @pre dest > 0
+ * @post $none
+ */
+ public PacketScheduler getScheduler(int dest)
+ {
+ if (dest < 0) {
+ return null;
+ }
+
+ String destName = GridSim.getEntityName(dest);
+ return getScheduler(destName);
+ }
+
+ /**
+ * Returns the Scheduler that the router would use to reach a particular
+ * destination. This can be used to set weigths, priorities etc. as the
+ * case may be on the Scheduler
+ *
+ * @param dest Name of the destination for which the Scheduler is required.
+ * @return destination's packet scheduler or <tt>null</tt> if destination
+ * name is invalid.
+ * @pre dest != null
+ * @post $none
+ */
+ public PacketScheduler getScheduler(String dest)
+ {
+ if (dest == null || dest.length() == 0) {
+ return null;
+ }
+
+ PacketScheduler sched = null;
+ try
+ {
+ if ( hostTable.containsValue(dest) )
+ {
+ String linkName = (String) linkTable.get(dest);
+ sched = (PacketScheduler) schedTable.get(linkName);
+ }
+ else
+ {
+ // need to forward to another router
+ Object[] data = (Object[]) forwardTable.get(dest);
+
+ // in case the forwarding table is incomplete
+ if (data == null) {
+ return null;
+ }
+
+ String router = (String) data[0];
+ String linkName = (String) linkTable.get(router);
+ sched = (PacketScheduler) schedTable.get(linkName);
+ }
+ }
+ catch (Exception e) {
+ sched = null;
+ }
+
+ return sched;
+ }
+
+ /**
+ * Processes internal event
+ * @param ev a Sim_event object
+ * @pre ev != null
+ * @post $none
+ */
+ private synchronized void processInternalEvent(Sim_event ev)
+ {
+ PacketScheduler sched = (PacketScheduler) ev.get_data();
+ dequeue(sched);
+ }
+
+ /**
+ * Dequeue a packet from the scheduler and sends it to the next
+ * destination via a link.
+ * @param sched the packet scheduler
+ * @pre sched != null
+ * @post $none
+ */
+ private synchronized void dequeue(PacketScheduler sched)
+ {
+ Packet np = sched.deque();
+
+ // process ping() packet
+ if (np instanceof InfoPacket) {
+ ((InfoPacket) np).addExitTime( GridSim.clock() );
+ }
+
+ super.write("dequeuing, " + np);
+
+ // must distinguish between normal and junk packet
+ int tag = GridSimTags.PKT_FORWARD;
+ if (np.getTag() == GridSimTags.JUNK_PKT) {
+ tag = GridSimTags.JUNK_PKT;
+ }
+
+ // sends the packet via the link
+ String linkName = getLinkName( np.getDestID() );
+ super.sim_schedule(GridSim.getEntityId(linkName),
+ GridSimTags.SCHEDULE_NOW, tag, np);
+
+ System.out.println(super.get_name() + ".deque() time now " + GridSim.clock());
+
+ // process the next packet in the scheduler
+ if ( !sched.isEmpty() )
+ {
+ double nextTime = (np.getSize() * BITS) / sched.getBaudRate();
+ sendInternalEvent(nextTime, sched);
+ }
+ }
+
+ /**-
+ * Sends an internal event to itself
+ * @param time the delay time period
+ * @param data the data to be sent
+ * @return <tt>true</tt> if it is successful, <tt>false</tt> otherwise
+ * @pre time >= 0
+ * @post $none
+ */
+ private synchronized boolean sendInternalEvent(double time, Object data)
+ {
+ if (time < 0.0) {
+ return false;
+ }
+
+ super.sim_schedule(id, time, GridSimTags.INSIGNIFICANT, data);
+ return true;
+ }
+
+ /**
+ * Prints this router's routing table in a nice-formatted layout
+ * @pre $none
+ * @post $none
+ */
+ public synchronized void printRoutingTable()
+ {
+ synchronized (System.out)
+ {
+ System.out.println();
+ System.out.println("--- Routing Table for " +
+ super.get_name() + " ---");
+
+ for (Enumeration e = hostTable.keys(); e.hasMoreElements(); )
+ {
+ String link = (String) e.nextElement();
+ System.out.println(hostTable.get(link) + "\t\t" + link);
+ }
+
+ for (Enumeration e = forwardTable.keys(); e.hasMoreElements(); )
+ {
+ String host = (String)e.nextElement();
+ Object[] data = (Object[])forwardTable.get(host);
+ String nextHop = (String)data[0];
+ System.out.println(host + "\t\t" + nextHop);
+ }
+
+ System.out.println("-------------------------------------");
+ System.out.println();
+ }
+ }
+
+
+ //----------- ADVERTISING FUNCTIONS --------------//
+
+ /**
+ * All hosts connected to this router are advertised to adjacent routers
+ * @pre $none
+ * @post $none
+ */
+ protected synchronized void advertiseHosts()
+ {
+ Collection hosts = hostTable.values(); // who to advertise
+ Enumeration routers = routerTable.elements();
+
+ while ( routers.hasMoreElements() )
+ {
+ RIPAdPack ad = new RIPAdPack(super.get_name(), hosts);
+ String router = (String) routers.nextElement();
+ super.write("advertise to router, " + router);
+ sim_schedule(Sim_system.get_entity_id(router),
+ GridSimTags.SCHEDULE_NOW, GridSimTags.ROUTER_AD, ad);
+ }
+
+ //super.sim_pause(1); // wait for 5 secs to gather the results
+ }
+
+ /**
+ * When an ad is recieved, the forwarding table is updated. After that we
+ * need to propogate this ad along all links except the incoming one.
+ * {@link #forwardAd(RIPAdPack)} is used for that
+ * @param ev a Sim_event object
+ * @pre ev != null
+ * @post $none
+ */
+ private synchronized void receiveAd(Sim_event ev)
+ {
+ super.write("receive router ad from, "+GridSim.getEntityName(ev.get_src()));
+
+ // what to do when an ad is received
+ RIPAdPack ad = (RIPAdPack)ev.get_data();
+
+ // prevent count-to-infinity
+ if (ad.getHopCount() > 15) {
+ return;
+ }
+
+ String sender = ad.getSender();
+ Iterator it = ad.getHosts().iterator();
+
+ while ( it.hasNext() )
+ {
+ String host = (String) it.next();
+
+ if ( host.equals(super.get_name()) ) {
+ continue;
+ }
+
+ if (hostTable.containsValue(host)) { // direct connection
+ continue;
+ }
+
+ if (forwardTable.containsKey(host))
+ {
+ Object[] data = (Object[])forwardTable.get(host);
+ int hop = ((Integer)data[1]).intValue();
+
+ if ((hop) > ad.getHopCount())
+ {
+ Object[] toPut = { sender, new Integer(ad.getHopCount()) };
+ forwardTable.put(host, toPut);
+ }
+ }
+ else
+ {
+ Object[] toPut = { sender, new Integer(ad.getHopCount()) };
+ forwardTable.put(host, toPut);
+ }
+ }
+
+ forwardAd(ad);
+ }
+
+ /**
+ * Received ads should be forwarded along all links except the incoming
+ * one. Also need to change id to onself
+ *
+ * @param ad a RIPAdPack object
+ * @pre ad != null
+ * @post $none
+ */
+ private synchronized void forwardAd(RIPAdPack ad)
+ {
+ String sender = ad.getSender();
+ ad.incrementHopCount();
+ RIPAdPack newad = new RIPAdPack(super.get_name(),ad.getHosts());
+ newad.setHopCount(ad.getHopCount());
+
+ Enumeration routers = routerTable.elements();
+ while ( routers.hasMoreElements() )
+ {
+ String router = (String)routers.nextElement();
+ if (!router.equals(sender))
+ {
+ sim_schedule(Sim_system.get_entity_id(router),
+ GridSimTags.SCHEDULE_NOW, GridSimTags.ROUTER_AD, newad);
+ }
+ }
+ }
+
+} // end class
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|