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