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
018package com.net2plan.examples.general.onlineSim;
019
020import java.util.HashSet;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import com.net2plan.interfaces.networkDesign.Demand;
026import com.net2plan.interfaces.networkDesign.Link;
027import com.net2plan.interfaces.networkDesign.Net2PlanException;
028import com.net2plan.interfaces.networkDesign.NetPlan;
029import com.net2plan.interfaces.networkDesign.NetworkLayer;
030import com.net2plan.interfaces.networkDesign.Route;
031import com.net2plan.interfaces.simulation.IEventProcessor;
032import com.net2plan.interfaces.simulation.SimEvent;
033import com.net2plan.libraries.IPUtils;
034import com.net2plan.libraries.WDMUtils;
035import com.net2plan.utils.InputParameter;
036import com.net2plan.utils.Triple;
037
038/** 
039 * Implements the reactions of an IP over WDM multilayer network, where the IP traffic is carried over fixed rate lightpaths, routed over a topology of fiber links with a fixed wavelength grid
040 * 
041 * This algorithm implements the reactions of an IP over WDM multilayer network. Internally, the algorithm just coordinates the reactions of the WDM layer and the 
042 * IP layer, each of them implemented by the {@code Online_evProv_wdm} and {@code Online_evProc_ipOspf} modules. The coordination actions are basically during the 
043 * failure processes, propagating the failures and repairs at the WDM layer, as links down/up events in the IP layer. 
044 * 
045 * The algorithm reacts to the following events:
046 * <ul>
047 * <li>WDMUtils.LightpathAdd: Adds the corresponding lightpath to the network, if enough resources exist for it, calling to the WDM layer module. If so, it is added also as an IP link, and the IP routing modified, by calling the IP module.</li>
048 * <li>WDMUtils.LightpathRemove: Removes the corresponding lightpath, releasing the resources and updating both layers.</li>
049 * <li>SimEvent.DemandAdd: (only for the IP layer) Forwards this event to the IP layer module. The target module behaves appropriately.</li>
050 * <li>SimEvent.DemandModify: Forwards this event to the WDM or IP layer modules, depending on the event associated layer. The target module behaves appropriately.</li>
051 * <li>SimEvent.DemandRemove: (only for the IP layer) Forwards this event to the IP layer module. The target module behaves appropriately.</li>
052 * <li>SimEvent.NodesAndLinksChangeFailureState: This event is first forwarded to the WDM layer module, with the fails/repairs associated to its layer. Then, the event 
053 * is sent to the IP layer, updating the IP links failures and repairs, depending on the results of the WDM layer. For instance, any WDM failures that result in a WDM 
054 * demand carrying no traffic (affected by a failure for which it could not recover), is propagated to the IP layer as a failing IP link.</li>
055 * </ul>
056 * 
057 * This module can be used in conjunction with the {@code Online_evGen_ipOverWdm} generator for simulating IP over WDM designs. 
058 * 
059 * See the technology conventions used in Net2Plan built-in algorithms and libraries to represent IP and WDM networks. 
060 * @net2plan.keywords IP/OSPF, WDM, Multilayer, Network recovery: protection, Network recovery: restoration
061 * @net2plan.inputParameters 
062 * @author Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza
063 */
064public class Online_evProc_ipOverWdm extends IEventProcessor
065{
066        private InputParameter wdmNumWavelengthsPerFiber = new InputParameter ("wdmNumWavelengthsPerFiber", (int) 40 , "Set the number of wavelengths per link. If < 1, the number of wavelengths set in the input file is used.");
067        private InputParameter wdmRwaType = new InputParameter ("wdmRwaType", "#select# srg-disjointness-aware-route-first-fit alternate-routing least-congested-routing load-sharing" , "Criteria to decide the route of a connection among the available paths");
068        private InputParameter wdmKShortestPathType = new InputParameter ("wdmKShortestPathType", "#select# hops km" , "Criteria to compute the shortest path. Valid values: 'hops' or 'km'");
069        private InputParameter wdmK = new InputParameter ("wdmK", (int) 2 , "Maximum number of admissible paths per demand" , 1 , Integer.MAX_VALUE);
070        private InputParameter wdmRandomSeed = new InputParameter ("wdmRandomSeed", (long) 1 , "Seed for the random generator (-1 means random)");
071        private InputParameter wdmMaxLightpathLengthInKm = new InputParameter ("wdmMaxLightpathLengthInKm", (double) -1 , "Lightpaths longer than this are considered not admissible. A non-positive number means this limit does not exist");
072        private InputParameter wdmMaxLightpathNumHops = new InputParameter ("wdmMaxLightpathNumHops", (int) -1 , "A lightpath cannot have more than this number of hops. A non-positive number means this limit does not exist");
073        private InputParameter wdmLayerIndex = new InputParameter ("wdmLayerIndex", (int) 0 , "Index of the WDM layer (-1 means default layer)");
074        private InputParameter wdmRemovePreviousLightpaths = new InputParameter ("wdmRemovePreviousLightpaths", false  , "If true, previous lightpaths are removed from the system during initialization.");
075        private InputParameter wdmProtectionTypeToNewRoutes = new InputParameter ("wdmProtectionTypeToNewRoutes", "#select# none 1+1-link-disjoint 1+1-node-disjoint 1+1-srg-disjoint" , "");
076        private InputParameter wdmLineRatePerLightpath_Gbps = new InputParameter ("wdmLineRatePerLightpath_Gbps", (double) 40 , "All the lightpaths have this carried traffic by default, when a lightpath is added and this quantity is not specified in the add lightpath event" , 0 , false , Double.MAX_VALUE , true);
077
078        private InputParameter ipLayerIndex = new InputParameter ("ipLayerIndex", (int) 1 , "Index of the layer containing IP network (-1 means default layer)");
079        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)");
080
081        private InputParameter ipOverWdmNetworkRecoveryType = new InputParameter ("ipOverWdmNetworkRecoveryType", "#select# static-lps-OSPF-rerouting 1+1-lps-OSPF-rerouting lp-restoration-OSPF-rerouting" , "The recovery type the network will apply. If static lps, the VT is overdimensioned to tolerate single SRG failures. In the 1+1 case, link disjoit backup lps are created. If lps are 1+1 protected or have lp restoration, the VT is dimensioned to carry all IP traffic in the no failure state.");
082        
083        private NetworkLayer wdmLayer , ipLayer;
084        private IEventProcessor ospfNetwork , wdmNetwork;
085        
086        @Override
087        public String getDescription()
088        {
089                return "Implements the reactions of an IP over WDM multilayer network, where the IP traffic is carried over fixed rate lightpaths, routed over a topology of fiber links with a fixed wavelength grid";
090        }
091        
092        @Override
093        public List<Triple<String, String, String>> getParameters()
094        {
095                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
096                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
097        }
098
099        @Override
100        public void initialize(NetPlan initialNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters)
101        {
102                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
103//              System.out.println ("IP over WDM algoritm params: " + algorithmParameters);
104                InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
105                if (!ipOverWdmNetworkRecoveryType.getString().equals("1+1-lps-OSPF-rerouting") && !wdmProtectionTypeToNewRoutes.getString().equals ("none")) throw new Net2PlanException ("The type of 1+1 protection can only be specified in network recovery uses lightpath protection");
106                
107                this.ipLayer = ipLayerIndex.getInt () == -1? initialNetPlan.getNetworkLayerDefault() : initialNetPlan.getNetworkLayer(ipLayerIndex.getInt ());
108                this.wdmLayer = wdmLayerIndex.getInt () == -1? initialNetPlan.getNetworkLayerDefault() : initialNetPlan.getNetworkLayer(wdmLayerIndex.getInt ());
109                if (initialNetPlan.getNumberOfLayers() != 2) throw new Net2PlanException ("The input design must have two layers");
110                if (ipLayer == wdmLayer) throw new Net2PlanException ("IP layer and/or WDM layer ids are wrong");
111
112                this.ospfNetwork = new Online_evProc_ipOspf();
113                this.wdmNetwork = new Online_evProc_wdm();
114
115                Map<String,String> wdmParam = InputParameter.createMapFromInputParameters(new InputParameter [] 
116                                { wdmNumWavelengthsPerFiber , wdmRwaType ,  wdmKShortestPathType , wdmK , wdmRandomSeed , wdmMaxLightpathLengthInKm ,  
117                                wdmMaxLightpathNumHops , wdmLayerIndex , wdmRemovePreviousLightpaths , wdmLineRatePerLightpath_Gbps } );
118                String wdmRecoveryType , wdmProtectionTypeToNewRoutes_st;
119                if (ipOverWdmNetworkRecoveryType.getString ().equals ("static-lps-OSPF-rerouting")) { wdmRecoveryType = "none"; wdmProtectionTypeToNewRoutes_st = "none"; }
120                else if (ipOverWdmNetworkRecoveryType.getString ().equals ("1+1-lps-OSPF-rerouting")) { wdmRecoveryType = "protection"; wdmProtectionTypeToNewRoutes_st = wdmProtectionTypeToNewRoutes.getString (); }
121                else if (ipOverWdmNetworkRecoveryType.getString ().equals ("lp-restoration-OSPF-rerouting")) {wdmRecoveryType = "restoration"; wdmProtectionTypeToNewRoutes_st = "none"; }
122                else throw new RuntimeException ("Bad");
123                wdmParam.put ("wdmRecoveryType" , wdmRecoveryType);
124                wdmParam.put ("wdmProtectionTypeToNewRoutes" , wdmProtectionTypeToNewRoutes_st);
125                this.wdmNetwork.initialize(initialNetPlan , wdmParam , simulationParameters , net2planParameters);
126
127                Map<String,String> ipParam = InputParameter.createMapFromInputParameters(new InputParameter [] { ipLayerIndex  , ipMaximumE2ELatencyMs } );
128                this.ospfNetwork.initialize(initialNetPlan , ipParam , simulationParameters , net2planParameters);
129
130                Set<Link> ipLinksDownBecauseOfWDMLayer = new HashSet<Link> (); for (Link ipLink : initialNetPlan.getLinks (ipLayer)) if (ipLink.getCapacity() == 0)  ipLinksDownBecauseOfWDMLayer.add (ipLink); 
131                SimEvent.NodesAndLinksChangeFailureState evIp = new SimEvent.NodesAndLinksChangeFailureState(null , null , null , ipLinksDownBecauseOfWDMLayer);
132                ospfNetwork.processEvent(initialNetPlan , new SimEvent(0 , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
133}
134
135        @Override
136        public void processEvent(NetPlan currentNetPlan, SimEvent event)
137        {
138                /* First, the WDM layer reacts */
139                if (event.getEventObject () instanceof WDMUtils.LightpathAdd)
140                {
141                        WDMUtils.LightpathAdd addLpEvent = (WDMUtils.LightpathAdd) event.getEventObject ();
142                        wdmNetwork.processEvent(currentNetPlan , event);
143                        if (addLpEvent.lpAddedToFillByProcessor != null)
144                        {
145                                Route addedLp = addLpEvent.lpAddedToFillByProcessor;
146                                /* The lightpath was added */
147                                SimEvent.LinkAdd evIp = new SimEvent.LinkAdd(addLpEvent.ingressNode , addLpEvent.egressNode , ipLayer , wdmLineRatePerLightpath_Gbps.getDouble() , addedLp.getLengthInKm() , addedLp.getPropagationSpeedInKmPerSecond());
148                                ospfNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
149                                if (evIp.linkAddedToFillByProcessor == null) throw new RuntimeException ("Bad");
150                                IPUtils.setLinkWeight(evIp.linkAddedToFillByProcessor , (double) 1);
151                                final Demand lpWdmDemand = addedLp.getDemand(); if (lpWdmDemand.getRoutes().size() != 1) throw new Net2PlanException ("Each lightpath must be hosted in its own WDM demand");
152                                lpWdmDemand.coupleToUpperLayerLink(evIp.linkAddedToFillByProcessor);
153                        }
154                }
155                else if (event.getEventObject () instanceof WDMUtils.LightpathRemove)
156                {
157                        WDMUtils.LightpathRemove removeLpEvent = (WDMUtils.LightpathRemove) event.getEventObject ();
158                        SimEvent.LinkRemove evIp = new SimEvent.LinkRemove(removeLpEvent.lp.getDemand().getCoupledLink());
159                        ospfNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
160                        SimEvent.DemandRemove evWdmDemandRemove = new SimEvent.DemandRemove(removeLpEvent.lp.getDemand());
161                        wdmNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evWdmDemandRemove));
162                }
163                else if (event.getEventObject () instanceof SimEvent.DemandModify) 
164                {
165                        if (((SimEvent.DemandModify) event.getEventObject ()).demand.getLayer() == wdmLayer) wdmNetwork.processEvent(currentNetPlan , event); 
166                        else if (((SimEvent.DemandModify) event.getEventObject ()).demand.getLayer() == ipLayer) ospfNetwork.processEvent(currentNetPlan , event);
167                } 
168                /* Events for the IP layer */
169                else if (event.getEventObject () instanceof SimEvent.DemandAdd)
170                {
171                        if (((SimEvent.DemandAdd) event.getEventObject ()).layer == ipLayer) ospfNetwork.processEvent(currentNetPlan , event);
172                        throw new Net2PlanException ("This algorithm does not handle events of the type DemandAdd, for the WDM layer");
173                }
174                else if (event.getEventObject () instanceof SimEvent.DemandRemove)
175                {
176                        if (((SimEvent.DemandRemove) event.getEventObject ()).demand.getLayer() == ipLayer) ospfNetwork.processEvent(currentNetPlan , event);
177                        throw new Net2PlanException ("This algorithm does not handle events of the type DemandRemove, for the WDM layer");
178                }
179                else if (event.getEventObject () instanceof SimEvent.NodesAndLinksChangeFailureState)
180                {
181                        /* each layer processes all node events, and the link events of its layer */
182                        SimEvent.NodesAndLinksChangeFailureState ev = (SimEvent.NodesAndLinksChangeFailureState) event.getEventObject ();
183                        Set<Link> ipLinksUp = new HashSet<Link> ();
184                        Set<Link> wdmLinksUp = new HashSet<Link> ();
185                        Set<Link> ipLinksDown = new HashSet<Link> ();
186                        Set<Link> wdmLinksDown = new HashSet<Link> ();
187//                      System.out.println ("-- ev.linksDown: " + ev.linksDown);
188
189                        if (ev.linksToDown != null) for (Link e : ev.linksToDown) if (e.getLayer () == ipLayer) ipLinksDown.add (e); else if (e.getLayer () == wdmLayer) wdmLinksDown.add (e); 
190                        if (ev.linksToUp != null) for (Link e : ev.linksToUp) if (e.getLayer () == ipLayer) ipLinksUp.add (e); else if (e.getLayer () == wdmLayer) wdmLinksUp.add (e); 
191
192//                      System.out.println ("-- original ip links up: " + ipLinksUp);
193//                      System.out.println ("-- original ip links down: " + ipLinksDown);
194//                      System.out.println ("-- original wdm links up: " + wdmLinksUp);
195//                      System.out.println ("-- original wdm links down: " + wdmLinksDown);
196                        
197                        /* Failures at WDM layer are processed */
198//                      System.out.println ("-- process wdm links up/down: " + wdmLinksDown + ", wdmLinksUp: " + wdmLinksUp + ", ev.nodesToUp : " + ev.nodesToUp  + ", ev.nodesToDown: " +  ev.nodesToDown);
199                        SimEvent.NodesAndLinksChangeFailureState evWdm = new SimEvent.NodesAndLinksChangeFailureState(ev.nodesToUp , ev.nodesToDown , wdmLinksUp , wdmLinksDown);
200                        wdmNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evWdm));
201                        
202                        /* Lightpaths with no traffic carried, mean that they are down => OSPF should treat them as down IP links => propagate these failures to IP layer */
203                        Set<Link> ipLinksDownBecauseOfWDMLayer = new HashSet<Link> (); for (Link ipLink : currentNetPlan.getLinks (ipLayer)) if (ipLink.getCapacity() == 0)  ipLinksDownBecauseOfWDMLayer.add (ipLink); 
204//                      System.out.println ("-- ipLinksDownBecauseOfWDMLayer: " + ipLinksDownBecauseOfWDMLayer);
205                        ipLinksDown.addAll (ipLinksDownBecauseOfWDMLayer);
206//                      System.out.println ("-- total ipLinksDown: " + ipLinksDown);
207                        ipLinksUp = new HashSet<Link> (currentNetPlan.getLinks (ipLayer)); ipLinksUp.removeAll (ipLinksDown);
208//                      System.out.println ("-- ipLinksUp: " + ipLinksUp);
209//                      System.out.println ("-- ev.nodesToUp: " + ev.nodesToUp);
210//                      System.out.println ("-- ev.nodesToDown: " + ev.nodesToDown);
211                        SimEvent.NodesAndLinksChangeFailureState evIp = new SimEvent.NodesAndLinksChangeFailureState(ev.nodesToUp , ev.nodesToDown , ipLinksUp , ipLinksDown);
212                        ospfNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
213                }
214                else throw new Net2PlanException ("Unknown event type: " + event);
215                
216        }       
217        
218
219        @Override
220        public String finish(StringBuilder output, double simTime)
221        {
222                output.append ("WDM LAYER OUTPUT");
223                wdmNetwork.finish(output , simTime);
224                output.append ("<p></p>IP LAYER OUTPUT");
225                
226                ospfNetwork.finish(output , simTime);
227                return "";
228        }
229
230        @Override
231        public void finishTransitory(double simTime)
232        {
233                wdmNetwork.finishTransitory(simTime);
234                ospfNetwork.finishTransitory(simTime);
235        }
236
237}