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}