001/*******************************************************************************
002 * Copyright (c) 2016 Pablo Pavon Mari�o.
003 * All rights reserved. This program and the accompanying materials
004 * are made available under the terms of the GNU Lesser Public License v2.1
005 * which accompanies this distribution, and is available at
006 * http://www.gnu.org/licenses/lgpl.html
007 ******************************************************************************/
008
009
010
011
012
013
014 
015
016
017
018
019package com.net2plan.examples.general.onlineSim;
020
021import java.util.List;
022import java.util.Map;
023
024import cern.colt.function.tdouble.DoubleDoubleFunction;
025import cern.colt.matrix.tdouble.DoubleMatrix1D;
026
027import com.net2plan.interfaces.networkDesign.Demand;
028import com.net2plan.interfaces.networkDesign.Link;
029import com.net2plan.interfaces.networkDesign.Net2PlanException;
030import com.net2plan.interfaces.networkDesign.NetPlan;
031import com.net2plan.interfaces.networkDesign.NetworkLayer;
032import com.net2plan.interfaces.simulation.IEventProcessor;
033import com.net2plan.interfaces.simulation.SimEvent;
034import com.net2plan.libraries.IPUtils;
035import com.net2plan.utils.Constants.RoutingType;
036import com.net2plan.utils.InputParameter;
037import com.net2plan.utils.Triple;
038
039/** 
040 * Implements the reactions of an IP network governed by the OSPF/ECMP forwarding policies, for given link weigths
041 * 
042 * This algorithm implements the reactions of an IP network governed by the OSPF/ECMP forwarding policies, for given link weigths, to the following events: 
043 * <ul>
044 * <li>SimEvent.DemandAdd: Adds a new IP traffic demand, and recomputes the routing (now including the new traffic).</li>
045 * <li>SimEvent.DemandRemove: Remvoes an IP traffic demand, and recomputes the routing.</li>
046 * <li>SimEvent.DemandModify: Modifies the offered traffic of a demand, and recomputes the routing.</li>
047 * <li>SimEvent.LinkAdd: Adds a new IP link to the network, recomputes the routing tables and the routing.</li>
048 * <li>SimEvent.LinkRemove: Removes an existing IP link in the network, recomputes the routing tables and the routing.</li>
049 * <li>SimEvent.LinkModify: Modifies the capacity of an IP link. The routing is not modified, since OSPF does not react to capacity changes.</li>
050 * <li>SimEvent.NodesAndLinksChangeFailureState: Fails/repairs the indicated nodes and/or IP links, and reacts to such failures as OSPF does: the failed links are removed from the routing tables, and the network routing recomputed.</li>
051 * </ul>
052 * 
053 * This module can be used in conjunction with the {@code Online_evGen_generalGenerator} generator for simulating IP/OSPF networks. 
054 * 
055 * See the technology conventions used in Net2Plan built-in algorithms and libraries to represent IP/OSPF networks. 
056 * @net2plan.keywords IP/OSPF, Network recovery: restoration
057 * @net2plan.inputParameters 
058 * @author Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza
059 */
060public class Online_evProc_ipOspf extends IEventProcessor
061{
062        private InputParameter ipLayerIndex = new InputParameter ("ipLayerIndex", (int) -1 , "Index of the layer containing IP network (-1 means default layer)");
063        private InputParameter ipMaximumE2ELatencyMs = new InputParameter ("ipMaximumE2ELatencyMs", (double) -1 , "Maximum end-to-end latency of the traffic of an IP demand to consider it as lost traffic (a non-positive value means no limit)");
064        private NetworkLayer ipLayer;
065        private double stat_trafficOffered , stat_trafficCarried , stat_trafficOversubscribed , stat_trafficOutOfLatencyLimit , stat_trafficOfDemandsTraversingOversubscribedLink;
066        private double stat_transitoryInitTime , stat_timeLastChangeInNetwork;
067        
068        @Override
069        public String getDescription()
070        {
071                return "Implements the reactions of an IP network governed by the OSPF/ECMP forwarding policies, for given link weigths";
072        }
073
074        @Override
075        public List<Triple<String, String, String>> getParameters()
076        {
077                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
078                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
079        }
080
081        @Override
082        public void initialize(NetPlan initialNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters)
083        {
084                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
085                InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
086
087                this.ipLayer = (ipLayerIndex.getInt() == -1)? initialNetPlan.getNetworkLayerDefault() : initialNetPlan.getNetworkLayer(ipLayerIndex.getInt ());
088                if (ipLayer == null) throw new Net2PlanException ("Unknown layer id");
089                
090                initialNetPlan.setRoutingType(RoutingType.HOP_BY_HOP_ROUTING , ipLayer);
091                DoubleMatrix1D linkIGPWeightSetting = IPUtils.getLinkWeightVector(initialNetPlan , ipLayer);
092                linkIGPWeightSetting.assign (initialNetPlan.getVectorLinkUpState(ipLayer) , new DoubleDoubleFunction () { public double apply (double x , double y) { return y == 1? x : Double.MAX_VALUE; }  } );
093                IPUtils.setECMPForwardingRulesFromLinkWeights(initialNetPlan , linkIGPWeightSetting , ipLayer);
094                
095                finishTransitory(0);
096                stat_timeLastChangeInNetwork = 0;
097        }
098
099        @Override
100        public void processEvent(NetPlan currentNetPlan, SimEvent event)
101        {
102                /* Update with the network stage since the last event until now */
103                final double timeSinceLastChange = event.getEventTime() - stat_timeLastChangeInNetwork;
104                stat_trafficOffered += timeSinceLastChange * currentNetPlan.getVectorDemandOfferedTraffic(this.ipLayer).zSum();
105                stat_trafficCarried += timeSinceLastChange * currentNetPlan.getVectorDemandCarriedTraffic(this.ipLayer).zSum();
106                stat_trafficOversubscribed += timeSinceLastChange * currentNetPlan.getVectorLinkOversubscribedTraffic(this.ipLayer).zSum();
107                stat_trafficOfDemandsTraversingOversubscribedLink += timeSinceLastChange * currentNetPlan.getVectorDemandOfferedTraffic(this.ipLayer).zDotProduct(currentNetPlan.getVectorDemandTraversesOversubscribedLink(this.ipLayer));
108                if (ipMaximumE2ELatencyMs.getDouble () > 0) for (Demand d : currentNetPlan.getDemands (ipLayer)) if (d.getWorseCasePropagationTimeInMs() > ipMaximumE2ELatencyMs.getDouble ()) stat_trafficOutOfLatencyLimit += timeSinceLastChange * d.getOfferedTraffic();
109                
110                stat_timeLastChangeInNetwork = event.getEventTime();
111
112                if (event.getEventObject () instanceof SimEvent.DemandAdd)
113                {
114                        SimEvent.DemandAdd ev = (SimEvent.DemandAdd) event.getEventObject ();
115                        Demand d = currentNetPlan.addDemand(ev.ingressNode, ev.egressNode, ev.offeredTraffic, null, ev.layer); 
116                        ev.demandAddedToFillByProcessor = d;
117                } else if (event.getEventObject () instanceof SimEvent.DemandRemove)
118                {
119                        SimEvent.DemandRemove ev = (SimEvent.DemandRemove) event.getEventObject ();
120                        ev.demand.remove (); 
121                } else if (event.getEventObject () instanceof SimEvent.DemandModify)
122                {
123                        SimEvent.DemandModify ev = (SimEvent.DemandModify) event.getEventObject ();
124                        Demand d = ev.demand; 
125//                      System.out.print ("IPOSPF DemandModify: demand " + d + ", " + (ev.modificationIsRelativeToCurrentOfferedTraffic? "RELATIVE" : "ABSOLUTE") + " , old demand offered: " + d.getOfferedTraffic() + " ");
126                        if (ev.modificationIsRelativeToCurrentOfferedTraffic) 
127                                d.setOfferedTraffic(d.getOfferedTraffic() + ev.offeredTraffic);
128                        else
129                                d.setOfferedTraffic(ev.offeredTraffic);
130                        System.out.println (" new demand offered: " + d.getOfferedTraffic());
131                } else if (event.getEventObject () instanceof SimEvent.LinkAdd)
132                {
133                        SimEvent.LinkAdd ev = (SimEvent.LinkAdd) event.getEventObject ();
134                        Link newLink = currentNetPlan.addLink (ev.originNode , ev.destinationNode, ev.capacity , ev.lengthInKm , ev.propagationSpeedInKmPerSecond , null , ev.layer);
135                        ev.linkAddedToFillByProcessor = newLink;
136                } else if (event.getEventObject () instanceof SimEvent.LinkRemove)
137                {
138                        SimEvent.LinkRemove ev = (SimEvent.LinkRemove) event.getEventObject ();
139                        ev.link.remove();
140                } else if (event.getEventObject () instanceof SimEvent.LinkModify)
141                {
142                        SimEvent.LinkModify ev = (SimEvent.LinkModify) event.getEventObject ();
143                        ev.link.setCapacity(ev.newCapacity);
144                } else if (event.getEventObject () instanceof SimEvent.NodesAndLinksChangeFailureState)
145                {
146                        SimEvent.NodesAndLinksChangeFailureState ev = (SimEvent.NodesAndLinksChangeFailureState) event.getEventObject ();
147                        currentNetPlan.setLinksAndNodesFailureState(ev.linksToUp , ev.linksToDown , ev.nodesToUp , ev.nodesToDown);
148                }
149                else throw new Net2PlanException ("Unknown event type: " + event);
150
151                /* Link weights from netPlan, but the down links have Double.MAX_VALUE weight */
152                DoubleMatrix1D linkIGPWeightSetting = IPUtils.getLinkWeightVector(currentNetPlan , ipLayer);
153                linkIGPWeightSetting.assign (currentNetPlan.getVectorLinkUpState(ipLayer) , new DoubleDoubleFunction () { public double apply (double x , double y) { return y == 1? x : Double.MAX_VALUE; }  } );
154                IPUtils.setECMPForwardingRulesFromLinkWeights(currentNetPlan , linkIGPWeightSetting , ipLayer);
155//              System.out.println ("-- CHANGE OSPF ROUTING: linkIGPWeightSetting: "  + linkIGPWeightSetting);
156        }
157
158        @Override
159        public void finishTransitory(double simTime)
160        {
161                this.stat_trafficOffered = 0;
162                this.stat_trafficCarried = 0;
163                this.stat_trafficOversubscribed = 0;
164                this.stat_trafficOutOfLatencyLimit = 0;
165                this.stat_trafficOfDemandsTraversingOversubscribedLink = 0;
166                this.stat_transitoryInitTime = simTime;
167        }
168
169        @Override
170        public String finish(StringBuilder output, double simTime)
171        {
172                final double dataTime = simTime - stat_transitoryInitTime;
173                if (dataTime <= 0) { output.append ("<p>No time for data acquisition</p>"); return ""; }
174                output.append (String.format("<p>Time average traffic offered / carried / blocking (%f , %f , %f) </p>", stat_trafficOffered / dataTime, stat_trafficCarried / dataTime , stat_trafficOffered == 0? 0 : 1 - (stat_trafficCarried / stat_trafficOffered)));
175                output.append (String.format("<p>Time average traffic oversubscribed: %f (sum traffic oversubscription in the links) </p>", stat_trafficOversubscribed / dataTime));
176                output.append (String.format("<p>Time average traffic of demands with worse case propagation time out of latency limits: %f</p>", stat_trafficOutOfLatencyLimit / dataTime));
177                output.append (String.format("<p>Time average traffic of demands which traverse an oversubscribed link (summing all the demand offered traffic, even if only a fraction of traffic traverses oversubscribed links): %f</p>", stat_trafficOfDemandsTraversingOversubscribedLink / dataTime));
178                return "";
179        }
180}