blob: a072882a4e99447f40a7bddde031ee1563da8982 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00004import java.io.PrintWriter;
5import java.io.StringWriter;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.ArrayList;
7import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07008import java.util.Collections;
9import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000012import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000015import java.util.Random;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +000016import java.util.concurrent.ConcurrentLinkedQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.Executors;
18import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070028import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.util.OFMessageDamper;
Pankaj Berde38646d62013-06-21 11:34:04 -070030import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070031import net.onrc.onos.ofcontroller.core.INetMapStorage;
32import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
33import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
34import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
35import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
36import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070037import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070038import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070039import net.onrc.onos.ofcontroller.util.CallerId;
40import net.onrc.onos.ofcontroller.util.DataPath;
41import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
42import net.onrc.onos.ofcontroller.util.Dpid;
43import net.onrc.onos.ofcontroller.util.FlowEntry;
44import net.onrc.onos.ofcontroller.util.FlowEntryAction;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070045import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
46import net.onrc.onos.ofcontroller.util.FlowEntryActions;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.FlowEntryId;
48import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
49import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
50import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
51import net.onrc.onos.ofcontroller.util.FlowId;
52import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070053import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070054import net.onrc.onos.ofcontroller.util.IPv4Net;
55import net.onrc.onos.ofcontroller.util.Port;
56import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057
58import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
60import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070061import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062import org.openflow.protocol.OFType;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070063import org.openflow.protocol.action.*;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080064import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
Jonathan Hartf5315fb2013-04-05 11:41:56 -070067
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070068public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080069
Toshio Koide9fe1cb22013-06-13 13:51:11 -070070 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080071
72 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070073 protected volatile IFloodlightProviderService floodlightProvider;
74 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070075 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080076
77 protected OFMessageDamper messageDamper;
78
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070079 //
80 // TODO: Values copied from elsewhere (class LearningSwitch).
81 // The local copy should go away!
82 //
83 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
84 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
85 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
86 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
87 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080088
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000089 // Flow Entry ID generation state
90 private static Random randomGenerator = new Random();
91 private static int nextFlowEntryIdPrefix = 0;
92 private static int nextFlowEntryIdSuffix = 0;
93 private static long nextFlowEntryId = 0;
94
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070095 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070096 private static long measurementFlowId = 100000;
97 private static String measurementFlowIdStr = "0x186a0"; // 100000
98 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070099 //
100 private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700101 private long measurementStartTimeProcessingPaths = 0;
102 private long measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000103 Map<Long, ?> measurementShortestPathTopo = null;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000104 private String measurementPerFlowStr = new String();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700105
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800106 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800107 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
108
109 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700110 private ScheduledExecutorService mapReaderScheduler;
111 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700112
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700113 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800114 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700115 try {
116 runImpl();
117 } catch (Exception e) {
118 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700119 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700120 return;
121 }
122 }
123
124 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700125 long startTime = System.nanoTime();
126 int counterAllFlowEntries = 0;
127 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700128
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800129 if (floodlightProvider == null) {
130 log.debug("FloodlightProvider service not found!");
131 return;
132 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 Map<Long, IOFSwitch> mySwitches =
134 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700135 LinkedList<IFlowEntry> addFlowEntries =
136 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000137 LinkedList<IFlowEntry> deleteFlowEntries =
138 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700139
140 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700141 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700142 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700143 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700144 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000145 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700146 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700147 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700148 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000149
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000150 String dpidStr = flowEntryObj.getSwitchDpid();
151 if (dpidStr == null)
152 continue;
153 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800154 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000155 if (mySwitch == null)
156 continue; // Ignore the entry: not my switch
157
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700158 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700159 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700160 if (flowObj == null)
161 continue; // Should NOT happen
162 if (flowObj.getFlowId() == null)
163 continue; // Invalid entry
164
165 //
166 // NOTE: For now we process the DELETE before the ADD
167 // to cover the more common scenario.
168 // TODO: This is error prone and needs to be fixed!
169 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000170 String userState = flowEntryObj.getUserState();
171 if (userState == null)
172 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700173 if (userState.equals("FE_USER_DELETE")) {
174 // An entry that needs to be deleted.
175 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700176 installFlowEntry(mySwitch, flowObj, flowEntryObj);
177 } else {
178 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700179 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700180 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700181 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700182 // TODO: Commented-out for now
183 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700184 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700185 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700186 processed_measurement_flow = true;
187 }
188 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700189 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700190 }
191
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700192 //
193 // Process the Flow Entries that need to be added
194 //
195 for (IFlowEntry flowEntryObj : addFlowEntries) {
196 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700197 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700198 if (flowObj == null)
199 continue; // Should NOT happen
200 if (flowObj.getFlowId() == null)
201 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700202
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700203 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700204 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000205 if (mySwitch == null)
206 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700207 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800208 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000209
210 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000211 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700212 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000213 //
214 // TODO: We should use the OpenFlow Barrier mechanism
215 // to check for errors, and delete the Flow Entries after the
216 // Barrier message is received.
217 //
218 while (! deleteFlowEntries.isEmpty()) {
219 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
220 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700221 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000222 if (flowObj == null) {
223 log.debug("Did not find FlowPath to be deleted");
224 continue;
225 }
226 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700227 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000228 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700229
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700230 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700231
232 if (processed_measurement_flow) {
233 long estimatedTime =
234 System.nanoTime() - modifiedMeasurementFlowTime;
235 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
236 (double)estimatedTime / 1000000000 + " sec";
237 log.debug(logMsg);
238 }
239
240 long estimatedTime = System.nanoTime() - startTime;
241 double rate = 0.0;
242 if (estimatedTime > 0)
243 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
244 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
245 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
246 counterMyNotUpdatedFlowEntries + " in " +
247 (double)estimatedTime / 1000000000 + " sec: " +
248 rate + " paths/s";
249 log.debug(logMsg);
250 }
251 };
252
253 final Runnable shortestPathReconcile = new Runnable() {
254 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700255 try {
256 runImpl();
257 } catch (Exception e) {
258 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700259 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700260 return;
261 }
262 }
263
264 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700265 long startTime = System.nanoTime();
266 int counterAllFlowPaths = 0;
267 int counterMyFlowPaths = 0;
268
269 if (floodlightProvider == null) {
270 log.debug("FloodlightProvider service not found!");
271 return;
272 }
273 Map<Long, IOFSwitch> mySwitches =
274 floodlightProvider.getSwitches();
275 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
276
277 boolean processed_measurement_flow = false;
278
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700279 //
280 // Fetch and recompute the Shortest Path for those
281 // Flow Paths this controller is responsible for.
282 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000283 Map<Long, ?> shortestPathTopo =
284 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700285 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700286 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700287 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700288 if (flowPathObj == null)
289 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700290
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700291 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000292 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700293 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700294 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700295 //
296 // Use the source DPID as a heuristic to decide
297 // which controller is responsible for maintaining the
298 // shortest path.
299 // NOTE: This heuristic is error-prone: if the switch
300 // goes away and no controller is responsible for that
301 // switch, then the original Flow Path is not cleaned-up
302 //
303 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
304 if (mySwitch == null)
305 continue; // Ignore: not my responsibility
306
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700307 // Test the Data Path Summary string
308 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
309 if (dataPathSummaryStr == null)
310 continue; // Could be invalid entry?
311 if (dataPathSummaryStr.isEmpty())
312 continue; // No need to maintain this flow
313
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000314 //
315 // Test whether we need to complete the Flow cleanup,
316 // if the Flow has been deleted by the user.
317 //
318 String flowUserState = flowPathObj.getUserState();
319 if ((flowUserState != null)
320 && flowUserState.equals("FE_USER_DELETE")) {
321 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
322 boolean empty = true; // TODO: an ugly hack
323 for (IFlowEntry flowEntryObj : flowEntries) {
324 empty = false;
325 break;
326 }
327 if (empty)
328 deleteFlows.add(flowPathObj);
329 }
330
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000331 // Fetch the fields needed to recompute the shortest path
332 Short srcPortShort = flowPathObj.getSrcPort();
333 String dstDpidStr = flowPathObj.getDstSwitch();
334 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700335 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000336 if ((srcPortShort == null) ||
337 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700338 (dstPortShort == null) ||
339 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000340 continue;
341 }
342
343 Port srcPort = new Port(srcPortShort);
344 Dpid dstDpid = new Dpid(dstDpidStr);
345 Port dstPort = new Port(dstPortShort);
346 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
347 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700348 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000349
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700350 counterMyFlowPaths++;
351
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700352 //
353 // NOTE: Using here the regular getShortestPath() method
354 // won't work here, because that method calls internally
355 // "conn.endTx(Transaction.COMMIT)", and that will
356 // invalidate all handlers to the Titan database.
357 // If we want to experiment with calling here
358 // getShortestPath(), we need to refactor that code
359 // to avoid closing the transaction.
360 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700361 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000362 topoRouteService.getTopoShortestPath(shortestPathTopo,
363 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700364 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000365 if (dataPath == null) {
366 // We need the DataPath to compare the paths
367 dataPath = new DataPath();
368 dataPath.setSrcPort(srcSwitchPort);
369 dataPath.setDstPort(dstSwitchPort);
370 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700371 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000372
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700373 String newDataPathSummaryStr = dataPath.dataPathSummary();
374 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
375 continue; // Nothing changed
376
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700377 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700378 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000379
380 //
381 // Delete all leftover Flows marked for deletion from the
382 // Network MAP.
383 //
384 while (! deleteFlows.isEmpty()) {
385 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700386 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000387 }
388
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000389 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700390
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700391 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700392
393 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700394 long estimatedTime =
395 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700396 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
397 (double)estimatedTime / 1000000000 + " sec";
398 log.debug(logMsg);
399 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700400
401 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700402 double rate = 0.0;
403 if (estimatedTime > 0)
404 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700405 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700406 counterAllFlowPaths + " MyFlowPaths: " +
407 counterMyFlowPaths + " in " +
408 (double)estimatedTime / 1000000000 + " sec: " +
409 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700410 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800411 }
412 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700413
Jonathan Hart50a94982013-04-10 14:49:51 -0700414 //final ScheduledFuture<?> mapReaderHandle =
415 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800416
Jonathan Hart50a94982013-04-10 14:49:51 -0700417 //final ScheduledFuture<?> shortestPathReconcileHandle =
418 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700419
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800420 @Override
421 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700422 op = new GraphDBOperation(conf);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700423 topoRouteService = new TopoRouteService(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800424 }
425
426 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700427 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800428 }
429
430 @Override
431 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700432 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800433 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800434
435 @Override
436 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
437 Collection<Class<? extends IFloodlightService>> l =
438 new ArrayList<Class<? extends IFloodlightService>>();
439 l.add(IFlowService.class);
440 return l;
441 }
442
443 @Override
444 public Map<Class<? extends IFloodlightService>, IFloodlightService>
445 getServiceImpls() {
446 Map<Class<? extends IFloodlightService>,
447 IFloodlightService> m =
448 new HashMap<Class<? extends IFloodlightService>,
449 IFloodlightService>();
450 m.put(IFlowService.class, this);
451 return m;
452 }
453
454 @Override
455 public Collection<Class<? extends IFloodlightService>>
456 getModuleDependencies() {
457 Collection<Class<? extends IFloodlightService>> l =
458 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800459 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800460 l.add(IRestApiService.class);
461 return l;
462 }
463
464 @Override
465 public void init(FloodlightModuleContext context)
466 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700467 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800468 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800469 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800470 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
471 EnumSet.of(OFType.FLOW_MOD),
472 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700473
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800474 // TODO: An ugly hack!
475 String conf = "/tmp/cassandra.titan";
476 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700477
478 mapReaderScheduler = Executors.newScheduledThreadPool(1);
479 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800480 }
481
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700482 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000483 //
484 // Generate the next Flow Entry ID.
485 // NOTE: For now, the higher 32 bits are random, and
486 // the lower 32 bits are sequential.
487 // In the future, we need a better allocation mechanism.
488 //
489 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
490 nextFlowEntryIdPrefix = randomGenerator.nextInt();
491 nextFlowEntryIdSuffix = 0;
492 } else {
493 nextFlowEntryIdSuffix++;
494 }
495 long result = (long)nextFlowEntryIdPrefix << 32;
496 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
497 return result;
498 }
499
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800500 @Override
501 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700502 restApi.addRestletRoutable(new FlowWebRoutable());
503
504 // Initialize the Flow Entry ID generator
505 nextFlowEntryIdPrefix = randomGenerator.nextInt();
506
507 mapReaderScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200508 mapReader, 3, 3, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700509 shortestPathReconcileScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200510 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800511 }
512
513 /**
514 * Add a flow.
515 *
516 * Internally, ONOS will automatically register the installer for
517 * receiving Flow Path Notifications for that path.
518 *
519 * @param flowPath the Flow Path to install.
520 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700521 * @param dataPathSummaryStr the data path summary string if the added
522 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800523 * @return true on success, otherwise false.
524 */
525 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700526 public boolean addFlow(FlowPath flowPath, FlowId flowId,
527 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700528 /*
529 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700530 if (flowPath.flowId().value() == measurementFlowId) {
531 modifiedMeasurementFlowTime = System.nanoTime();
532 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700533 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800534
535 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000536 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800537 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700538 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800539 != null) {
540 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
541 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000542 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800543 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700544 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800545 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
546 flowPath.flowId().toString());
547 }
548 } catch (Exception e) {
549 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700550 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000551
552 StringWriter sw = new StringWriter();
553 e.printStackTrace(new PrintWriter(sw));
554 String stacktrace = sw.toString();
555
556 log.error(":addFlow FlowId:{} failed: {}",
557 flowPath.flowId().toString(),
558 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800559 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700560 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000561 log.error(":addFlow FlowId:{} failed: Flow object not created",
562 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700563 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800564 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700565 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800566
567 //
568 // Set the Flow key:
569 // - flowId
570 //
571 flowObj.setFlowId(flowPath.flowId().toString());
572 flowObj.setType("flow");
573
574 //
575 // Set the Flow attributes:
576 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700577 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800578 // - flowPath.dataPath().srcPort()
579 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700580 // - flowPath.matchSrcMac()
581 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700582 // - flowPath.matchEthernetFrameType()
583 // - flowPath.matchVlanId()
584 // - flowPath.matchVlanPriority()
585 // - flowPath.matchSrcIPv4Net()
586 // - flowPath.matchDstIPv4Net()
587 // - flowPath.matchIpProto()
588 // - flowPath.matchIpToS()
589 // - flowPath.matchSrcTcpUdpPort()
590 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700591 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800592 //
593 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700594 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800595 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
596 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
597 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
598 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700599 if (flowPath.flowEntryMatch().matchSrcMac()) {
600 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
601 }
602 if (flowPath.flowEntryMatch().matchDstMac()) {
603 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
604 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700605 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
606 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
607 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700608 if (flowPath.flowEntryMatch().matchVlanId()) {
609 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
610 }
611 if (flowPath.flowEntryMatch().matchVlanPriority()) {
612 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
613 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700614 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
615 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
616 }
617 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
618 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
619 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700620 if (flowPath.flowEntryMatch().matchIpProto()) {
621 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700622 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700623 if (flowPath.flowEntryMatch().matchIpToS()) {
624 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
625 }
626 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
627 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
628 }
629 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
630 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700631 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700632 if (! flowPath.flowEntryActions().actions().isEmpty()) {
633 flowObj.setActions(flowPath.flowEntryActions().toString());
634 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800635
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700636 if (dataPathSummaryStr != null) {
637 flowObj.setDataPathSummary(dataPathSummaryStr);
638 } else {
639 flowObj.setDataPathSummary("");
640 }
641
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000642 if (found)
643 flowObj.setUserState("FE_USER_MODIFY");
644 else
645 flowObj.setUserState("FE_USER_ADD");
646
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800647 // Flow edges:
648 // HeadFE
649
650
651 //
652 // Flow Entries:
653 // flowPath.dataPath().flowEntries()
654 //
655 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700656 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700657 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800658 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700659 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800660 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700661 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800662
663 //
664 // TODO: We need a proper Flow ID allocation mechanism.
665 //
666 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700667
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800668 return true;
669 }
670
671 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700672 * Add a flow entry to the Network MAP.
673 *
674 * @param flowObj the corresponding Flow Path object for the Flow Entry.
675 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700676 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700677 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700678 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700679 // Flow edges
680 // HeadFE (TODO)
681
682 //
683 // Assign the FlowEntry ID.
684 //
685 if ((flowEntry.flowEntryId() == null) ||
686 (flowEntry.flowEntryId().value() == 0)) {
687 long id = getNextFlowEntryId();
688 flowEntry.setFlowEntryId(new FlowEntryId(id));
689 }
690
691 IFlowEntry flowEntryObj = null;
692 boolean found = false;
693 try {
694 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700695 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700696 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
697 flowEntry.flowEntryId().toString());
698 found = true;
699 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700700 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700701 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
702 flowEntry.flowEntryId().toString());
703 }
704 } catch (Exception e) {
705 log.error(":addFlow FlowEntryId:{} failed",
706 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700707 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700708 }
709 if (flowEntryObj == null) {
710 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
711 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700712 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700713 }
714
715 //
716 // Set the Flow Entry key:
717 // - flowEntry.flowEntryId()
718 //
719 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
720 flowEntryObj.setType("flow_entry");
721
722 //
723 // Set the Flow Entry Edges and attributes:
724 // - Switch edge
725 // - InPort edge
726 // - OutPort edge
727 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700728 // - flowEntry.dpid()
729 // - flowEntry.flowEntryUserState()
730 // - flowEntry.flowEntrySwitchState()
731 // - flowEntry.flowEntryErrorState()
732 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700733 // - flowEntry.matchSrcMac()
734 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700735 // - flowEntry.matchEthernetFrameType()
736 // - flowEntry.matchVlanId()
737 // - flowEntry.matchVlanPriority()
738 // - flowEntry.matchSrcIPv4Net()
739 // - flowEntry.matchDstIPv4Net()
740 // - flowEntry.matchIpProto()
741 // - flowEntry.matchIpToS()
742 // - flowEntry.matchSrcTcpUdpPort()
743 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700744 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700745 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700746 //
747 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700748 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700749 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
750 flowEntryObj.setSwitch(sw);
751 if (flowEntry.flowEntryMatch().matchInPort()) {
752 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700753 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700754 flowEntry.flowEntryMatch().inPort().value());
755 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
756 flowEntryObj.setInPort(inport);
757 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700758 if (flowEntry.flowEntryMatch().matchSrcMac()) {
759 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
760 }
761 if (flowEntry.flowEntryMatch().matchDstMac()) {
762 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
763 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700764 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
765 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
766 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700767 if (flowEntry.flowEntryMatch().matchVlanId()) {
768 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
769 }
770 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
771 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
772 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700773 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
774 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
775 }
776 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
777 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
778 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700779 if (flowEntry.flowEntryMatch().matchIpProto()) {
780 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700781 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700782 if (flowEntry.flowEntryMatch().matchIpToS()) {
783 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
784 }
785 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
786 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
787 }
788 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
789 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700790 }
791
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700792 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700793 if (fa.actionOutput() != null) {
794 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700795 op.searchPort(flowEntry.dpid().toString(),
796 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700797 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700798 flowEntryObj.setOutPort(outport);
799 }
800 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700801 if (! flowEntry.flowEntryActions().isEmpty()) {
802 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
803 }
804
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700805 // TODO: Hacks with hard-coded state names!
806 if (found)
807 flowEntryObj.setUserState("FE_USER_MODIFY");
808 else
809 flowEntryObj.setUserState("FE_USER_ADD");
810 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
811 //
812 // TODO: Take care of the FlowEntryErrorState.
813 //
814
815 // Flow Entries edges:
816 // Flow
817 // NextFE (TODO)
818 if (! found) {
819 flowObj.addFlowEntry(flowEntryObj);
820 flowEntryObj.setFlow(flowObj);
821 }
822
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700823 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700824 }
825
826 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000827 * Delete all previously added flows.
828 *
829 * @return true on success, otherwise false.
830 */
831 @Override
832 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000833 List<Thread> threads = new LinkedList<Thread>();
834 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
835 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000836
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000837 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700838 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000839 for (IFlowPath flowPathObj : allFlowPaths) {
840 if (flowPathObj == null)
841 continue;
842 String flowIdStr = flowPathObj.getFlowId();
843 if (flowIdStr == null)
844 continue;
845 FlowId flowId = new FlowId(flowIdStr);
846 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000847 }
848
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000849 // Delete all flows one-by-one
850 for (FlowId flowId : concurrentAllFlowIds)
851 deleteFlow(flowId);
852
853 /*
854 * TODO: A faster mechanism to delete the Flow Paths by using
855 * a number of threads. Commented-out for now.
856 */
857 /*
858 //
859 // Create the threads to delete the Flow Paths
860 //
861 for (int i = 0; i < 10; i++) {
862 Thread thread = new Thread(new Runnable() {
863 @Override
864 public void run() {
865 while (true) {
866 FlowId flowId = concurrentAllFlowIds.poll();
867 if (flowId == null)
868 return;
869 deleteFlow(flowId);
870 }
871 }}, "Delete All Flow Paths");
872 threads.add(thread);
873 }
874
875 // Start processing
876 for (Thread thread : threads) {
877 thread.start();
878 }
879
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000880 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000881 for (Thread thread : threads) {
882 try {
883 thread.join();
884 } catch (InterruptedException e) {
885 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
886 }
887 }
888 */
889
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000890 return true;
891 }
892
893 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800894 * Delete a previously added flow.
895 *
896 * @param flowId the Flow ID of the flow to delete.
897 * @return true on success, otherwise false.
898 */
899 @Override
900 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700901 /*
902 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700903 if (flowId.value() == measurementFlowId) {
904 modifiedMeasurementFlowTime = System.nanoTime();
905 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700906 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700907
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800908 IFlowPath flowObj = null;
909 //
910 // We just mark the entries for deletion,
911 // and let the switches remove each individual entry after
912 // it has been removed from the switches.
913 //
914 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700915 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800916 != null) {
917 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
918 flowId.toString());
919 } else {
920 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
921 flowId.toString());
922 }
923 } catch (Exception e) {
924 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700925 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800926 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
927 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700928 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700929 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800930 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700931 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800932
933 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000934 // Find and mark for deletion all Flow Entries,
935 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800936 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000937 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800938 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
939 boolean empty = true; // TODO: an ugly hack
940 for (IFlowEntry flowEntryObj : flowEntries) {
941 empty = false;
942 // flowObj.removeFlowEntry(flowEntryObj);
943 // conn.utils().removeFlowEntry(conn, flowEntryObj);
944 flowEntryObj.setUserState("FE_USER_DELETE");
945 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
946 }
947 // Remove from the database empty flows
948 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700949 op.removeFlowPath(flowObj);
950 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800951
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800952 return true;
953 }
954
955 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000956 * Clear the state for all previously added flows.
957 *
958 * @return true on success, otherwise false.
959 */
960 @Override
961 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000962 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000963
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000964 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700965 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000966 for (IFlowPath flowPathObj : allFlowPaths) {
967 if (flowPathObj == null)
968 continue;
969 String flowIdStr = flowPathObj.getFlowId();
970 if (flowIdStr == null)
971 continue;
972 FlowId flowId = new FlowId(flowIdStr);
973 allFlowIds.add(flowId);
974 }
975
976 // Clear all flows one-by-one
977 for (FlowId flowId : allFlowIds) {
978 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000979 }
980
981 return true;
982 }
983
984 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700985 * Clear the state for a previously added flow.
986 *
987 * @param flowId the Flow ID of the flow to clear.
988 * @return true on success, otherwise false.
989 */
990 @Override
991 public boolean clearFlow(FlowId flowId) {
992 IFlowPath flowObj = null;
993 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700994 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700995 != null) {
996 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
997 flowId.toString());
998 } else {
999 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1000 flowId.toString());
1001 }
1002 } catch (Exception e) {
1003 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001004 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001005 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1006 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001007 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001008 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001009 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001010 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001011
1012 //
1013 // Remove all Flow Entries
1014 //
1015 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1016 for (IFlowEntry flowEntryObj : flowEntries) {
1017 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001018 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001019 }
1020 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001021 op.removeFlowPath(flowObj);
1022 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001023
1024 return true;
1025 }
1026
1027 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001028 * Get a previously added flow.
1029 *
1030 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001031 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001032 */
1033 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001034 public FlowPath getFlow(FlowId flowId) {
1035 IFlowPath flowObj = null;
1036 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001037 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001038 != null) {
1039 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1040 flowId.toString());
1041 } else {
1042 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1043 flowId.toString());
1044 }
1045 } catch (Exception e) {
1046 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001047 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001048 log.error(":getFlow FlowId:{} failed", flowId.toString());
1049 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001050 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001051 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001052 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001053 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001054
1055 //
1056 // Extract the Flow state
1057 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001058 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001059 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001060
1061 return flowPath;
1062 }
1063
1064 /**
1065 * Get all previously added flows by a specific installer for a given
1066 * data path endpoints.
1067 *
1068 * @param installerId the Caller ID of the installer of the flow to get.
1069 * @param dataPathEndpoints the data path endpoints of the flow to get.
1070 * @return the Flow Paths if found, otherwise null.
1071 */
1072 @Override
1073 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1074 DataPathEndpoints dataPathEndpoints) {
1075 //
1076 // TODO: The implementation below is not optimal:
1077 // We fetch all flows, and then return only the subset that match
1078 // the query conditions.
1079 // We should use the appropriate Titan/Gremlin query to filter-out
1080 // the flows as appropriate.
1081 //
1082 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001083 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001084
1085 if (allFlows == null) {
1086 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001087 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001088 }
1089
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001090 for (FlowPath flow : allFlows) {
1091 //
1092 // TODO: String-based comparison is sub-optimal.
1093 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001094 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001095 //
1096 if (! flow.installerId().toString().equals(installerId.toString()))
1097 continue;
1098 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1099 continue;
1100 }
1101 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1102 continue;
1103 }
1104 flowPaths.add(flow);
1105 }
1106
1107 if (flowPaths.isEmpty()) {
1108 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001109 } else {
1110 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1111 }
1112
1113 return flowPaths;
1114 }
1115
1116 /**
1117 * Get all installed flows by all installers for given data path endpoints.
1118 *
1119 * @param dataPathEndpoints the data path endpoints of the flows to get.
1120 * @return the Flow Paths if found, otherwise null.
1121 */
1122 @Override
1123 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1124 //
1125 // TODO: The implementation below is not optimal:
1126 // We fetch all flows, and then return only the subset that match
1127 // the query conditions.
1128 // We should use the appropriate Titan/Gremlin query to filter-out
1129 // the flows as appropriate.
1130 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001131 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1132 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001133
1134 if (allFlows == null) {
1135 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001136 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001137 }
1138
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001139 for (FlowPath flow : allFlows) {
1140 //
1141 // TODO: String-based comparison is sub-optimal.
1142 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001143 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001144 //
1145 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1146 continue;
1147 }
1148 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1149 continue;
1150 }
1151 flowPaths.add(flow);
1152 }
1153
1154 if (flowPaths.isEmpty()) {
1155 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001156 } else {
1157 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1158 }
1159
1160 return flowPaths;
1161 }
1162
1163 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001164 * Get summary of all installed flows by all installers in a given range
1165 *
1166 * @param flowId the data path endpoints of the flows to get.
1167 * @param maxFlows: the maximum number of flows to be returned
1168 * @return the Flow Paths if found, otherwise null.
1169 */
1170 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001171 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001172
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001173 // TODO: The implementation below is not optimal:
1174 // We fetch all flows, and then return only the subset that match
1175 // the query conditions.
1176 // We should use the appropriate Titan/Gremlin query to filter-out
1177 // the flows as appropriate.
1178 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001179 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001180
Jonathan Hart01f2d272013-04-04 20:03:46 -07001181 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1182
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001183 Collections.sort(flowPathsWithoutFlowEntries,
1184 new Comparator<IFlowPath>(){
1185 @Override
1186 public int compare(IFlowPath first, IFlowPath second) {
1187 // TODO Auto-generated method stub
1188 long result = new FlowId(first.getFlowId()).value()
1189 - new FlowId(second.getFlowId()).value();
1190 if (result > 0) return 1;
1191 else if (result < 0) return -1;
1192 else return 0;
1193 }
1194 }
1195 );
1196
Jonathan Hart01f2d272013-04-04 20:03:46 -07001197 return flowPathsWithoutFlowEntries;
1198
1199 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001200 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001201
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001202 if (allFlows == null) {
1203 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001204 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001205 }
1206
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001207 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001208
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001209 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001210 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001211
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001212 // start from desired flowId
1213 if (flow.flowId().value() < flowId.value()) {
1214 continue;
1215 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001216
1217 // Summarize by making null flow entry fields that are not relevant to report
1218 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1219 flowEntry.setFlowEntryActions(null);
1220 flowEntry.setFlowEntryMatch(null);
1221 }
1222
1223 flowPaths.add(flow);
1224 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1225 break;
1226 }
1227 }
1228
1229 if (flowPaths.isEmpty()) {
1230 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001231 } else {
1232 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1233 }
1234
1235 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001236 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001237 }
1238
1239 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001240 * Get all installed flows by all installers.
1241 *
1242 * @return the Flow Paths if found, otherwise null.
1243 */
1244 @Override
1245 public ArrayList<FlowPath> getAllFlows() {
1246 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001247 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001248
1249 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001250 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001251 log.debug("Get all FlowPaths: found FlowPaths");
1252 } else {
1253 log.debug("Get all FlowPaths: no FlowPaths found");
1254 }
1255 } catch (Exception e) {
1256 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001257 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001258 log.error(":getAllFlowPaths failed");
1259 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001260 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001261 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001262 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001263 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001264
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001265 for (IFlowPath flowObj : flowPathsObj) {
1266 //
1267 // Extract the Flow state
1268 //
1269 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001270 if (flowPath != null)
1271 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001272 }
1273
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001274 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001275
1276 return flowPaths;
1277 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001278
1279 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1280 Iterable<IFlowPath> flowPathsObj = null;
1281 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1282 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1283
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001284 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001285
Jonathan Hart01f2d272013-04-04 20:03:46 -07001286 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001287 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001288 log.debug("Get all FlowPaths: found FlowPaths");
1289 } else {
1290 log.debug("Get all FlowPaths: no FlowPaths found");
1291 }
1292 } catch (Exception e) {
1293 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001294 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001295 log.error(":getAllFlowPaths failed");
1296 }
1297 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1298 return new ArrayList<IFlowPath>(); // No Flows found
1299 }
1300
1301 for (IFlowPath flowObj : flowPathsObj){
1302 flowPathsObjArray.add(flowObj);
1303 }
1304 /*
1305 for (IFlowPath flowObj : flowPathsObj) {
1306 //
1307 // Extract the Flow state
1308 //
1309 FlowPath flowPath = extractFlowPath(flowObj);
1310 if (flowPath != null)
1311 flowPaths.add(flowPath);
1312 }
1313 */
1314
1315 //conn.endTx(Transaction.COMMIT);
1316
1317 return flowPathsObjArray;
1318 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001319
1320 /**
1321 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1322 *
1323 * @param flowObj the object to extract the Flow Path State from.
1324 * @return the extracted Flow Path State.
1325 */
1326 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001327 //
1328 // Extract the Flow state
1329 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001330 String flowIdStr = flowObj.getFlowId();
1331 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001332 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001333 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001334 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001335 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001336 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001337
1338 if ((flowIdStr == null) ||
1339 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001340 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001341 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001342 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001343 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001344 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001345 // TODO: A work-around, becauuse of some bogus database objects
1346 return null;
1347 }
1348
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001349 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001350 flowPath.setFlowId(new FlowId(flowIdStr));
1351 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001352 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001353 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001354 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001355 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001356 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001357 //
1358 // Extract the match conditions common for all Flow Entries
1359 //
1360 {
1361 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001362 String matchSrcMac = flowObj.getMatchSrcMac();
1363 if (matchSrcMac != null)
1364 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1365 String matchDstMac = flowObj.getMatchDstMac();
1366 if (matchDstMac != null)
1367 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001368 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1369 if (matchEthernetFrameType != null)
1370 match.enableEthernetFrameType(matchEthernetFrameType);
1371 Short matchVlanId = flowObj.getMatchVlanId();
1372 if (matchVlanId != null)
1373 match.enableVlanId(matchVlanId);
1374 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1375 if (matchVlanPriority != null)
1376 match.enableVlanPriority(matchVlanPriority);
1377 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1378 if (matchSrcIPv4Net != null)
1379 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1380 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1381 if (matchDstIPv4Net != null)
1382 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1383 Byte matchIpProto = flowObj.getMatchIpProto();
1384 if (matchIpProto != null)
1385 match.enableIpProto(matchIpProto);
1386 Byte matchIpToS = flowObj.getMatchIpToS();
1387 if (matchIpToS != null)
1388 match.enableIpToS(matchIpToS);
1389 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1390 if (matchSrcTcpUdpPort != null)
1391 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1392 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1393 if (matchDstTcpUdpPort != null)
1394 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1395
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001396 flowPath.setFlowEntryMatch(match);
1397 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001398 //
1399 // Extract the actions for the first Flow Entry
1400 //
1401 {
1402 String actionsStr = flowObj.getActions();
1403 if (actionsStr != null) {
1404 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1405 flowPath.setFlowEntryActions(flowEntryActions);
1406 }
1407 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001408
1409 //
1410 // Extract all Flow Entries
1411 //
1412 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1413 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001414 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1415 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001416 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001417 flowPath.dataPath().flowEntries().add(flowEntry);
1418 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001419
1420 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001421 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001422
1423 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001424 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1425 *
1426 * @param flowEntryObj the object to extract the Flow Entry State from.
1427 * @return the extracted Flow Entry State.
1428 */
1429 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1430 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1431 String switchDpidStr = flowEntryObj.getSwitchDpid();
1432 String userState = flowEntryObj.getUserState();
1433 String switchState = flowEntryObj.getSwitchState();
1434
1435 if ((flowEntryIdStr == null) ||
1436 (switchDpidStr == null) ||
1437 (userState == null) ||
1438 (switchState == null)) {
1439 // TODO: A work-around, becauuse of some bogus database objects
1440 return null;
1441 }
1442
1443 FlowEntry flowEntry = new FlowEntry();
1444 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1445 flowEntry.setDpid(new Dpid(switchDpidStr));
1446
1447 //
1448 // Extract the match conditions
1449 //
1450 FlowEntryMatch match = new FlowEntryMatch();
1451 Short matchInPort = flowEntryObj.getMatchInPort();
1452 if (matchInPort != null)
1453 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001454 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1455 if (matchSrcMac != null)
1456 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1457 String matchDstMac = flowEntryObj.getMatchDstMac();
1458 if (matchDstMac != null)
1459 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001460 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1461 if (matchEthernetFrameType != null)
1462 match.enableEthernetFrameType(matchEthernetFrameType);
1463 Short matchVlanId = flowEntryObj.getMatchVlanId();
1464 if (matchVlanId != null)
1465 match.enableVlanId(matchVlanId);
1466 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1467 if (matchVlanPriority != null)
1468 match.enableVlanPriority(matchVlanPriority);
1469 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1470 if (matchSrcIPv4Net != null)
1471 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1472 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1473 if (matchDstIPv4Net != null)
1474 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1475 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1476 if (matchIpProto != null)
1477 match.enableIpProto(matchIpProto);
1478 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1479 if (matchIpToS != null)
1480 match.enableIpToS(matchIpToS);
1481 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1482 if (matchSrcTcpUdpPort != null)
1483 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1484 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1485 if (matchDstTcpUdpPort != null)
1486 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001487 flowEntry.setFlowEntryMatch(match);
1488
1489 //
1490 // Extract the actions
1491 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001492 FlowEntryActions actions = new FlowEntryActions();
1493 String actionsStr = flowEntryObj.getActions();
1494 if (actionsStr != null)
1495 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001496 flowEntry.setFlowEntryActions(actions);
1497 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1498 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1499 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001500 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001501 //
1502 return flowEntry;
1503 }
1504
1505 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001506 * Add and maintain a shortest-path flow.
1507 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001508 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001509 *
1510 * @param flowPath the Flow Path with the endpoints and the match
1511 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001512 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001513 */
1514 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001515 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001516 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001517 // Don't do the shortest path computation here.
1518 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001519 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001520
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001521 // We need the DataPath to populate the Network MAP
1522 DataPath dataPath = new DataPath();
1523 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1524 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001525
1526 //
1527 // Prepare the computed Flow Path
1528 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001529 FlowPath computedFlowPath = new FlowPath();
1530 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1531 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001532 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001533 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001534 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001535 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001536
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001537 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001538 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001539 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001540 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001541
1542 // TODO: Mark the flow for maintenance purpose
1543
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001544 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001545 }
1546
1547 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001548 * Reconcile a flow.
1549 *
1550 * @param flowObj the flow that needs to be reconciliated.
1551 * @param newDataPath the new data path to use.
1552 * @return true on success, otherwise false.
1553 */
1554 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1555 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1556
1557 //
1558 // Set the incoming port matching and the outgoing port output
1559 // actions for each flow entry.
1560 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001561 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001562 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1563 // Set the incoming port matching
1564 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1565 flowEntry.setFlowEntryMatch(flowEntryMatch);
1566 flowEntryMatch.enableInPort(flowEntry.inPort());
1567
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001568 //
1569 // Set the actions
1570 //
1571 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1572 //
1573 // If the first Flow Entry, copy the Flow Path actions to it
1574 //
1575 if (idx == 0) {
1576 String actionsStr = flowObj.getActions();
1577 if (actionsStr != null) {
1578 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1579 for (FlowEntryAction action : flowActions.actions())
1580 flowEntryActions.addAction(action);
1581 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001582 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001583 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001584 //
1585 // Add the outgoing port output action
1586 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001587 FlowEntryAction flowEntryAction = new FlowEntryAction();
1588 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001589 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001590 }
1591
1592 //
1593 // Remove the old Flow Entries, and add the new Flow Entries
1594 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001595 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1596 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1597 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001598 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001599 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001600 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001601 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001602 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001603 }
1604
1605 //
1606 // Set the Data Path Summary
1607 //
1608 String dataPathSummaryStr = newDataPath.dataPathSummary();
1609 flowObj.setDataPathSummary(dataPathSummaryStr);
1610
1611 return true;
1612 }
1613
1614 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001615 * Reconcile all flows in a set.
1616 *
1617 * @param flowObjSet the set of flows that need to be reconciliated.
1618 */
1619 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1620 if (! flowObjSet.iterator().hasNext())
1621 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001622 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001623 }
1624
1625 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001626 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001627 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001628 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001629 * @param flowObj the flow path object for the flow entry to install.
1630 * @param flowEntryObj the flow entry object to install.
1631 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001632 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001633 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1634 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001635 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1636 if (flowEntryIdStr == null)
1637 return false;
1638 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001639 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001640 if (userState == null)
1641 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001642
1643 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001644 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001645 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001646 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1647 .getMessage(OFType.FLOW_MOD);
1648 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001649
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001650 short flowModCommand = OFFlowMod.OFPFC_ADD;
1651 if (userState.equals("FE_USER_ADD")) {
1652 flowModCommand = OFFlowMod.OFPFC_ADD;
1653 } else if (userState.equals("FE_USER_MODIFY")) {
1654 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1655 } else if (userState.equals("FE_USER_DELETE")) {
1656 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1657 } else {
1658 // Unknown user state. Ignore the entry
1659 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1660 flowEntryId.toString(), userState);
1661 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001662 }
1663
1664 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001665 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001666 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001667 // NOTE: The Flow matching conditions common for all Flow Entries are
1668 // used ONLY if a Flow Entry does NOT have the corresponding matching
1669 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001670 //
1671 OFMatch match = new OFMatch();
1672 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001673
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001674 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001675 Short matchInPort = flowEntryObj.getMatchInPort();
1676 if (matchInPort != null) {
1677 match.setInputPort(matchInPort);
1678 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1679 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001680
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001681 // Match the Source MAC address
1682 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1683 if (matchSrcMac == null)
1684 matchSrcMac = flowObj.getMatchSrcMac();
1685 if (matchSrcMac != null) {
1686 match.setDataLayerSource(matchSrcMac);
1687 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1688 }
1689
1690 // Match the Destination MAC address
1691 String matchDstMac = flowEntryObj.getMatchDstMac();
1692 if (matchDstMac == null)
1693 matchDstMac = flowObj.getMatchDstMac();
1694 if (matchDstMac != null) {
1695 match.setDataLayerDestination(matchDstMac);
1696 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1697 }
1698
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001699 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001700 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1701 if (matchEthernetFrameType == null)
1702 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1703 if (matchEthernetFrameType != null) {
1704 match.setDataLayerType(matchEthernetFrameType);
1705 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1706 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001707
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001708 // Match the VLAN ID
1709 Short matchVlanId = flowEntryObj.getMatchVlanId();
1710 if (matchVlanId == null)
1711 matchVlanId = flowObj.getMatchVlanId();
1712 if (matchVlanId != null) {
1713 match.setDataLayerVirtualLan(matchVlanId);
1714 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1715 }
1716
1717 // Match the VLAN priority
1718 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1719 if (matchVlanPriority == null)
1720 matchVlanPriority = flowObj.getMatchVlanPriority();
1721 if (matchVlanPriority != null) {
1722 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1723 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1724 }
1725
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001726 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001727 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1728 if (matchSrcIPv4Net == null)
1729 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1730 if (matchSrcIPv4Net != null) {
1731 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1732 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001733
1734 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001735 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1736 if (matchDstIPv4Net == null)
1737 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1738 if (matchDstIPv4Net != null) {
1739 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1740 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001741
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001742 // Match the IP protocol
1743 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1744 if (matchIpProto == null)
1745 matchIpProto = flowObj.getMatchIpProto();
1746 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001747 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001748 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001749 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001750
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001751 // Match the IP ToS (DSCP field, 6 bits)
1752 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1753 if (matchIpToS == null)
1754 matchIpToS = flowObj.getMatchIpToS();
1755 if (matchIpToS != null) {
1756 match.setNetworkTypeOfService(matchIpToS);
1757 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1758 }
1759
1760 // Match the Source TCP/UDP port
1761 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1762 if (matchSrcTcpUdpPort == null)
1763 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1764 if (matchSrcTcpUdpPort != null) {
1765 match.setTransportSource(matchSrcTcpUdpPort);
1766 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1767 }
1768
1769 // Match the Destination TCP/UDP port
1770 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1771 if (matchDstTcpUdpPort == null)
1772 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1773 if (matchDstTcpUdpPort != null) {
1774 match.setTransportDestination(matchDstTcpUdpPort);
1775 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001776 }
1777
1778 //
1779 // Fetch the actions
1780 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001781 Short actionOutputPort = null;
1782 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1783 int actionsLen = 0;
1784 FlowEntryActions flowEntryActions = null;
1785 String actionsStr = flowEntryObj.getActions();
1786 if (actionsStr != null)
1787 flowEntryActions = new FlowEntryActions(actionsStr);
1788 for (FlowEntryAction action : flowEntryActions.actions()) {
1789 ActionOutput actionOutput = action.actionOutput();
1790 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1791 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1792 ActionStripVlan actionStripVlan = action.actionStripVlan();
1793 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1794 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1795 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1796 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1797 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1798 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1799 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1800 ActionEnqueue actionEnqueue = action.actionEnqueue();
1801
1802 if (actionOutput != null) {
1803 actionOutputPort = actionOutput.port().value();
1804 // XXX: The max length is hard-coded for now
1805 OFActionOutput ofa =
1806 new OFActionOutput(actionOutput.port().value(),
1807 (short)0xffff);
1808 openFlowActions.add(ofa);
1809 actionsLen += ofa.getLength();
1810 }
1811
1812 if (actionSetVlanId != null) {
1813 OFActionVirtualLanIdentifier ofa =
1814 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1815 openFlowActions.add(ofa);
1816 actionsLen += ofa.getLength();
1817 }
1818
1819 if (actionSetVlanPriority != null) {
1820 OFActionVirtualLanPriorityCodePoint ofa =
1821 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1822 openFlowActions.add(ofa);
1823 actionsLen += ofa.getLength();
1824 }
1825
1826 if (actionStripVlan != null) {
1827 if (actionStripVlan.stripVlan() == true) {
1828 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1829 openFlowActions.add(ofa);
1830 actionsLen += ofa.getLength();
1831 }
1832 }
1833
1834 if (actionSetEthernetSrcAddr != null) {
1835 OFActionDataLayerSource ofa =
1836 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1837 openFlowActions.add(ofa);
1838 actionsLen += ofa.getLength();
1839 }
1840
1841 if (actionSetEthernetDstAddr != null) {
1842 OFActionDataLayerDestination ofa =
1843 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1844 openFlowActions.add(ofa);
1845 actionsLen += ofa.getLength();
1846 }
1847
1848 if (actionSetIPv4SrcAddr != null) {
1849 OFActionNetworkLayerSource ofa =
1850 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1851 openFlowActions.add(ofa);
1852 actionsLen += ofa.getLength();
1853 }
1854
1855 if (actionSetIPv4DstAddr != null) {
1856 OFActionNetworkLayerDestination ofa =
1857 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1858 openFlowActions.add(ofa);
1859 actionsLen += ofa.getLength();
1860 }
1861
1862 if (actionSetIpToS != null) {
1863 OFActionNetworkTypeOfService ofa =
1864 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1865 openFlowActions.add(ofa);
1866 actionsLen += ofa.getLength();
1867 }
1868
1869 if (actionSetTcpUdpSrcPort != null) {
1870 OFActionTransportLayerSource ofa =
1871 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1872 openFlowActions.add(ofa);
1873 actionsLen += ofa.getLength();
1874 }
1875
1876 if (actionSetTcpUdpDstPort != null) {
1877 OFActionTransportLayerDestination ofa =
1878 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1879 openFlowActions.add(ofa);
1880 actionsLen += ofa.getLength();
1881 }
1882
1883 if (actionEnqueue != null) {
1884 OFActionEnqueue ofa =
1885 new OFActionEnqueue(actionEnqueue.port().value(),
1886 actionEnqueue.queueId());
1887 openFlowActions.add(ofa);
1888 actionsLen += ofa.getLength();
1889 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001890 }
1891
1892 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1893 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1894 .setPriority(PRIORITY_DEFAULT)
1895 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1896 .setCookie(cookie)
1897 .setCommand(flowModCommand)
1898 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001899 .setActions(openFlowActions)
1900 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001901 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1902 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1903 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1904 if (actionOutputPort != null)
1905 fm.setOutPort(actionOutputPort);
1906 }
1907
1908 //
1909 // TODO: Set the following flag
1910 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1911 // See method ForwardingBase::pushRoute()
1912 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001913
1914 //
1915 // Write the message to the switch
1916 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001917 log.debug("MEASUREMENT: Installing flow entry " + userState +
1918 " into switch DPID: " +
1919 mySwitch.getStringId() +
1920 " flowEntryId: " + flowEntryId.toString() +
1921 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1922 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1923 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001924 try {
1925 messageDamper.write(mySwitch, fm, null);
1926 mySwitch.flush();
1927 //
1928 // TODO: We should use the OpenFlow Barrier mechanism
1929 // to check for errors, and update the SwitchState
1930 // for a flow entry after the Barrier message is
1931 // is received.
1932 //
1933 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1934 } catch (IOException e) {
1935 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001936 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001937 }
1938
1939 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001940 }
1941
1942 /**
1943 * Install a Flow Entry on a switch.
1944 *
1945 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001946 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001947 * @param flowEntry the flow entry to install.
1948 * @return true on success, otherwise false.
1949 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001950 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1951 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001952 //
1953 // Create the OpenFlow Flow Modification Entry to push
1954 //
1955 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1956 .getMessage(OFType.FLOW_MOD);
1957 long cookie = flowEntry.flowEntryId().value();
1958
1959 short flowModCommand = OFFlowMod.OFPFC_ADD;
1960 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1961 flowModCommand = OFFlowMod.OFPFC_ADD;
1962 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1963 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1964 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1965 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1966 } else {
1967 // Unknown user state. Ignore the entry
1968 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1969 flowEntry.flowEntryId().toString(),
1970 flowEntry.flowEntryUserState());
1971 return false;
1972 }
1973
1974 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001975 // Fetch the match conditions.
1976 //
1977 // NOTE: The Flow matching conditions common for all Flow Entries are
1978 // used ONLY if a Flow Entry does NOT have the corresponding matching
1979 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001980 //
1981 OFMatch match = new OFMatch();
1982 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001983 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1984 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1985
1986 // Match the Incoming Port
1987 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001988 if (matchInPort != null) {
1989 match.setInputPort(matchInPort.value());
1990 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1991 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001992
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001993 // Match the Source MAC address
1994 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1995 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1996 matchSrcMac = flowPathMatch.srcMac();
1997 }
1998 if (matchSrcMac != null) {
1999 match.setDataLayerSource(matchSrcMac.toString());
2000 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2001 }
2002
2003 // Match the Destination MAC address
2004 MACAddress matchDstMac = flowEntryMatch.dstMac();
2005 if ((matchDstMac == null) && (flowPathMatch != null)) {
2006 matchDstMac = flowPathMatch.dstMac();
2007 }
2008 if (matchDstMac != null) {
2009 match.setDataLayerDestination(matchDstMac.toString());
2010 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2011 }
2012
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002013 // Match the Ethernet Frame Type
2014 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2015 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2016 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2017 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002018 if (matchEthernetFrameType != null) {
2019 match.setDataLayerType(matchEthernetFrameType);
2020 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2021 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002022
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002023 // Match the VLAN ID
2024 Short matchVlanId = flowEntryMatch.vlanId();
2025 if ((matchVlanId == null) && (flowPathMatch != null)) {
2026 matchVlanId = flowPathMatch.vlanId();
2027 }
2028 if (matchVlanId != null) {
2029 match.setDataLayerVirtualLan(matchVlanId);
2030 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2031 }
2032
2033 // Match the VLAN priority
2034 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2035 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2036 matchVlanPriority = flowPathMatch.vlanPriority();
2037 }
2038 if (matchVlanPriority != null) {
2039 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2040 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2041 }
2042
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002043 // Match the Source IPv4 Network prefix
2044 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2045 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2046 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2047 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002048 if (matchSrcIPv4Net != null) {
2049 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2050 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002051
2052 // Natch the Destination IPv4 Network prefix
2053 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2054 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2055 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2056 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002057 if (matchDstIPv4Net != null) {
2058 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2059 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002060
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002061 // Match the IP protocol
2062 Byte matchIpProto = flowEntryMatch.ipProto();
2063 if ((matchIpProto == null) && (flowPathMatch != null)) {
2064 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002065 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002066 if (matchIpProto != null) {
2067 match.setNetworkProtocol(matchIpProto);
2068 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002069 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002070
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002071 // Match the IP ToS (DSCP field, 6 bits)
2072 Byte matchIpToS = flowEntryMatch.ipToS();
2073 if ((matchIpToS == null) && (flowPathMatch != null)) {
2074 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002075 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002076 if (matchIpToS != null) {
2077 match.setNetworkTypeOfService(matchIpToS);
2078 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2079 }
2080
2081 // Match the Source TCP/UDP port
2082 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2083 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2084 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2085 }
2086 if (matchSrcTcpUdpPort != null) {
2087 match.setTransportSource(matchSrcTcpUdpPort);
2088 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2089 }
2090
2091 // Match the Destination TCP/UDP port
2092 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2093 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2094 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2095 }
2096 if (matchDstTcpUdpPort != null) {
2097 match.setTransportDestination(matchDstTcpUdpPort);
2098 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002099 }
2100
2101 //
2102 // Fetch the actions
2103 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002104 Short actionOutputPort = null;
2105 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2106 int actionsLen = 0;
2107 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002108 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002109 for (FlowEntryAction action : flowEntryActions.actions()) {
2110 ActionOutput actionOutput = action.actionOutput();
2111 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2112 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2113 ActionStripVlan actionStripVlan = action.actionStripVlan();
2114 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2115 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2116 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2117 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2118 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2119 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2120 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2121 ActionEnqueue actionEnqueue = action.actionEnqueue();
2122
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002123 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002124 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002125 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002126 OFActionOutput ofa =
2127 new OFActionOutput(actionOutput.port().value(),
2128 (short)0xffff);
2129 openFlowActions.add(ofa);
2130 actionsLen += ofa.getLength();
2131 }
2132
2133 if (actionSetVlanId != null) {
2134 OFActionVirtualLanIdentifier ofa =
2135 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2136 openFlowActions.add(ofa);
2137 actionsLen += ofa.getLength();
2138 }
2139
2140 if (actionSetVlanPriority != null) {
2141 OFActionVirtualLanPriorityCodePoint ofa =
2142 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2143 openFlowActions.add(ofa);
2144 actionsLen += ofa.getLength();
2145 }
2146
2147 if (actionStripVlan != null) {
2148 if (actionStripVlan.stripVlan() == true) {
2149 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2150 openFlowActions.add(ofa);
2151 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002152 }
2153 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002154
2155 if (actionSetEthernetSrcAddr != null) {
2156 OFActionDataLayerSource ofa =
2157 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2158 openFlowActions.add(ofa);
2159 actionsLen += ofa.getLength();
2160 }
2161
2162 if (actionSetEthernetDstAddr != null) {
2163 OFActionDataLayerDestination ofa =
2164 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2165 openFlowActions.add(ofa);
2166 actionsLen += ofa.getLength();
2167 }
2168
2169 if (actionSetIPv4SrcAddr != null) {
2170 OFActionNetworkLayerSource ofa =
2171 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2172 openFlowActions.add(ofa);
2173 actionsLen += ofa.getLength();
2174 }
2175
2176 if (actionSetIPv4DstAddr != null) {
2177 OFActionNetworkLayerDestination ofa =
2178 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2179 openFlowActions.add(ofa);
2180 actionsLen += ofa.getLength();
2181 }
2182
2183 if (actionSetIpToS != null) {
2184 OFActionNetworkTypeOfService ofa =
2185 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2186 openFlowActions.add(ofa);
2187 actionsLen += ofa.getLength();
2188 }
2189
2190 if (actionSetTcpUdpSrcPort != null) {
2191 OFActionTransportLayerSource ofa =
2192 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2193 openFlowActions.add(ofa);
2194 actionsLen += ofa.getLength();
2195 }
2196
2197 if (actionSetTcpUdpDstPort != null) {
2198 OFActionTransportLayerDestination ofa =
2199 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2200 openFlowActions.add(ofa);
2201 actionsLen += ofa.getLength();
2202 }
2203
2204 if (actionEnqueue != null) {
2205 OFActionEnqueue ofa =
2206 new OFActionEnqueue(actionEnqueue.port().value(),
2207 actionEnqueue.queueId());
2208 openFlowActions.add(ofa);
2209 actionsLen += ofa.getLength();
2210 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002211 }
2212
2213 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2214 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2215 .setPriority(PRIORITY_DEFAULT)
2216 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2217 .setCookie(cookie)
2218 .setCommand(flowModCommand)
2219 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002220 .setActions(openFlowActions)
2221 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2222 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2223 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2224 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2225 if (actionOutputPort != null)
2226 fm.setOutPort(actionOutputPort);
2227 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002228
2229 //
2230 // TODO: Set the following flag
2231 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2232 // See method ForwardingBase::pushRoute()
2233 //
2234
2235 //
2236 // Write the message to the switch
2237 //
2238 try {
2239 messageDamper.write(mySwitch, fm, null);
2240 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002241 //
2242 // TODO: We should use the OpenFlow Barrier mechanism
2243 // to check for errors, and update the SwitchState
2244 // for a flow entry after the Barrier message is
2245 // is received.
2246 //
2247 // TODO: The FlowEntry Object in Titan should be set
2248 // to FE_SWITCH_UPDATED.
2249 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002250 } catch (IOException e) {
2251 log.error("Failure writing flow mod from network map", e);
2252 return false;
2253 }
2254 return true;
2255 }
2256
2257 /**
2258 * Remove a Flow Entry from a switch.
2259 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002260 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002261 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002262 * @param flowEntry the flow entry to remove.
2263 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002264 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002265 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2266 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002267 //
2268 // The installFlowEntry() method implements both installation
2269 // and removal of flow entries.
2270 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002271 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002272 }
2273
2274 /**
2275 * Install a Flow Entry on a remote controller.
2276 *
2277 * TODO: We need it now: Jono
2278 * - For now it will make a REST call to the remote controller.
2279 * - Internally, it needs to know the name of the remote controller.
2280 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002281 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002282 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002283 * @return true on success, otherwise false.
2284 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002285 public boolean installRemoteFlowEntry(FlowPath flowPath,
2286 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002287 // TODO: We need it now: Jono
2288 // - For now it will make a REST call to the remote controller.
2289 // - Internally, it needs to know the name of the remote controller.
2290 return true;
2291 }
2292
2293 /**
2294 * Remove a flow entry on a remote controller.
2295 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002296 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002297 * @param flowEntry the flow entry to remove.
2298 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002299 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002300 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2301 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002302 //
2303 // The installRemoteFlowEntry() method implements both installation
2304 // and removal of flow entries.
2305 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002306 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002307 }
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002308
2309 /**
2310 * Store a path flow for measurement purpose.
2311 *
2312 * NOTE: The Flow Path argument does NOT contain flow entries.
2313 * The Shortest Path is computed, and the corresponding Flow Entries
2314 * are stored in the Flow Path.
2315 *
2316 * @param flowPath the Flow Path with the endpoints and the match
2317 * conditions to store.
2318 * @return the stored shortest-path flow on success, otherwise null.
2319 */
2320 @Override
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002321 public synchronized FlowPath measurementStorePathFlow(FlowPath flowPath) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002322 //
2323 // Prepare the Shortest Path computation if the first Flow Path
2324 //
2325 if (measurementStoredPaths.isEmpty())
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002326 measurementShortestPathTopo = topoRouteService.prepareShortestPathTopo();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002327
2328 //
2329 // Compute the Shortest Path
2330 //
2331 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002332 topoRouteService.getTopoShortestPath(measurementShortestPathTopo,
2333 flowPath.dataPath().srcPort(),
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002334 flowPath.dataPath().dstPort());
2335 if (dataPath == null) {
2336 // We need the DataPath to populate the Network MAP
2337 dataPath = new DataPath();
2338 dataPath.setSrcPort(flowPath.dataPath().srcPort());
2339 dataPath.setDstPort(flowPath.dataPath().dstPort());
2340 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07002341 dataPath.applyFlowPathFlags(flowPath.flowPathFlags());
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002342
2343 //
2344 // Set the incoming port matching and the outgoing port output
2345 // actions for each flow entry.
2346 //
2347 for (FlowEntry flowEntry : dataPath.flowEntries()) {
2348 // Set the incoming port matching
2349 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
2350 flowEntry.setFlowEntryMatch(flowEntryMatch);
2351 flowEntryMatch.enableInPort(flowEntry.inPort());
2352
2353 // Set the outgoing port output action
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002354 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002355 FlowEntryAction flowEntryAction = new FlowEntryAction();
2356 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002357 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002358 }
2359
2360 //
2361 // Prepare the computed Flow Path
2362 //
2363 FlowPath computedFlowPath = new FlowPath();
2364 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
2365 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07002366 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002367 computedFlowPath.setDataPath(dataPath);
2368 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
2369
2370 //
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002371 // Add the computed Flow Path to the internal storage
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002372 //
2373 measurementStoredPaths.add(computedFlowPath);
2374
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002375 log.debug("Measurement storing path {}",
2376 computedFlowPath.flowId().toString());
2377
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002378 return (computedFlowPath);
2379 }
2380
2381 /**
2382 * Install path flows for measurement purpose.
2383 *
2384 * @param numThreads the number of threads to use to install the path
2385 * flows.
2386 * @return true on success, otherwise false.
2387 */
2388 @Override
2389 public boolean measurementInstallPaths(Integer numThreads) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002390 // Create a copy of the Flow Paths to install
2391 final ConcurrentLinkedQueue<FlowPath> measurementProcessingPaths =
2392 new ConcurrentLinkedQueue<FlowPath>(measurementStoredPaths);
2393
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002394 /**
2395 * A Thread-wrapper class for executing the threads and collecting
2396 * the measurement data.
2397 */
2398 class MyThread extends Thread {
2399 public long[] execTime = new long[2000];
2400 public int samples = 0;
2401 public int threadId = -1;
2402 @Override
2403 public void run() {
2404 while (true) {
2405 FlowPath flowPath = measurementProcessingPaths.poll();
2406 if (flowPath == null)
2407 return;
2408 // Install the Flow Path
2409 FlowId flowId = new FlowId();
2410 String dataPathSummaryStr =
2411 flowPath.dataPath().dataPathSummary();
2412 long startTime = System.nanoTime();
2413 addFlow(flowPath, flowId, dataPathSummaryStr);
2414 long endTime = System.nanoTime();
2415 execTime[samples] = endTime - startTime;
2416 samples++;
2417 }
2418 }
2419 };
2420
2421 List<MyThread> threads = new LinkedList<MyThread>();
2422
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002423 log.debug("Measurement Installing {} flows",
2424 measurementProcessingPaths.size());
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002425
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002426 //
2427 // Create the threads to install the Flow Paths
2428 //
2429 for (int i = 0; i < numThreads; i++) {
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002430 MyThread thread = new MyThread();
2431 thread.threadId = i;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002432 threads.add(thread);
2433 }
2434
2435 //
2436 // Start processing
2437 //
2438 measurementEndTimeProcessingPaths = 0;
2439 measurementStartTimeProcessingPaths = System.nanoTime();
2440 for (Thread thread : threads) {
2441 thread.start();
2442 }
2443
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002444 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002445 for (Thread thread : threads) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002446 try {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002447 thread.join();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002448 } catch (InterruptedException e) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002449 log.debug("Exception waiting for a thread to install a Flow Path: ", e);
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002450 }
2451 }
2452
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002453 // Record the end of processing
2454 measurementEndTimeProcessingPaths = System.nanoTime();
2455
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002456 //
2457 // Prepare the string with measurement data per each Flow Path
2458 // installation.
2459 // The string is multiple lines: one line per Flow Path installation:
2460 // ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2461 //
2462 measurementPerFlowStr = new String();
2463 String eol = System.getProperty("line.separator");
2464 for (MyThread thread : threads) {
2465 for (int i = 0; i < thread.samples; i++) {
2466 measurementPerFlowStr += "ThreadAndTimePerFlow " + thread.threadId + " " + numThreads + " " + thread.execTime[i] + eol;
2467 }
2468 }
2469
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002470 return true;
2471 }
2472
2473 /**
2474 * Get the measurement time that took to install the path flows.
2475 *
2476 * @return the measurement time (in nanoseconds) it took to install
2477 * the path flows.
2478 */
2479 @Override
2480 public Long measurementGetInstallPathsTimeNsec() {
2481 return new Long(measurementEndTimeProcessingPaths -
2482 measurementStartTimeProcessingPaths);
2483 }
2484
2485 /**
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002486 * Get the measurement install time per Flow.
2487 *
2488 * @return a multi-line string with the following format per line:
2489 * ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2490 */
2491 @Override
2492 public String measurementGetPerFlowInstallTime() {
2493 return new String(measurementPerFlowStr);
2494 }
2495
2496 /**
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002497 * Clear the path flows stored for measurement purpose.
2498 *
2499 * @return true on success, otherwise false.
2500 */
2501 @Override
2502 public boolean measurementClearAllPaths() {
2503 measurementStoredPaths.clear();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002504 topoRouteService.dropShortestPathTopo(measurementShortestPathTopo);
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002505 measurementStartTimeProcessingPaths = 0;
2506 measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002507 measurementPerFlowStr = new String();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002508
2509 return true;
2510 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002511}