/* IP.java */ package SSF.OS; import java.util.*; import com.renesys.raceway.DML.*; import SSF.Net.*; import SSF.Net.Util.*; import com.renesys.raceway.SSF.*; /** * This class implements a subset of the IP protocol. The primary job * of IP is to find a route for each datagram and send it on its way. * In order to allow gateways or other intermediate systems to forward the * datagram, it adds its own header (IpHeader.java). This version * of IP uses a 'next hop' IP address as a surrogate hardware address; * future alternatives with more elaborate link layer models will fix this. * @see SSF.OS.IpHeader */ public class IP extends ProtocolSession implements Configurable { public int udpdrops=0; public double udpdelay=0.0; /** A reference to the top-level Net. */ public static Net topnet; public int udpsent=0; //number of udp packets sent public int udprcvd =0; //number of udp packets rcvd public int udprcvdTR =0;//transit public int tcprcvdTR =0; //public double udpdelay=0.0; /** An array of NIC(s) controlled by this IP. */ public Vector INTERFACES; /** The IP routing table. */ protected RoutingTable ROUTING_TABLE; /** Return the IP routing table. */ public RoutingTable getRoutingTable() { return ROUTING_TABLE; }; protected demux_cache session_cache; public final int INTERFACE_SET_STARTING_SIZE = 2; public NIC[] INTERFACE_SET; public int INTERFACE_COUNT; private boolean DEBUG = false; protected String tieBreakerClass = null; // Class implementing IpMonitor used to monitor and/or mark IP packets private ProtocolMonitor monitor = null; // The ProtocolMonitor on/off switch */ private boolean monitorON = false; //------------------------------------------------------ CONSTRUCTOR public IP() { super(); INTERFACES = new Vector(); session_cache = new demux_cache(); INTERFACE_SET = new NIC[INTERFACE_SET_STARTING_SIZE]; INTERFACE_COUNT = 0; } public void setGraph(ProtocolGraph G) throws ProtocolException { RouteTieBreaker T = null; try { T = (tieBreakerClass==null?null:(RouteTieBreaker) (Class.forName(tieBreakerClass).newInstance())); } catch (Exception any) { // System.out.println(debugIdentifier() + any); } ROUTING_TABLE = new RadixTreeRoutingTable(G,T); // System.out.println(debugIdentifier() +" routing table is.."); ROUTING_TABLE.print(); super.setGraph(G); } //------------------------------------------------------ CONFIGURATION /** Configure this IP session. Example of the supported DML attributes: *
   *   ProtocolSession [for ip use SSF.OS.IP
   *     debug   %S    # print verbose diagnostics, true/false
   *
   *     tiebreaker [
   *       use   %S    # class name to use to choose routes of equal cost
   *     ]
   *
   *     monitor [
   *       use   %S    # class name to use for IP Monitoring
   *     ]
   *   ]
   * 
* If tiebreaker is omitted, the default is a simple hash on src and * dest address provided in an anonymous inner class in SSF.Net.RadixTreeRoutingTable. * */ public void config(Configuration cfg) throws configException { super.config(cfg); String str; //selma Host myhost = (Host)inGraph(); // the local router topnet = myhost.net; // set a reference to the top-level Net // str = (String)cfg.findSingle("debug"); if (str != null) DEBUG = Boolean.valueOf(str).booleanValue(); Configuration mConfig = (Configuration)cfg.findSingle("monitor"); if (mConfig != null) createMonitor(mConfig); str = (String)cfg.findSingle("tiebreaker.use"); if (str != null) tieBreakerClass = str; } /** Instantiate and configure an IP packet monitor implementing * the interface SSF.OS.ProtocolMonitor, if specified * locally in this host's IP configuration. */ private void createMonitor(Configuration config) throws configException { String monitor_type = (String)config.findSingle("use"); if (monitor_type == null) throw new configException("\n"+debugIdentifier()+" DML monitor.use is not specified"); try { Class mClass = Class.forName(monitor_type); Object mobj = mClass.newInstance(); monitor = (ProtocolMonitor)mobj; } catch (Exception any) { System.err.println(debugIdentifier()+" Can't create an instance of "+monitor_type); any.printStackTrace(); throw new configException("Can't create monitor "+monitor_type); } //let the monitor do its own config, and let it know the owner IP session monitor.config(this, config); //turn on the monitor setMonitorEnable(true); } //selma private class WrapupThread implements Runnable { public void run() { System.out.println(debugIdentifier()+" udpdelay is="+udpdelay+" udpdrops are="+udpdrops + " udpsent="+ udpsent+" udprcvd="+ udprcvd ); System.out.println(debugIdentifier()+" udprcvdTR="+ udprcvdTR+" tcprcvdTR="+ tcprcvdTR); } } /** Monitor may need to initialize after the config() phase. */ public void init() throws ProtocolException { if (monitor != null) monitor.init(); //selma //if (mon.wrapup) { topnet.wrapup(new WrapupThread()); //} } /** An ProtocolMonitor may turn on and off calls to its receive() * method. NOTE: the ProtocolMonitor MUST explicitely set * enableMonitor(true) in its init() method to begin * receiving IP packets. */ public void setMonitorEnable(boolean en) { if(monitor != null) monitorON = en; } /** An ProtocolMonitor may inquire if IP calls to its receive() are enabled */ public boolean getMonitorEnable() { return monitorON; } //------------------------------------------------------- OPENED NIC public void opened(ProtocolSession nic) throws ProtocolException { INTERFACES.addElement(nic); // DEPRECATED if (INTERFACE_COUNT == INTERFACE_SET.length) { // must expand NIC[] larger = new NIC[INTERFACE_SET.length*2]; System.arraycopy(INTERFACE_SET,0,larger,0,INTERFACE_SET.length); // :DELETE: INTERFACE_SET INTERFACE_SET = larger; } INTERFACE_SET[INTERFACE_COUNT++] = (NIC)nic; } //------------------------------------------------------- PACKET HANDLING /** demux_cache: class internal to IP, used for rapid demultiplexing * of protocol numbers to protocol session instances. Two dynamic * arrays are maintained: a list of protocol numbers and a list of * protocol sessions. These lists are unordered, but the most recently * requested protocol number may always be found in slot 0. */ protected final class demux_cache { int curr, max; int[] numbers; ProtocolSession[] sessions; final int INITIAL_CACHE_SIZE = 4; public demux_cache() { curr = 0; // will initialize on first use } public final ProtocolSession demux(int pnum) throws ProtocolException { if (curr == 0) { max = INITIAL_CACHE_SIZE; sessions = new ProtocolSession[max]; numbers = new int[max]; numbers[0] = pnum; try { sessions[0] = IP.this.inGraph.SessionForName(Protocols.getProtocolByNumber(pnum)); } catch (ProtocolException pex) { //System.err.println(debugIdentifier() + pex); sessions[0] = null; } curr = 1; } if (numbers[0] == pnum) // Common case: most recently requested. return sessions[0]; else for (int n=1; n=150.0 ) sn=(int)(Integer.parseInt(pktpayload.substring( pktpayload.indexOf("seqno=")+6, pktpayload.indexOf("sendtime")-1))); if (udp && (this.inGraph().now()/(double)SSF.Net.Net.seconds(1.0) )>=150.0){ if (sn!=0) { double sndtime=(double)(Double.parseDouble(pktpayload.substring( pktpayload.indexOf("sendtime=")+9, pktpayload.indexOf("]")))); if (sndtime==rtime) { udpsent++; } } } // 1. If the local host is the destination indicated by the ipHeader,push the payload up to the correct protocol. boolean isLocal = // loopback address 127.0.0.1 with netmask 255.0.0.0 (0x7F000000 == (0xFF000000 & ipHeader.DEST_IP)); for (int n=0; !isLocal && n=150.0 ) { //parse sendtime=..] int seqno=(int)(Integer.parseInt(pktpayload.substring( pktpayload.indexOf("seqno=")+6, pktpayload.indexOf("sendtime")-1))); if (seqno!=0) { double sendtime=(double)(Double.parseDouble(pktpayload.substring( pktpayload.indexOf("sendtime=")+9, pktpayload.indexOf("]")))); udpdelay+=rtime-sendtime; udprcvd++; } } return (handler.push(ipHeader.payload(), this)); } //return (handler.push(ipHeader.payload(), this)); } else { if (!ICMP.suppressReporting(ipHeader)) push(ICMPHeader.makeProtocolUnreachableMessage(ipHeader). ipHeader(),this); drop(ipHeader); return false; } } else {//not local if (tcp) tcprcvdTR++; if (udp) udprcvdTR++; } //if (0 >= --ipHeader.TIME_TO_LIVE) { bugfix 12-13-01 if (0 >= ipHeader.TIME_TO_LIVE--) { if (!ICMP.suppressReporting(ipHeader)) push(ICMPHeader.makeTimeExceededMessage(ipHeader).ipHeader(),this); drop(ipHeader); return false; } RoutingInfo rtgInfo = ROUTING_TABLE.findBest(ipHeader.SOURCE_IP,ipHeader.DEST_IP); int recurse = 0; while (rtgInfo != null && rtgInfo.next_hop_interface() == null) { recurse++; if (recurse > 10) { // recursive lookup limit throw new Error("IP: recursive lookup limit exceeded"); } rtgInfo=ROUTING_TABLE.findBest(ipHeader.SOURCE_IP,rtgInfo.next_hop_ip()); } if (rtgInfo != null) { NIC use_iface = rtgInfo.next_hop_interface(); // if no source is specified in the header, then set it to the // interface which it is about to be sent out on if (ipHeader.SOURCE_IP < 0) { // if (DEBUG) { // System.err.println(debugIdentifier() + "invalid IP source address: " // + ipHeader.SOURCE_IP); // } //System.out.println("does it come to here?"); ipHeader.SOURCE_IP = use_iface.ipAddr; } ipHeader.NEXT_HOP_IP = rtgInfo.next_hop_ip(); if (monitorON) monitor.receive(ipHeader, fromSession, use_iface); return (use_iface.push(ipHeader,this)); } else { /*if (DEBUG) { System.out.println(debugIdentifier() + "no route for " + IP_s.IPtoString(ipHeader.DEST_IP) + " in:"); ((RadixTreeRoutingTable)ROUTING_TABLE).print(" "); }*/ // shouldn't drop() be called here? -bjp 2000.06.29 if (!ICMP.suppressReporting(ipHeader)) push(ICMPHeader.makeHostUnreachableMessage(ipHeader). ipHeader(),this); drop(ipHeader); return false; } } // end of push() /** Method called when IP drops a packet that has reached the end of its * lifetime, or has no route to its destination. */ public void drop(IpHeader pkt) { // if (DEBUG) { String pktpayload=pkt.payload().toString(); if (pktpayload.indexOf("UDP")!=-1 && (this.inGraph().now()/(double)SSF.Net.Net.seconds(1.0))>=150.0 ) { //change time=150.0 depending on simulation udpdrops++; // System.out.println("udpdrops="+udpdrops); } // // } } } /*= =*/ /*= 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 =*/ /*= =*/