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}