/** * @copyright 2013 Computer Science Department, Recursive InterNetworking Architecture (RINA) laboratory, Boston University. * All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation * for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all * copies and that both the copyright notice and this permission notice appear in supporting documentation. * The RINA laboratory of the Computer Science Department at Boston University makes no * representations about the suitability of this software for any purpose. */ package rina.routing; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Timer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import rina.config.RINAConfig; import rina.irm.impl.IRMImpl; import rina.object.internal.ForwardingTable; import rina.object.internal.Neighbor; import rina.object.internal.Neighbors; import rina.object.internal.SubscriptionEvent; import rina.object.internal.SubscriptionEvent.EventType; import rina.rib.impl.RIBImpl; import rina.ribDaemon.impl.RIBDaemonImpl; import rina.routing.util.CheckNeighborTimerTask; import rina.routing.util.LinkStateRoutingInfo; /** * Routing Daemon is responsible for the routing in the DIF. * Current we support link state protocol, but programmer can add new policies. * @author Yuefeng Wang. Computer Science Department, Boston University * */ public class RoutingDaemon { private Log log = LogFactory.getLog(this.getClass()); private RINAConfig config = null; private String routingProtocol = null; private RIBImpl rib = null; private IRMImpl irm = null; private RIBDaemonImpl ribDaemon = null; private Neighbors neighbors = null; private int rinaAddr = -1; //Link State Routing //Later will support other routing, such as distance vector private LinkStateRoutingInfo linkStateRoutingInfo = null; private ForwardingTable forwardingTable = null; private double routingEntrySubUpdatePeriod = -1; private String linkCostPolicy = null; public static double inf = 99999999; public static double checkNeighborPeriod = -1; // The following is to check if the neighbor is alive private Timer timer = null; private LinkedHashMap<Integer, CheckNeighborTimerTask> allCheckNeighborTimerTask = null; public RoutingDaemon(RIBImpl rib, IRMImpl irm) { this.rib = rib; this.irm = irm; this.config = (RINAConfig)this.rib.getAttribute("config"); this.routingEntrySubUpdatePeriod = this.config.getRoutingEntrySubUpdatePeriod(); this.rib.addAttribute("routingEntrySubUpdatePeriod", this.routingEntrySubUpdatePeriod); this.checkNeighborPeriod = this.config.getCheckNeighborPeriod(); this.rib.addAttribute("checkNeighborPeriod", this.checkNeighborPeriod); this.linkCostPolicy = this.config.getLinkCostPolity(); this.rib.addAttribute("linkCostPolicy", this.linkCostPolicy); this.rinaAddr = (Integer)this.rib.getAttribute("rinaAddr"); this.forwardingTable = (ForwardingTable )this.rib.getAttribute("forwardingTable"); this.routingProtocol = (String) this.rib.getAttribute("routingProtocol"); //POLICY HOLDER if(this.routingProtocol.equals("linkState")) { this.linkStateRoutingInfo = new LinkStateRoutingInfo(this.rinaAddr, this.forwardingTable); this.rib.addAttribute("linkStateRoutingInfo", this.linkStateRoutingInfo); this.timer = new Timer(); this.allCheckNeighborTimerTask = new LinkedHashMap<Integer, CheckNeighborTimerTask>(); this.ribDaemon = (RIBDaemonImpl) this.rib.getAttribute("ribDaemon"); this.neighbors = (Neighbors) this.rib.getAttribute("neighbors"); this.initPub(); this.initSub(); }else if (this.routingProtocol.equals("myNewRoutingPolicy")) { //implement new routing policy here } this.log.info("Routing Daemon started, and routing protocol used is " + this.routingProtocol); } /** * Init sub events needed for Routing Daemon */ private void initSub() { LinkedList<Neighbor> neighborList = this.neighbors.getNeighborList(); //create sub event of routing entry for(int i = 0; i< neighborList.size(); i ++) { String publisher = Long.toString( neighborList.get(i).getAddr() ); this.addLinkStateRoutingEntrySubEvent(publisher); } } /** * Init sub events needed for Routing Daemon */ private void initPub() { //first it is a neighbor discover pub event, pub to its neighbor, to check if it is alive or not //this event should be more frequent than the routing sub events(event1 and event2), which will send update to neighbor alive based on the neighbor discover event SubscriptionEvent event = new SubscriptionEvent(EventType.PUB, this.checkNeighborPeriod, "checkNeighborAlive"); this.ribDaemon.createEvent(event); //two things are pubed here, one is its direct routing entries //but also the routing entries it received from its neighbors, basically flooding SubscriptionEvent event1 = new SubscriptionEvent(EventType.PUB, this.routingEntrySubUpdatePeriod, "linkStateRoutingEntry"); this.ribDaemon.createEvent(event1); SubscriptionEvent event2 = new SubscriptionEvent(EventType.PUB, this.routingEntrySubUpdatePeriod, "linkStateRoutingEntryNeighborsReceived"); this.ribDaemon.createEvent(event2); } public void addLinkStateRoutingEntrySubEvent(String publisher) { //Sleep 1 seconds on purpose. //This is extremely useful after a member joins a DIF, the DIF manager subscriber to its routing Entry // as it takes some time for the new member to start is routing daemon after the enrollment is done this.log.debug("add routing entry sub to publisher :" + publisher); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //first it is a neighbor discover sub event, sub to all it neighbor, to check if it is alive or not //this event should be more frequent than the routing sub events(event1 and event2), which will send update to neighbor alive based on the neighbor discover event SubscriptionEvent event = new SubscriptionEvent(EventType.SUB, this.checkNeighborPeriod, "checkNeighborAlive", publisher); int eventID = this.ribDaemon.createEvent(event); this.log.debug("sub (checkNeighborAlive) id to " + publisher + " is " + eventID); //two things are subed here, one is neigbor's direct routing entry, //but also the routing entries the neighbor received from their neighbors, basically flooding SubscriptionEvent event1 = new SubscriptionEvent(EventType.SUB, routingEntrySubUpdatePeriod, "linkStateRoutingEntry", publisher); int event1ID = this.ribDaemon.createEvent(event1); this.log.debug("sub (linkStateRoutingEntry) id to " + publisher + " is " + event1ID); SubscriptionEvent event2 = new SubscriptionEvent(EventType.SUB, routingEntrySubUpdatePeriod, "linkStateRoutingEntryNeighborsReceived", publisher); int event2ID = this.ribDaemon.createEvent(event2); this.log.debug("sub (linkStateRoutingEntryNeighborsReceived) id to " + publisher + " is " + event2ID); } public synchronized void addCheckNeighborTimerTask(int neighborAddr) { if(!this.allCheckNeighborTimerTask.containsKey(neighborAddr)) // no check timer task, create one { CheckNeighborTimerTask task = null; task = new CheckNeighborTimerTask(neighborAddr,this.neighbors,this.linkStateRoutingInfo,this.irm); this.allCheckNeighborTimerTask.put(neighborAddr, task); //here adding extra time is used to prevent sync of pub and check time double extraTime = 1; System.err.println(" RoutingDaemon.checkNeighborPeriod " + this.checkNeighborPeriod ); this.timer.schedule(task, (long)0, (long)( this.checkNeighborPeriod + extraTime)* 1000); }else { // this.log.debug(" CheckNeighborTimerTask exists already for " + neighborAddr); } } public synchronized void updateChckNeighborTimerTask(int neighborAddr) { if(this.allCheckNeighborTimerTask.containsKey(neighborAddr)) { this.allCheckNeighborTimerTask.get(neighborAddr).setAlive(true); } } }