001package com.net2plan.examples.general.onlineSim;
002/*******************************************************************************
003 * Copyright (c) 2017 Pablo Pavon Marino and others.
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the 2-clause BSD License 
006 * which accompanies this distribution, and is available at
007 * https://opensource.org/licenses/BSD-2-Clause
008 *
009 * Contributors:
010 *     Pablo Pavon Marino and others - initial API and implementation
011 *******************************************************************************/
012
013
014import com.net2plan.interfaces.networkDesign.*;
015import com.net2plan.interfaces.simulation.IEventProcessor;
016import com.net2plan.interfaces.simulation.SimEvent;
017import com.net2plan.libraries.IPUtils;
018import com.net2plan.libraries.WDMUtils;
019import com.net2plan.utils.InputParameter;
020import com.net2plan.utils.Triple;
021
022import java.util.HashSet;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027/** 
028 * <p>Implements the reactions of an IP over WDM multilayer network, where the IP traffic is carried over lightpaths routed over 
029 * a topology of fiber links with a fixed or a flexible wavelength grid.</p>
030 * 
031 * <p>The design follows the assumptions described in {@link com.net2plan.libraries.WDMUtils WDMUtils} Net2Plan library</p>
032 * 
033 * <p>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 
034 * 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 
035 * failure processes, propagating the failures and repairs at the WDM layer, as links down/up events in the IP layer.</p> 
036 * 
037 * <p>The algorithm reacts to the following events:</p>
038 * <ul>
039 * <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>
040 * <li>WDMUtils.LightpathRemove: Removes the corresponding lightpath, releasing the resources and updating both layers.</li>
041 * <li>SimEvent.DemandAdd: (only for the IP layer) Forwards this event to the IP layer module. The target module behaves appropriately.</li>
042 * <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>
043 * <li>SimEvent.DemandRemove: (only for the IP layer) Forwards this event to the IP layer module. The target module behaves appropriately.</li>
044 * <li>SimEvent.NodesAndLinksChangeFailureState: This event is first forwarded to the WDM layer module, with the fails/repairs associated to its layer. Then, the event 
045 * 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 
046 * 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>
047 * </ul>
048 * 
049 * <p>This module can be used in conjunction with the {@code Online_evGen_ipOverWdm} generator for simulating IP over WDM designs.</p> 
050 * 
051 * <p>See the technology conventions used in Net2Plan built-in algorithms and libraries to represent IP and WDM networks.</p> 
052 * @net2plan.keywords IP/OSPF, WDM, Multilayer, Network recovery: protection, Network recovery: restoration
053 * @net2plan.inputParameters 
054 * @author Pablo Pavon-Marino
055 */
056public class Online_evProc_ipOverWdm extends IEventProcessor
057{
058        private InputParameter wdmNumFrequencySlotsPerFiber = new InputParameter ("wdmNumFrequencySlotsPerFiber", (int) 40 , "Set the number of frequency slots per fiber. If < 1, the number of slots set in the input file is used.");
059        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");
060        private InputParameter wdmK = new InputParameter ("wdmK", (int) 2 , "Maximum number of admissible paths per demand" , 1 , Integer.MAX_VALUE);
061        private InputParameter wdmRandomSeed = new InputParameter ("wdmRandomSeed", (long) 1 , "Seed for the random generator (-1 means random)");
062        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");
063        private InputParameter wdmRemovePreviousLightpaths = new InputParameter ("wdmRemovePreviousLightpaths", false  , "If true, previous lightpaths are removed from the system during initialization.");
064//      private InputParameter wdmProtectionTypeToNewRoutes = new InputParameter ("wdmProtectionTypeToNewRoutes", "#select# none 1+1-link-disjoint 1+1-node-disjoint 1+1-srg-disjoint" , "");
065//      private InputParameter wdmProtectionTypeIfProtectionToNewRoutes = new InputParameter ("wdmProtectionTypeIfProtectionToNewRoutes", "#select# 1+1-link-disjoint 1+1-node-disjoint 1+1-srg-disjoint" , "");
066        private InputParameter wdmDefaultAndNewRouteRevoveryType = new InputParameter ("wdmDefaultAndNewRouteRevoveryType", "#select# none restoration 1+1-link-disjoint 1+1-node-disjoint 1+1-srg-disjoint" , "New lightpaths are not protected, or are protected by a 1+1 link disjoint, or a node disjoint or a SRG disjoint lightpath");
067        private InputParameter wdmTransponderTypesInfo = new InputParameter ("wdmTransponderTypesInfo", "10 1 1 9600 1" , "Transpoder types separated by \";\" . Each type is characterized by the space-separated values: (i) Line rate in Gbps, (ii) cost of the transponder, (iii) number of slots occupied in each traversed fiber, (iv) optical reach in km (a non-positive number means no reach limit), (v) cost of the optical signal regenerator (regenerators do NOT make wavelength conversion ; if negative, regeneration is not possible).");
068
069        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)");
070
071//      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.");
072        
073        private NetworkLayer wdmLayer , ipLayer;
074        private IEventProcessor ospfNetwork , wdmNetwork;
075        
076        @Override
077        public String getDescription()
078        {
079                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";
080        }
081        
082        @Override
083        public List<Triple<String, String, String>> getParameters()
084        {
085                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
086                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
087        }
088
089        @Override
090        public void initialize(NetPlan initialNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters)
091        {
092                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
093                InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
094                
095                this.ipLayer = initialNetPlan.getNetworkLayer("IP"); if (ipLayer == null) throw new Net2PlanException ("IP layer not found");
096                this.wdmLayer = initialNetPlan.getNetworkLayer("WDM"); if (wdmLayer == null) throw new Net2PlanException ("WDM layer not found");
097                if (initialNetPlan.getNumberOfLayers() != 2) throw new Net2PlanException ("The input design must have two layers");
098
099                this.ospfNetwork = new Online_evProc_ipOspf();
100                this.wdmNetwork = new Online_evProc_wdm();
101
102                Map<String,String> wdmParam = InputParameter.createMapFromInputParameters(new InputParameter [] 
103                                { wdmNumFrequencySlotsPerFiber , wdmRwaType ,  wdmK , wdmRandomSeed , wdmTransponderTypesInfo ,  
104                                wdmMaxLightpathNumHops , wdmRemovePreviousLightpaths , wdmDefaultAndNewRouteRevoveryType } );
105
106                this.wdmNetwork.initialize(initialNetPlan , wdmParam , simulationParameters , net2planParameters);
107
108                Map<String,String> ipParam = InputParameter.createMapFromInputParameters(new InputParameter [] { ipMaximumE2ELatencyMs } );
109                this.ospfNetwork.initialize(initialNetPlan , ipParam , simulationParameters , net2planParameters);
110
111                Set<Link> ipLinksDownBecauseOfWDMLayer = new HashSet<Link> (); for (Link ipLink : initialNetPlan.getLinks (ipLayer)) if (ipLink.getCapacity() == 0)  ipLinksDownBecauseOfWDMLayer.add (ipLink); 
112                SimEvent.NodesAndLinksChangeFailureState evIp = new SimEvent.NodesAndLinksChangeFailureState(null , null , null , ipLinksDownBecauseOfWDMLayer);
113                ospfNetwork.processEvent(initialNetPlan , new SimEvent(0 , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
114        }
115        
116        @Override
117        public void processEvent(NetPlan currentNetPlan, SimEvent event)
118        {
119                /* First, the WDM layer reacts */
120                if (event.getEventObject () instanceof WDMUtils.LightpathAdd)
121                {
122                        WDMUtils.LightpathAdd addLpEvent = (WDMUtils.LightpathAdd) event.getEventObject ();
123                        wdmNetwork.processEvent(currentNetPlan , event);
124                        if (addLpEvent.lpAddedToFillByProcessor != null)
125                        {
126                                Route addedLp = addLpEvent.lpAddedToFillByProcessor;
127                                /* The lightpath was added */
128                                SimEvent.LinkAdd evIp = new SimEvent.LinkAdd(addLpEvent.ingressNode , addLpEvent.egressNode , ipLayer , addLpEvent.lineRateGbps , addedLp.getLengthInKm() , addedLp.getPropagationSpeedInKmPerSecond());
129                                ospfNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
130                                if (evIp.linkAddedToFillByProcessor == null) throw new RuntimeException ("Bad");
131                                IPUtils.setLinkWeight(evIp.linkAddedToFillByProcessor , (double) 1);
132                                final Demand lpWdmDemand = addedLp.getDemand(); if (lpWdmDemand.getRoutes().size() != 1) throw new Net2PlanException ("Each lightpath must be hosted in its own WDM demand");
133                                lpWdmDemand.coupleToUpperOrSameLayerLink(evIp.linkAddedToFillByProcessor);
134                        }
135                }
136                else if (event.getEventObject () instanceof WDMUtils.LightpathRemove)
137                {
138                        WDMUtils.LightpathRemove removeLpEvent = (WDMUtils.LightpathRemove) event.getEventObject ();
139                        SimEvent.LinkRemove evIp = new SimEvent.LinkRemove(removeLpEvent.lp.getDemand().getCoupledLink());
140                        ospfNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
141                        SimEvent.DemandRemove evWdmDemandRemove = new SimEvent.DemandRemove(removeLpEvent.lp.getDemand());
142                        wdmNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evWdmDemandRemove));
143                }
144                else if (event.getEventObject () instanceof SimEvent.DemandModify) 
145                {
146                        if (((SimEvent.DemandModify) event.getEventObject ()).demand.getLayer() == wdmLayer) wdmNetwork.processEvent(currentNetPlan , event); 
147                        else if (((SimEvent.DemandModify) event.getEventObject ()).demand.getLayer() == ipLayer) ospfNetwork.processEvent(currentNetPlan , event);
148                } 
149                /* Events for the IP layer */
150                else if (event.getEventObject () instanceof SimEvent.DemandAdd)
151                {
152                        if (((SimEvent.DemandAdd) event.getEventObject ()).layer == ipLayer) ospfNetwork.processEvent(currentNetPlan , event);
153                        throw new Net2PlanException ("This algorithm does not handle events of the type DemandAdd, for the WDM layer");
154                }
155                else if (event.getEventObject () instanceof SimEvent.DemandRemove)
156                {
157                        if (((SimEvent.DemandRemove) event.getEventObject ()).demand.getLayer() == ipLayer) ospfNetwork.processEvent(currentNetPlan , event);
158                        throw new Net2PlanException ("This algorithm does not handle events of the type DemandRemove, for the WDM layer");
159                }
160                else if (event.getEventObject () instanceof SimEvent.NodesAndLinksChangeFailureState)
161                {
162                        /* each layer processes all node events, and the link events of its layer */
163                        SimEvent.NodesAndLinksChangeFailureState ev = (SimEvent.NodesAndLinksChangeFailureState) event.getEventObject ();
164                        Set<Link> ipLinksUp = new HashSet<Link> ();
165                        Set<Link> wdmLinksUp = new HashSet<Link> ();
166                        Set<Link> ipLinksDown = new HashSet<Link> ();
167                        Set<Link> wdmLinksDown = new HashSet<Link> ();
168//                      System.out.println ("-- ev.linksDown: " + ev.linksDown);
169
170                        if (ev.linksToDown != null) for (Link e : ev.linksToDown) if (e.getLayer () == ipLayer) ipLinksDown.add (e); else if (e.getLayer () == wdmLayer) wdmLinksDown.add (e); 
171                        if (ev.linksToUp != null) for (Link e : ev.linksToUp) if (e.getLayer () == ipLayer) ipLinksUp.add (e); else if (e.getLayer () == wdmLayer) wdmLinksUp.add (e); 
172
173//                      System.out.println ("-- original ip links up: " + ipLinksUp);
174//                      System.out.println ("-- original ip links down: " + ipLinksDown);
175//                      System.out.println ("-- original wdm links up: " + wdmLinksUp);
176//                      System.out.println ("-- original wdm links down: " + wdmLinksDown);
177                        
178                        /* Failures at WDM layer are processed */
179//                      System.out.println ("-- process wdm links up/down: " + wdmLinksDown + ", wdmLinksUp: " + wdmLinksUp + ", ev.nodesToUp : " + ev.nodesToUp  + ", ev.nodesToDown: " +  ev.nodesToDown);
180                        SimEvent.NodesAndLinksChangeFailureState evWdm = new SimEvent.NodesAndLinksChangeFailureState(ev.nodesToUp , ev.nodesToDown , wdmLinksUp , wdmLinksDown);
181                        wdmNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evWdm));
182                        
183                        /* Lightpaths with no traffic carried, mean that they are down => OSPF should treat them as down IP links => propagate these failures to IP layer */
184                        Set<Link> ipLinksDownBecauseOfWDMLayer = new HashSet<Link> (); for (Link ipLink : currentNetPlan.getLinks (ipLayer)) if (ipLink.getCapacity() == 0)  ipLinksDownBecauseOfWDMLayer.add (ipLink); 
185//                      System.out.println ("-- ipLinksDownBecauseOfWDMLayer: " + ipLinksDownBecauseOfWDMLayer);
186                        ipLinksDown.addAll (ipLinksDownBecauseOfWDMLayer);
187//                      System.out.println ("-- total ipLinksDown: " + ipLinksDown);
188                        ipLinksUp = new HashSet<Link> (currentNetPlan.getLinks (ipLayer)); ipLinksUp.removeAll (ipLinksDown);
189//                      System.out.println ("-- ipLinksUp: " + ipLinksUp);
190//                      System.out.println ("-- ev.nodesToUp: " + ev.nodesToUp);
191//                      System.out.println ("-- ev.nodesToDown: " + ev.nodesToDown);
192                        SimEvent.NodesAndLinksChangeFailureState evIp = new SimEvent.NodesAndLinksChangeFailureState(ev.nodesToUp , ev.nodesToDown , ipLinksUp , ipLinksDown);
193                        ospfNetwork.processEvent(currentNetPlan , new SimEvent(event.getEventTime() , SimEvent.DestinationModule.EVENT_GENERATOR , -1 , evIp));
194                }
195                else if(event.getEventObject() instanceof WDMUtils.LightpathModify) 
196                {
197                        wdmNetwork.processEvent(currentNetPlan, new SimEvent(event.getEventTime(), SimEvent.DestinationModule.EVENT_GENERATOR, - 1, (WDMUtils.LightpathModify)event.getEventObject()));
198                }
199                else throw new Net2PlanException ("Unknown event type: " + event);
200                
201        }       
202        
203
204        @Override
205        public String finish(StringBuilder output, double simTime)
206        {
207                output.append ("WDM LAYER OUTPUT");
208                wdmNetwork.finish(output , simTime);
209                output.append ("<p></p>IP LAYER OUTPUT");
210                
211                ospfNetwork.finish(output , simTime);
212                return "";
213        }
214
215        @Override
216        public void finishTransitory(double simTime)
217        {
218                wdmNetwork.finishTransitory(simTime);
219                ospfNetwork.finishTransitory(simTime);
220        }
221
222}