/* 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