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
017package com.net2plan.examples.ocnbook.reports;
018
019import java.io.File;
020import java.text.DecimalFormat;
021import java.util.ArrayList;
022import java.util.HashSet;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026
027import com.net2plan.interfaces.networkDesign.Demand;
028import com.net2plan.interfaces.networkDesign.IReport;
029import com.net2plan.interfaces.networkDesign.Link;
030import com.net2plan.interfaces.networkDesign.MulticastDemand;
031import com.net2plan.interfaces.networkDesign.Net2PlanException;
032import com.net2plan.interfaces.networkDesign.NetPlan;
033import com.net2plan.interfaces.networkDesign.NetworkLayer;
034import com.net2plan.interfaces.networkDesign.Node;
035import com.net2plan.interfaces.networkDesign.SharedRiskGroup;
036import com.net2plan.interfaces.simulation.IEventProcessor;
037import com.net2plan.interfaces.simulation.SimEvent;
038import com.net2plan.libraries.SRGUtils;
039import com.net2plan.utils.ClassLoaderUtils;
040import com.net2plan.utils.InputParameter;
041import com.net2plan.utils.StringUtils;
042import com.net2plan.utils.Triple;
043
044/**
045 * This report receives as an input a network design, the network recovery scheme algorithm, and a set of network risks (SRGs), and computes 
046 * the availability of each network and each demand, in the no-failure state, and in each of the single-SRG failure states. 
047 * 
048 * @net2plan.keywords Network recovery: protection , Network recovery: restoration
049 * @net2plan.ocnbooksections Section 3.7.3
050 * @net2plan.inputParameters 
051 * @author Pablo Pavon-Marino
052 */
053public class Report_perSRGFailureAnalysis implements IReport
054{
055        private InputParameter provisioningAlgorithm = new InputParameter ("provisioningAlgorithm" , "#eventProcessor#" , "Algorithm to process failure events");
056        private InputParameter considerTrafficInOversubscribedLinksAsLost = new InputParameter ("considerTrafficInOversubscribedLinksAsLost" , true , "If true, all the demands whose traffic (even only a fraction of it) traverses an oversubscribed link, are considered that all its treaffic is blocked, as they are supposed to fail to satisfy QoS agreements");
057        private InputParameter maximumE2ELatencyMs = new InputParameter ("maximumE2ELatencyMs", (double) -1 , "Maximum end-to-end latency of the traffic of any demand (a non-positive value means no limit). All the traffic of demands where a fraction of its traffic can exceed this value, are considered as lost, as they are supposed to fail to satisfy QoS agreements");
058        private InputParameter failureModel = new InputParameter ("failureModel" , "#select# perBidirectionalLinkBundle SRGfromNetPlan perNode perLink perDirectionalLinkBundle" , "Failure model selection: SRGfromNetPlan, perNode, perLink, perDirectionalLinkBundle, perBidirectionalLinkBundle");
059        private InputParameter rootNameOfOutFiles = new InputParameter ("rootNameOfOutFiles" , "./reportPerSRGFailure" , "For each single-SRG failure state and for the no-failure state, a n2p file is produced with the result of the network in that state. The file is named XXX_srgIndex.n2p, and XXX_noFailure.n2p, where XXX is this parameter");
060
061        private IEventProcessor algorithm;
062        private double PRECISION_FACTOR;
063        
064        @Override
065        public String executeReport(NetPlan netPlan, Map<String, String> reportParameters, Map<String, String> net2planParameters)
066        {
067                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
068                InputParameter.initializeAllInputParameterFieldsOfObject(this, reportParameters);
069
070                String algorithmFile = reportParameters.get("provisioningAlgorithm_file");
071                String algorithmName = reportParameters.get("provisioningAlgorithm_classname");
072                String algorithmParam = reportParameters.get("provisioningAlgorithm_parameters");
073                if (algorithmFile.isEmpty() || algorithmName.isEmpty()) throw new Net2PlanException("A provisioning algorithm must be defined");
074                this.PRECISION_FACTOR = Double.parseDouble(net2planParameters.get("precisionFactor"));
075
076                Map<String, String> algorithmParameters = StringUtils.stringToMap(algorithmParam);
077                switch (failureModel.getString ())
078                {
079                        case "SRGfromNetPlan":
080                                break;
081
082                        case "perNode":
083                                SRGUtils.configureSRGs(netPlan, 1, 1 , SRGUtils.SharedRiskModel.PER_NODE, true);
084                                break;
085
086                        case "perLink":
087                                SRGUtils.configureSRGs(netPlan, 1, 1 , SRGUtils.SharedRiskModel.PER_LINK, true);
088                                break;
089
090                        case "perDirectionalLinkBundle":
091                                SRGUtils.configureSRGs(netPlan, 1, 1, SRGUtils.SharedRiskModel.PER_DIRECTIONAL_LINK_BUNDLE, true);
092                                break;
093
094                        case "perBidirectionalLinkBundle":
095                                SRGUtils.configureSRGs(netPlan, 1, 1, SRGUtils.SharedRiskModel.PER_BIDIRECTIONAL_LINK_BUNDLE, true);
096                                break;
097
098                        default:
099                                throw new Net2PlanException("Failure model not valid. Please, check algorithm parameters description");
100                }
101
102                /* Compute the n2p for the non failure state */
103                netPlan.setAllNodesFailureState(true);
104                for (NetworkLayer layer : netPlan.getNetworkLayers ())
105                        netPlan.setAllLinksFailureState(true , layer);
106                if (!netPlan.getLinksDownAllLayers().isEmpty() || !netPlan.getNodesDown().isEmpty()) throw new RuntimeException ("Bad");
107                NetPlan npNoFailure = netPlan.copy ();
108                npNoFailure.saveToFile(new File (rootNameOfOutFiles.getString () + "_noFailure"));
109
110                /* Initialize the provisioning algorithm */
111                NetPlan npForProducingAllFailures = netPlan.copy ();
112                Set<Link> npForProducingAllFailures_linksAllLayers = new HashSet<Link> (); for (NetworkLayer layer : npForProducingAllFailures.getNetworkLayers()) npForProducingAllFailures_linksAllLayers.addAll (npForProducingAllFailures.getLinks (layer));
113
114                this.algorithm = ClassLoaderUtils.getInstance(new File(algorithmFile), algorithmName, IEventProcessor.class);
115                this.algorithm.initialize(npForProducingAllFailures , algorithmParameters , reportParameters , net2planParameters);
116
117                /* Compute the other network states */
118                List<NetPlan> npsFailureStates = new ArrayList<NetPlan> (netPlan.getNumberOfSRGs());
119                for (int srgIndex = 0 ; srgIndex < netPlan.getNumberOfSRGs() ; srgIndex ++)
120                {
121                        if (!npForProducingAllFailures.getLinksDownAllLayers().isEmpty() || !npForProducingAllFailures.getNodesDown().isEmpty()) throw new RuntimeException ("Bad");
122
123                        /* Fail this SRG */
124                        final SharedRiskGroup srg = npForProducingAllFailures.getSRG(srgIndex);
125                        Set<Link> linksToSetAsDown = new HashSet<Link> ();
126                        Set<Node> nodesToSetAsDown = new HashSet<Node> ();
127                        nodesToSetAsDown.addAll (srg.getNodes ());
128                        linksToSetAsDown.addAll (srg.getLinks ());
129                        
130                        /* Make the algorithm process the event of nodes and links down */
131                        SimEvent.NodesAndLinksChangeFailureState failureInfo = new SimEvent.NodesAndLinksChangeFailureState(null , nodesToSetAsDown , null , linksToSetAsDown);
132                        algorithm.processEvent(npForProducingAllFailures, new SimEvent(0, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , failureInfo)); 
133                
134                        /* Save a coy of the new state */
135                        npForProducingAllFailures.saveToFile(new File (rootNameOfOutFiles.getString () + "_srgIndex_" + srgIndex));
136                        npsFailureStates.add (npForProducingAllFailures.copy ());
137                        
138                        /* Go back to the no failure state */
139                        SimEvent.NodesAndLinksChangeFailureState repairInfo = new SimEvent.NodesAndLinksChangeFailureState(npForProducingAllFailures.getNodes() , null , npForProducingAllFailures_linksAllLayers , null);
140                        algorithm.processEvent(npForProducingAllFailures, new SimEvent(0, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , repairInfo));
141                }
142                
143                return printReport(npNoFailure , npsFailureStates , reportParameters);
144        }
145        
146        @Override
147        public String getDescription()
148        {
149                return "This report receives as an input a network design, the network recovery scheme algorithm, and a set of network risks (SRGs), and computes the availability of each network and each demand, in the no-failure state, and in each of the single-SRG failure states. ";
150        }
151
152        @Override
153        public List<Triple<String, String, String>> getParameters()
154        {
155                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
156                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
157        }
158        
159
160        @Override
161        public String getTitle()
162        {
163                return "Single-SRG failure analysis report";
164        }
165        
166        private String printReport(NetPlan npNoFailure , List<NetPlan> npFailureStates , Map<String,String> reportParameters)
167        {
168                StringBuilder out = new StringBuilder();
169                DecimalFormat df_6 = new DecimalFormat("#.######");
170                out.append("<html><body>");
171                out.append("<head><title>" + getTitle () + "</title></head>");
172                out.append("<h1>Introduction</h1>");
173                out.append("<p>In contrast to the availability report, here only single failure states are simulated, where each " +
174                                "failure state is given by a single SRG going down, and all failure states have the same probability to occur.</p>" +
175                                "       <p>Definitions and conventions about failure states, availability, and so on, are the same as for the availability report.</p>");
176                out.append("<p>The report produces some summary information of the network, like demand blocking traffic, " +
177                                "traffic traversing oversubscribed links, or traffic with excessive latency, for each of the network states." );
178                out.append("<p>In addition, the report saves one N2P file for each single-SRG failing network state, and one file for the no-failure state." +
179                                " They are supposed to be used for more careful inspection of the state of the network under those situations");
180                out.append("<h1>Global information</h1>");
181                out.append("<h2>Input Parameters</h2>");
182                out.append("<table border='1'>");
183                out.append("<tr><th><b>Name</b></th><th><b>Value</b></th><th><b>Description</b></th>");
184                for (Triple<String, String, String> paramDef : getParameters())
185                {
186                        String name = paramDef.getFirst();
187                        String description = paramDef.getThird();
188                        String value = reportParameters.get(name);
189                        out.append("<tr><td>").append(name).append("</td><td>").append(value).append("</td><td>").append(description).append("</td></tr>");
190                }
191                out.append("<tr><td>Number of network layers: </td><td>" + npNoFailure.getNumberOfLayers() + "</td><td></td></tr>");
192                out.append("<tr><td>Number of SRGs defined: </td><td>" + npNoFailure.getNumberOfSRGs() + "</td><td></td></tr>");
193                out.append("</table>");
194
195                out.append("<h1>PER LAYER INFORMATION SUMMARY</h1>");
196                for (int layerIndex = 0 ; layerIndex < npNoFailure.getNumberOfLayers () ; layerIndex ++)
197                {
198                        NetworkLayer noFailureLayer = npNoFailure.getNetworkLayer (layerIndex);
199
200                        out.append("<h2>Layer " + noFailureLayer.getName () + ", index = " + noFailureLayer.getIndex () + ", id = " + noFailureLayer.getId () + "</h2>");
201
202                        if (npNoFailure.getNumberOfDemands(noFailureLayer) != 0)
203                        {
204                                out.append("<h3>Unicast traffic</h3>");
205                                out.append("<table border='1'>");
206                                out.append("<tr><th><b>SRG Index failed</b></th><th><b>Offered traffic</b></th><th><b>Blocked traffic (%)</b></th><th><b>Offered traffic traversing oversubscribed links (%)</b></th><th><b>Offered traffic of demands with excessive latency (%)</b></th><b>Total blocked traffic [out of contract] (%)</b></th><th><b>% of demands fully ok</b></th></tr>");
207                                printReport (npNoFailure , noFailureLayer , out , "No failure" , true);
208                                for (int srgIndex = 0 ; srgIndex < npNoFailure.getNumberOfSRGs() ; srgIndex ++)
209                                        printReport (npFailureStates.get(srgIndex) , npFailureStates.get(srgIndex).getNetworkLayer (layerIndex) , out , "" + srgIndex , true);
210                                out.append("</table>");
211                        }
212
213                        if (npNoFailure.getNumberOfMulticastDemands(noFailureLayer) != 0)
214                        {
215                                out.append("<h3>Multicast traffic</h3>");
216                                out.append("<table border='1'>");
217                                out.append("<tr><th><b>SRG Index failed</b></th><th><b>Offered traffic</b></th><th><b>Blocked traffic (%)</b></th><th><b>Offered traffic traversing oversubscribed links (%)</b></th><th><b>Offered traffic of demands with excessive latency (%)</b></th><b>Total blocked traffic [out of contract] (%)</b></th><th><b>% of demands fully ok</b></th></tr>");
218                                printReport (npNoFailure , noFailureLayer , out , "No failure" , false);
219                                for (int srgIndex = 0 ; srgIndex < npNoFailure.getNumberOfSRGs() ; srgIndex ++)
220                                        printReport (npFailureStates.get(srgIndex) , npFailureStates.get(srgIndex).getNetworkLayer (layerIndex) , out , "" + srgIndex , false);
221                                out.append("</table>");
222                        }
223                }
224                
225                return out.toString();
226        }
227
228        private void printReport (NetPlan np , NetworkLayer layer , StringBuilder out , String rowTitle , boolean unicastDemands)
229        {
230                double totalOfferedTraffic = 0;
231                double totalBlockedTraffic = 0; 
232                double totalTrafficOfDemandsTraversingOversubscribedLinks = 0;
233                double totalTrafficOfDemandsWithExcessiveWorseCaseLatency = 0;
234                double totalBlockedConsideringUserDefinedExtraLimitations = 0; 
235                int numberOfDemandsWithoutBlocking = 0;
236                if (unicastDemands)
237                {
238                        for (Demand d : np.getDemands (layer))
239                        {
240                                totalOfferedTraffic += d.getOfferedTraffic();
241                                totalBlockedTraffic += d.getBlockedTraffic();
242                                final boolean travOversuscribedLink = d.isTraversingOversubscribedLinks();
243                                final boolean hasExcessiveLatency = (maximumE2ELatencyMs.getDouble() > 0) && (d.getWorseCasePropagationTimeInMs() > maximumE2ELatencyMs.getDouble());
244                                if (considerTrafficInOversubscribedLinksAsLost.getBoolean())
245                                        totalTrafficOfDemandsTraversingOversubscribedLinks += travOversuscribedLink? d.getOfferedTraffic() : 0;
246                                if (hasExcessiveLatency) 
247                                        totalTrafficOfDemandsWithExcessiveWorseCaseLatency += d.getOfferedTraffic();
248                                if (hasExcessiveLatency || (considerTrafficInOversubscribedLinksAsLost.getBoolean() && travOversuscribedLink)) 
249                                        totalBlockedConsideringUserDefinedExtraLimitations += d.getOfferedTraffic();
250                                else
251                                {
252                                        totalBlockedConsideringUserDefinedExtraLimitations += d.getBlockedTraffic();
253                                        if (d.getBlockedTraffic() < PRECISION_FACTOR) numberOfDemandsWithoutBlocking ++;
254                                }
255                        }
256                }
257                else
258                {
259                        for (MulticastDemand d : np.getMulticastDemands (layer))
260                        {
261                                totalOfferedTraffic += d.getOfferedTraffic();
262                                totalBlockedTraffic += d.getBlockedTraffic();
263                                final boolean travOversuscribedLink = d.isTraversingOversubscribedLinks();
264                                final boolean hasExcessiveLatency = (maximumE2ELatencyMs.getDouble() > 0) && (d.getWorseCasePropagationTimeInMs() > maximumE2ELatencyMs.getDouble());
265                                if (considerTrafficInOversubscribedLinksAsLost.getBoolean())
266                                        totalTrafficOfDemandsTraversingOversubscribedLinks += travOversuscribedLink? d.getOfferedTraffic() : 0;
267                                if (hasExcessiveLatency) 
268                                        totalTrafficOfDemandsWithExcessiveWorseCaseLatency += d.getOfferedTraffic();
269                                if (hasExcessiveLatency || (considerTrafficInOversubscribedLinksAsLost.getBoolean() && travOversuscribedLink)) 
270                                        totalBlockedConsideringUserDefinedExtraLimitations += d.getOfferedTraffic();
271                                else
272                                {
273                                        totalBlockedConsideringUserDefinedExtraLimitations += d.getBlockedTraffic();
274                                        if (d.getBlockedTraffic() < PRECISION_FACTOR) numberOfDemandsWithoutBlocking ++;
275                                }
276                        }
277                }
278
279                out.append("<tr><td> " + rowTitle + 
280                                "</td><td>" + valString(totalOfferedTraffic) + 
281                                "</td><td>" + valString(totalBlockedTraffic) + percentage(totalBlockedTraffic,totalOfferedTraffic) + 
282                                "</td><td> " + valString(totalTrafficOfDemandsTraversingOversubscribedLinks) + percentage(totalTrafficOfDemandsTraversingOversubscribedLinks,totalOfferedTraffic) + 
283                                "</td><td>" + valString(totalTrafficOfDemandsWithExcessiveWorseCaseLatency) + percentage(totalTrafficOfDemandsWithExcessiveWorseCaseLatency,totalOfferedTraffic)  + 
284                                "</td><td>" + valString(totalBlockedConsideringUserDefinedExtraLimitations) + percentage(totalBlockedConsideringUserDefinedExtraLimitations,totalOfferedTraffic) + 
285                                "</td><td>" + percentage(numberOfDemandsWithoutBlocking,unicastDemands? np.getNumberOfDemands (layer) : np.getNumberOfMulticastDemands (layer)) + "</td></tr>");
286        }
287
288        private String percentage (double val , double total) { double res = 100 * val/total; if (res < 1e-8) res = 0; return " (" + valString(res) + " %)"; }
289        private String percentage (int val , int total) { double res = 100 * ((double) val)/ ((double) total); if (res < 1e-8) res = 0; return " (" + valString(res) + " %)"; }
290        private String valString(double traffic) { return String.format ("%.3f" , traffic < PRECISION_FACTOR? 0 : traffic); }
291        
292}