blob: 2f6569a0a32105368687211eaece9ed656d20835 [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
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;
22import net.floodlightcontroller.core.INetMapStorage;
23import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070025import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070026import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070027import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080028import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080029import net.floodlightcontroller.core.module.FloodlightModuleContext;
30import net.floodlightcontroller.core.module.FloodlightModuleException;
31import net.floodlightcontroller.core.module.IFloodlightModule;
32import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080033import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
34import net.floodlightcontroller.restserver.IRestApiService;
35import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080037import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070038import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070040import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070042import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.FlowEntrySwitchState;
44import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080045import net.floodlightcontroller.util.FlowId;
46import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070047import net.floodlightcontroller.util.IPv4Net;
48import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.floodlightcontroller.util.OFMessageDamper;
50import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070051import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052import net.onrc.onos.util.GraphDBConnection;
Toshio Koide9fe1cb22013-06-13 13:51:11 -070053import net.onrc.onos.util.GraphDBOperation;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080054
55import org.openflow.protocol.OFFlowMod;
56import org.openflow.protocol.OFMatch;
57import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070058import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059import org.openflow.protocol.OFType;
60import org.openflow.protocol.action.OFAction;
61import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Jonathan Hartf5315fb2013-04-05 11:41:56 -070065
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070066public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080067
Toshio Koide9fe1cb22013-06-13 13:51:11 -070068 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080069
70 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070071 protected volatile IFloodlightProviderService floodlightProvider;
72 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070073 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074
75 protected OFMessageDamper messageDamper;
76
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070077 //
78 // TODO: Values copied from elsewhere (class LearningSwitch).
79 // The local copy should go away!
80 //
81 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
82 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
83 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
84 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
85 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080086
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000087 // Flow Entry ID generation state
88 private static Random randomGenerator = new Random();
89 private static int nextFlowEntryIdPrefix = 0;
90 private static int nextFlowEntryIdSuffix = 0;
91 private static long nextFlowEntryId = 0;
92
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070093 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070094 private static long measurementFlowId = 100000;
95 private static String measurementFlowIdStr = "0x186a0"; // 100000
96 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070097 //
98 private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070099 private long measurementStartTimeProcessingPaths = 0;
100 private long measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000101 Map<Long, ?> measurementShortestPathTopo = null;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000102 private String measurementPerFlowStr = new String();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700103
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800104 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800105 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
106
107 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700108 private ScheduledExecutorService mapReaderScheduler;
109 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700110
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700111 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800112 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700113 try {
114 runImpl();
115 } catch (Exception e) {
116 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700117 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700118 return;
119 }
120 }
121
122 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700123 long startTime = System.nanoTime();
124 int counterAllFlowEntries = 0;
125 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700126
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800127 if (floodlightProvider == null) {
128 log.debug("FloodlightProvider service not found!");
129 return;
130 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000131 Map<Long, IOFSwitch> mySwitches =
132 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700133 LinkedList<IFlowEntry> addFlowEntries =
134 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000135 LinkedList<IFlowEntry> deleteFlowEntries =
136 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700137
138 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700139 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700140 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700141 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700142 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000143 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700144 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700145 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700146 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000147
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000148 String dpidStr = flowEntryObj.getSwitchDpid();
149 if (dpidStr == null)
150 continue;
151 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800152 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000153 if (mySwitch == null)
154 continue; // Ignore the entry: not my switch
155
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700156 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700157 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700158 if (flowObj == null)
159 continue; // Should NOT happen
160 if (flowObj.getFlowId() == null)
161 continue; // Invalid entry
162
163 //
164 // NOTE: For now we process the DELETE before the ADD
165 // to cover the more common scenario.
166 // TODO: This is error prone and needs to be fixed!
167 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000168 String userState = flowEntryObj.getUserState();
169 if (userState == null)
170 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700171 if (userState.equals("FE_USER_DELETE")) {
172 // An entry that needs to be deleted.
173 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700174 installFlowEntry(mySwitch, flowObj, flowEntryObj);
175 } else {
176 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700177 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700178 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700180 // TODO: Commented-out for now
181 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700182 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700183 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700184 processed_measurement_flow = true;
185 }
186 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700187 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700188 }
189
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700190 //
191 // Process the Flow Entries that need to be added
192 //
193 for (IFlowEntry flowEntryObj : addFlowEntries) {
194 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700195 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700196 if (flowObj == null)
197 continue; // Should NOT happen
198 if (flowObj.getFlowId() == null)
199 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700200
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700201 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700202 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000203 if (mySwitch == null)
204 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700205 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800206 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000207
208 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000209 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700210 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 //
212 // TODO: We should use the OpenFlow Barrier mechanism
213 // to check for errors, and delete the Flow Entries after the
214 // Barrier message is received.
215 //
216 while (! deleteFlowEntries.isEmpty()) {
217 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
218 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700219 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000220 if (flowObj == null) {
221 log.debug("Did not find FlowPath to be deleted");
222 continue;
223 }
224 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700225 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000226 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700227
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700228 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700229
230 if (processed_measurement_flow) {
231 long estimatedTime =
232 System.nanoTime() - modifiedMeasurementFlowTime;
233 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
234 (double)estimatedTime / 1000000000 + " sec";
235 log.debug(logMsg);
236 }
237
238 long estimatedTime = System.nanoTime() - startTime;
239 double rate = 0.0;
240 if (estimatedTime > 0)
241 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
242 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
243 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
244 counterMyNotUpdatedFlowEntries + " in " +
245 (double)estimatedTime / 1000000000 + " sec: " +
246 rate + " paths/s";
247 log.debug(logMsg);
248 }
249 };
250
251 final Runnable shortestPathReconcile = new Runnable() {
252 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700253 try {
254 runImpl();
255 } catch (Exception e) {
256 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700257 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700258 return;
259 }
260 }
261
262 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700263 long startTime = System.nanoTime();
264 int counterAllFlowPaths = 0;
265 int counterMyFlowPaths = 0;
266
267 if (floodlightProvider == null) {
268 log.debug("FloodlightProvider service not found!");
269 return;
270 }
271 Map<Long, IOFSwitch> mySwitches =
272 floodlightProvider.getSwitches();
273 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
274
275 boolean processed_measurement_flow = false;
276
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700277 //
278 // Fetch and recompute the Shortest Path for those
279 // Flow Paths this controller is responsible for.
280 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000281 Map<Long, ?> shortestPathTopo =
282 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700283 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700284 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700285 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700286 if (flowPathObj == null)
287 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700288
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700289 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000290 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700291 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700292 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700293 //
294 // Use the source DPID as a heuristic to decide
295 // which controller is responsible for maintaining the
296 // shortest path.
297 // NOTE: This heuristic is error-prone: if the switch
298 // goes away and no controller is responsible for that
299 // switch, then the original Flow Path is not cleaned-up
300 //
301 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
302 if (mySwitch == null)
303 continue; // Ignore: not my responsibility
304
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700305 // Test the Data Path Summary string
306 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
307 if (dataPathSummaryStr == null)
308 continue; // Could be invalid entry?
309 if (dataPathSummaryStr.isEmpty())
310 continue; // No need to maintain this flow
311
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000312 //
313 // Test whether we need to complete the Flow cleanup,
314 // if the Flow has been deleted by the user.
315 //
316 String flowUserState = flowPathObj.getUserState();
317 if ((flowUserState != null)
318 && flowUserState.equals("FE_USER_DELETE")) {
319 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
320 boolean empty = true; // TODO: an ugly hack
321 for (IFlowEntry flowEntryObj : flowEntries) {
322 empty = false;
323 break;
324 }
325 if (empty)
326 deleteFlows.add(flowPathObj);
327 }
328
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000329 // Fetch the fields needed to recompute the shortest path
330 Short srcPortShort = flowPathObj.getSrcPort();
331 String dstDpidStr = flowPathObj.getDstSwitch();
332 Short dstPortShort = flowPathObj.getDstPort();
333 if ((srcPortShort == null) ||
334 (dstDpidStr == null) ||
335 (dstPortShort == null)) {
336 continue;
337 }
338
339 Port srcPort = new Port(srcPortShort);
340 Dpid dstDpid = new Dpid(dstDpidStr);
341 Port dstPort = new Port(dstPortShort);
342 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
343 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
344
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700345 counterMyFlowPaths++;
346
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700347 //
348 // NOTE: Using here the regular getShortestPath() method
349 // won't work here, because that method calls internally
350 // "conn.endTx(Transaction.COMMIT)", and that will
351 // invalidate all handlers to the Titan database.
352 // If we want to experiment with calling here
353 // getShortestPath(), we need to refactor that code
354 // to avoid closing the transaction.
355 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700356 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000357 topoRouteService.getTopoShortestPath(shortestPathTopo,
358 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700359 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000360 if (dataPath == null) {
361 // We need the DataPath to compare the paths
362 dataPath = new DataPath();
363 dataPath.setSrcPort(srcSwitchPort);
364 dataPath.setDstPort(dstSwitchPort);
365 }
366
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700367 String newDataPathSummaryStr = dataPath.dataPathSummary();
368 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
369 continue; // Nothing changed
370
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700371 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700372 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000373
374 //
375 // Delete all leftover Flows marked for deletion from the
376 // Network MAP.
377 //
378 while (! deleteFlows.isEmpty()) {
379 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700380 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000381 }
382
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000383 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700384
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700385 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700386
387 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700388 long estimatedTime =
389 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700390 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
391 (double)estimatedTime / 1000000000 + " sec";
392 log.debug(logMsg);
393 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700394
395 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700396 double rate = 0.0;
397 if (estimatedTime > 0)
398 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700399 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700400 counterAllFlowPaths + " MyFlowPaths: " +
401 counterMyFlowPaths + " in " +
402 (double)estimatedTime / 1000000000 + " sec: " +
403 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700404 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800405 }
406 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700407
Jonathan Hart50a94982013-04-10 14:49:51 -0700408 //final ScheduledFuture<?> mapReaderHandle =
409 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800410
Jonathan Hart50a94982013-04-10 14:49:51 -0700411 //final ScheduledFuture<?> shortestPathReconcileHandle =
412 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700413
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 @Override
415 public void init(String conf) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700416 op = new GraphDBOperation(GraphDBConnection.getInstance(conf));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800417 }
418
419 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700420 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800421 }
422
423 @Override
424 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700425 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800426 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800427
428 @Override
429 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
430 Collection<Class<? extends IFloodlightService>> l =
431 new ArrayList<Class<? extends IFloodlightService>>();
432 l.add(IFlowService.class);
433 return l;
434 }
435
436 @Override
437 public Map<Class<? extends IFloodlightService>, IFloodlightService>
438 getServiceImpls() {
439 Map<Class<? extends IFloodlightService>,
440 IFloodlightService> m =
441 new HashMap<Class<? extends IFloodlightService>,
442 IFloodlightService>();
443 m.put(IFlowService.class, this);
444 return m;
445 }
446
447 @Override
448 public Collection<Class<? extends IFloodlightService>>
449 getModuleDependencies() {
450 Collection<Class<? extends IFloodlightService>> l =
451 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700453 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800454 l.add(IRestApiService.class);
455 return l;
456 }
457
458 @Override
459 public void init(FloodlightModuleContext context)
460 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700461 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800462 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700463 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800464 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800465 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
466 EnumSet.of(OFType.FLOW_MOD),
467 OFMESSAGE_DAMPER_TIMEOUT);
468 // TODO: An ugly hack!
469 String conf = "/tmp/cassandra.titan";
470 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700471
472 mapReaderScheduler = Executors.newScheduledThreadPool(1);
473 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800474 }
475
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700476 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000477 //
478 // Generate the next Flow Entry ID.
479 // NOTE: For now, the higher 32 bits are random, and
480 // the lower 32 bits are sequential.
481 // In the future, we need a better allocation mechanism.
482 //
483 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
484 nextFlowEntryIdPrefix = randomGenerator.nextInt();
485 nextFlowEntryIdSuffix = 0;
486 } else {
487 nextFlowEntryIdSuffix++;
488 }
489 long result = (long)nextFlowEntryIdPrefix << 32;
490 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
491 return result;
492 }
493
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800494 @Override
495 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700496 restApi.addRestletRoutable(new FlowWebRoutable());
497
498 // Initialize the Flow Entry ID generator
499 nextFlowEntryIdPrefix = randomGenerator.nextInt();
500
501 mapReaderScheduler.scheduleAtFixedRate(
Pankaj Berde55f121a2013-04-23 15:42:54 -0700502 mapReader, 1, 1, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700503 shortestPathReconcileScheduler.scheduleAtFixedRate(
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700504 shortestPathReconcile, 100, 100, TimeUnit.MILLISECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800505 }
506
507 /**
508 * Add a flow.
509 *
510 * Internally, ONOS will automatically register the installer for
511 * receiving Flow Path Notifications for that path.
512 *
513 * @param flowPath the Flow Path to install.
514 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700515 * @param dataPathSummaryStr the data path summary string if the added
516 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800517 * @return true on success, otherwise false.
518 */
519 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700520 public boolean addFlow(FlowPath flowPath, FlowId flowId,
521 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700522 /*
523 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700524 if (flowPath.flowId().value() == measurementFlowId) {
525 modifiedMeasurementFlowTime = System.nanoTime();
526 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700527 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800528
529 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000530 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800531 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700532 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800533 != null) {
534 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
535 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000536 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800537 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700538 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800539 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
540 flowPath.flowId().toString());
541 }
542 } catch (Exception e) {
543 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700544 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000545
546 StringWriter sw = new StringWriter();
547 e.printStackTrace(new PrintWriter(sw));
548 String stacktrace = sw.toString();
549
550 log.error(":addFlow FlowId:{} failed: {}",
551 flowPath.flowId().toString(),
552 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800553 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700554 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000555 log.error(":addFlow FlowId:{} failed: Flow object not created",
556 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700557 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800558 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700559 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800560
561 //
562 // Set the Flow key:
563 // - flowId
564 //
565 flowObj.setFlowId(flowPath.flowId().toString());
566 flowObj.setType("flow");
567
568 //
569 // Set the Flow attributes:
570 // - flowPath.installerId()
571 // - flowPath.dataPath().srcPort()
572 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700573 // - flowPath.matchEthernetFrameType()
574 // - flowPath.matchSrcIPv4Net()
575 // - flowPath.matchDstIPv4Net()
576 // - flowPath.matchSrcMac()
577 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800578 //
579 flowObj.setInstallerId(flowPath.installerId().toString());
580 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
581 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
582 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
583 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700584 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
585 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
586 }
587 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
588 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
589 }
590 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
591 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
592 }
593 if (flowPath.flowEntryMatch().matchSrcMac()) {
594 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
595 }
596 if (flowPath.flowEntryMatch().matchDstMac()) {
597 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
598 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800599
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700600 if (dataPathSummaryStr != null) {
601 flowObj.setDataPathSummary(dataPathSummaryStr);
602 } else {
603 flowObj.setDataPathSummary("");
604 }
605
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000606 if (found)
607 flowObj.setUserState("FE_USER_MODIFY");
608 else
609 flowObj.setUserState("FE_USER_ADD");
610
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800611 // Flow edges:
612 // HeadFE
613
614
615 //
616 // Flow Entries:
617 // flowPath.dataPath().flowEntries()
618 //
619 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700620 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700621 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800622 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700623 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800624 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700625 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800626
627 //
628 // TODO: We need a proper Flow ID allocation mechanism.
629 //
630 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700631
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800632 return true;
633 }
634
635 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700636 * Add a flow entry to the Network MAP.
637 *
638 * @param flowObj the corresponding Flow Path object for the Flow Entry.
639 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700640 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700641 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700642 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700643 // Flow edges
644 // HeadFE (TODO)
645
646 //
647 // Assign the FlowEntry ID.
648 //
649 if ((flowEntry.flowEntryId() == null) ||
650 (flowEntry.flowEntryId().value() == 0)) {
651 long id = getNextFlowEntryId();
652 flowEntry.setFlowEntryId(new FlowEntryId(id));
653 }
654
655 IFlowEntry flowEntryObj = null;
656 boolean found = false;
657 try {
658 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700659 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700660 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
661 flowEntry.flowEntryId().toString());
662 found = true;
663 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700664 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700665 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
666 flowEntry.flowEntryId().toString());
667 }
668 } catch (Exception e) {
669 log.error(":addFlow FlowEntryId:{} failed",
670 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700671 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700672 }
673 if (flowEntryObj == null) {
674 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
675 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700676 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700677 }
678
679 //
680 // Set the Flow Entry key:
681 // - flowEntry.flowEntryId()
682 //
683 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
684 flowEntryObj.setType("flow_entry");
685
686 //
687 // Set the Flow Entry Edges and attributes:
688 // - Switch edge
689 // - InPort edge
690 // - OutPort edge
691 //
692 // - flowEntry.flowEntryMatch()
693 // - flowEntry.flowEntryActions()
694 // - flowEntry.dpid()
695 // - flowEntry.flowEntryUserState()
696 // - flowEntry.flowEntrySwitchState()
697 // - flowEntry.flowEntryErrorState()
698 // - flowEntry.matchInPort()
699 // - flowEntry.matchEthernetFrameType()
700 // - flowEntry.matchSrcIPv4Net()
701 // - flowEntry.matchDstIPv4Net()
702 // - flowEntry.matchSrcMac()
703 // - flowEntry.matchDstMac()
704 // - flowEntry.actionOutput()
705 //
706 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700707 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700708 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
709 flowEntryObj.setSwitch(sw);
710 if (flowEntry.flowEntryMatch().matchInPort()) {
711 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700712 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700713 flowEntry.flowEntryMatch().inPort().value());
714 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
715 flowEntryObj.setInPort(inport);
716 }
717 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
718 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
719 }
720 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
721 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
722 }
723 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
724 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
725 }
726 if (flowEntry.flowEntryMatch().matchSrcMac()) {
727 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
728 }
729 if (flowEntry.flowEntryMatch().matchDstMac()) {
730 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
731 }
732
733 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
734 if (fa.actionOutput() != null) {
735 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700736 op.searchPort(flowEntry.dpid().toString(),
737 fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700738 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
739 flowEntryObj.setOutPort(outport);
740 }
741 }
742 // TODO: Hacks with hard-coded state names!
743 if (found)
744 flowEntryObj.setUserState("FE_USER_MODIFY");
745 else
746 flowEntryObj.setUserState("FE_USER_ADD");
747 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
748 //
749 // TODO: Take care of the FlowEntryErrorState.
750 //
751
752 // Flow Entries edges:
753 // Flow
754 // NextFE (TODO)
755 if (! found) {
756 flowObj.addFlowEntry(flowEntryObj);
757 flowEntryObj.setFlow(flowObj);
758 }
759
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700760 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700761 }
762
763 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000764 * Delete all previously added flows.
765 *
766 * @return true on success, otherwise false.
767 */
768 @Override
769 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000770 List<Thread> threads = new LinkedList<Thread>();
771 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
772 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000773
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000774 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700775 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000776 for (IFlowPath flowPathObj : allFlowPaths) {
777 if (flowPathObj == null)
778 continue;
779 String flowIdStr = flowPathObj.getFlowId();
780 if (flowIdStr == null)
781 continue;
782 FlowId flowId = new FlowId(flowIdStr);
783 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000784 }
785
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000786 // Delete all flows one-by-one
787 for (FlowId flowId : concurrentAllFlowIds)
788 deleteFlow(flowId);
789
790 /*
791 * TODO: A faster mechanism to delete the Flow Paths by using
792 * a number of threads. Commented-out for now.
793 */
794 /*
795 //
796 // Create the threads to delete the Flow Paths
797 //
798 for (int i = 0; i < 10; i++) {
799 Thread thread = new Thread(new Runnable() {
800 @Override
801 public void run() {
802 while (true) {
803 FlowId flowId = concurrentAllFlowIds.poll();
804 if (flowId == null)
805 return;
806 deleteFlow(flowId);
807 }
808 }}, "Delete All Flow Paths");
809 threads.add(thread);
810 }
811
812 // Start processing
813 for (Thread thread : threads) {
814 thread.start();
815 }
816
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000817 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000818 for (Thread thread : threads) {
819 try {
820 thread.join();
821 } catch (InterruptedException e) {
822 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
823 }
824 }
825 */
826
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000827 return true;
828 }
829
830 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800831 * Delete a previously added flow.
832 *
833 * @param flowId the Flow ID of the flow to delete.
834 * @return true on success, otherwise false.
835 */
836 @Override
837 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700838 /*
839 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700840 if (flowId.value() == measurementFlowId) {
841 modifiedMeasurementFlowTime = System.nanoTime();
842 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700843 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700844
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800845 IFlowPath flowObj = null;
846 //
847 // We just mark the entries for deletion,
848 // and let the switches remove each individual entry after
849 // it has been removed from the switches.
850 //
851 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700852 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800853 != null) {
854 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
855 flowId.toString());
856 } else {
857 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
858 flowId.toString());
859 }
860 } catch (Exception e) {
861 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700862 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800863 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
864 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700865 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700866 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800867 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700868 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800869
870 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000871 // Find and mark for deletion all Flow Entries,
872 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800873 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000874 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800875 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
876 boolean empty = true; // TODO: an ugly hack
877 for (IFlowEntry flowEntryObj : flowEntries) {
878 empty = false;
879 // flowObj.removeFlowEntry(flowEntryObj);
880 // conn.utils().removeFlowEntry(conn, flowEntryObj);
881 flowEntryObj.setUserState("FE_USER_DELETE");
882 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
883 }
884 // Remove from the database empty flows
885 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700886 op.removeFlowPath(flowObj);
887 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800888
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800889 return true;
890 }
891
892 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000893 * Clear the state for all previously added flows.
894 *
895 * @return true on success, otherwise false.
896 */
897 @Override
898 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000899 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000900
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000901 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700902 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000903 for (IFlowPath flowPathObj : allFlowPaths) {
904 if (flowPathObj == null)
905 continue;
906 String flowIdStr = flowPathObj.getFlowId();
907 if (flowIdStr == null)
908 continue;
909 FlowId flowId = new FlowId(flowIdStr);
910 allFlowIds.add(flowId);
911 }
912
913 // Clear all flows one-by-one
914 for (FlowId flowId : allFlowIds) {
915 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000916 }
917
918 return true;
919 }
920
921 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700922 * Clear the state for a previously added flow.
923 *
924 * @param flowId the Flow ID of the flow to clear.
925 * @return true on success, otherwise false.
926 */
927 @Override
928 public boolean clearFlow(FlowId flowId) {
929 IFlowPath flowObj = null;
930 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700931 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700932 != null) {
933 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
934 flowId.toString());
935 } else {
936 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
937 flowId.toString());
938 }
939 } catch (Exception e) {
940 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700941 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700942 log.error(":clearFlow FlowId:{} failed", flowId.toString());
943 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700944 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700945 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700946 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700947 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700948
949 //
950 // Remove all Flow Entries
951 //
952 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
953 for (IFlowEntry flowEntryObj : flowEntries) {
954 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700955 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700956 }
957 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700958 op.removeFlowPath(flowObj);
959 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700960
961 return true;
962 }
963
964 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800965 * Get a previously added flow.
966 *
967 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800968 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800969 */
970 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800971 public FlowPath getFlow(FlowId flowId) {
972 IFlowPath flowObj = null;
973 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700974 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800975 != null) {
976 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
977 flowId.toString());
978 } else {
979 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
980 flowId.toString());
981 }
982 } catch (Exception e) {
983 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700984 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800985 log.error(":getFlow FlowId:{} failed", flowId.toString());
986 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700987 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700988 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800989 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700990 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800991
992 //
993 // Extract the Flow state
994 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800995 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700996 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800997
998 return flowPath;
999 }
1000
1001 /**
1002 * Get all previously added flows by a specific installer for a given
1003 * data path endpoints.
1004 *
1005 * @param installerId the Caller ID of the installer of the flow to get.
1006 * @param dataPathEndpoints the data path endpoints of the flow to get.
1007 * @return the Flow Paths if found, otherwise null.
1008 */
1009 @Override
1010 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1011 DataPathEndpoints dataPathEndpoints) {
1012 //
1013 // TODO: The implementation below is not optimal:
1014 // We fetch all flows, and then return only the subset that match
1015 // the query conditions.
1016 // We should use the appropriate Titan/Gremlin query to filter-out
1017 // the flows as appropriate.
1018 //
1019 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001020 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001021
1022 if (allFlows == null) {
1023 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001024 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001025 }
1026
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001027 for (FlowPath flow : allFlows) {
1028 //
1029 // TODO: String-based comparison is sub-optimal.
1030 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001031 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001032 //
1033 if (! flow.installerId().toString().equals(installerId.toString()))
1034 continue;
1035 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1036 continue;
1037 }
1038 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1039 continue;
1040 }
1041 flowPaths.add(flow);
1042 }
1043
1044 if (flowPaths.isEmpty()) {
1045 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001046 } else {
1047 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1048 }
1049
1050 return flowPaths;
1051 }
1052
1053 /**
1054 * Get all installed flows by all installers for given data path endpoints.
1055 *
1056 * @param dataPathEndpoints the data path endpoints of the flows to get.
1057 * @return the Flow Paths if found, otherwise null.
1058 */
1059 @Override
1060 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1061 //
1062 // TODO: The implementation below is not optimal:
1063 // We fetch all flows, and then return only the subset that match
1064 // the query conditions.
1065 // We should use the appropriate Titan/Gremlin query to filter-out
1066 // the flows as appropriate.
1067 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001068 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1069 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001070
1071 if (allFlows == null) {
1072 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001073 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001074 }
1075
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001076 for (FlowPath flow : allFlows) {
1077 //
1078 // TODO: String-based comparison is sub-optimal.
1079 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001080 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001081 //
1082 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1083 continue;
1084 }
1085 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1086 continue;
1087 }
1088 flowPaths.add(flow);
1089 }
1090
1091 if (flowPaths.isEmpty()) {
1092 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001093 } else {
1094 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1095 }
1096
1097 return flowPaths;
1098 }
1099
1100 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001101 * Get summary of all installed flows by all installers in a given range
1102 *
1103 * @param flowId the data path endpoints of the flows to get.
1104 * @param maxFlows: the maximum number of flows to be returned
1105 * @return the Flow Paths if found, otherwise null.
1106 */
1107 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001108 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001109
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001110 // TODO: The implementation below is not optimal:
1111 // We fetch all flows, and then return only the subset that match
1112 // the query conditions.
1113 // We should use the appropriate Titan/Gremlin query to filter-out
1114 // the flows as appropriate.
1115 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001116 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001117
Jonathan Hart01f2d272013-04-04 20:03:46 -07001118 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1119
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001120 Collections.sort(flowPathsWithoutFlowEntries,
1121 new Comparator<IFlowPath>(){
1122 @Override
1123 public int compare(IFlowPath first, IFlowPath second) {
1124 // TODO Auto-generated method stub
1125 long result = new FlowId(first.getFlowId()).value()
1126 - new FlowId(second.getFlowId()).value();
1127 if (result > 0) return 1;
1128 else if (result < 0) return -1;
1129 else return 0;
1130 }
1131 }
1132 );
1133
Jonathan Hart01f2d272013-04-04 20:03:46 -07001134 return flowPathsWithoutFlowEntries;
1135
1136 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001137 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001138
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001139 if (allFlows == null) {
1140 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001141 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001142 }
1143
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001144 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001145
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001146 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001147 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001148
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001149 // start from desired flowId
1150 if (flow.flowId().value() < flowId.value()) {
1151 continue;
1152 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001153
1154 // Summarize by making null flow entry fields that are not relevant to report
1155 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1156 flowEntry.setFlowEntryActions(null);
1157 flowEntry.setFlowEntryMatch(null);
1158 }
1159
1160 flowPaths.add(flow);
1161 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1162 break;
1163 }
1164 }
1165
1166 if (flowPaths.isEmpty()) {
1167 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001168 } else {
1169 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1170 }
1171
1172 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001173 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001174 }
1175
1176 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001177 * Get all installed flows by all installers.
1178 *
1179 * @return the Flow Paths if found, otherwise null.
1180 */
1181 @Override
1182 public ArrayList<FlowPath> getAllFlows() {
1183 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001184 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001185
1186 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001187 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001188 log.debug("Get all FlowPaths: found FlowPaths");
1189 } else {
1190 log.debug("Get all FlowPaths: no FlowPaths found");
1191 }
1192 } catch (Exception e) {
1193 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001194 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001195 log.error(":getAllFlowPaths failed");
1196 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001197 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001198 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001199 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001200 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001201
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001202 for (IFlowPath flowObj : flowPathsObj) {
1203 //
1204 // Extract the Flow state
1205 //
1206 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001207 if (flowPath != null)
1208 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001209 }
1210
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001211 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001212
1213 return flowPaths;
1214 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001215
1216 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1217 Iterable<IFlowPath> flowPathsObj = null;
1218 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1219 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1220
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001221 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001222
Jonathan Hart01f2d272013-04-04 20:03:46 -07001223 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001224 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001225 log.debug("Get all FlowPaths: found FlowPaths");
1226 } else {
1227 log.debug("Get all FlowPaths: no FlowPaths found");
1228 }
1229 } catch (Exception e) {
1230 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001231 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001232 log.error(":getAllFlowPaths failed");
1233 }
1234 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1235 return new ArrayList<IFlowPath>(); // No Flows found
1236 }
1237
1238 for (IFlowPath flowObj : flowPathsObj){
1239 flowPathsObjArray.add(flowObj);
1240 }
1241 /*
1242 for (IFlowPath flowObj : flowPathsObj) {
1243 //
1244 // Extract the Flow state
1245 //
1246 FlowPath flowPath = extractFlowPath(flowObj);
1247 if (flowPath != null)
1248 flowPaths.add(flowPath);
1249 }
1250 */
1251
1252 //conn.endTx(Transaction.COMMIT);
1253
1254 return flowPathsObjArray;
1255 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001256
1257 /**
1258 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1259 *
1260 * @param flowObj the object to extract the Flow Path State from.
1261 * @return the extracted Flow Path State.
1262 */
1263 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001264 //
1265 // Extract the Flow state
1266 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001267 String flowIdStr = flowObj.getFlowId();
1268 String installerIdStr = flowObj.getInstallerId();
1269 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001270 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001271 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001272 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001273
1274 if ((flowIdStr == null) ||
1275 (installerIdStr == null) ||
1276 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001277 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001278 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001279 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001280 // TODO: A work-around, becauuse of some bogus database objects
1281 return null;
1282 }
1283
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001284 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001285 flowPath.setFlowId(new FlowId(flowIdStr));
1286 flowPath.setInstallerId(new CallerId(installerIdStr));
1287 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001288 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001289 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001290 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001291 //
1292 // Extract the match conditions common for all Flow Entries
1293 //
1294 {
1295 FlowEntryMatch match = new FlowEntryMatch();
1296 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1297 if (matchEthernetFrameType != null)
1298 match.enableEthernetFrameType(matchEthernetFrameType);
1299 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1300 if (matchSrcIPv4Net != null)
1301 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1302 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1303 if (matchDstIPv4Net != null)
1304 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1305 String matchSrcMac = flowObj.getMatchSrcMac();
1306 if (matchSrcMac != null)
1307 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1308 String matchDstMac = flowObj.getMatchDstMac();
1309 if (matchDstMac != null)
1310 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1311 flowPath.setFlowEntryMatch(match);
1312 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001313
1314 //
1315 // Extract all Flow Entries
1316 //
1317 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1318 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001319 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1320 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001321 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001322 flowPath.dataPath().flowEntries().add(flowEntry);
1323 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001324
1325 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001326 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001327
1328 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001329 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1330 *
1331 * @param flowEntryObj the object to extract the Flow Entry State from.
1332 * @return the extracted Flow Entry State.
1333 */
1334 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1335 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1336 String switchDpidStr = flowEntryObj.getSwitchDpid();
1337 String userState = flowEntryObj.getUserState();
1338 String switchState = flowEntryObj.getSwitchState();
1339
1340 if ((flowEntryIdStr == null) ||
1341 (switchDpidStr == null) ||
1342 (userState == null) ||
1343 (switchState == null)) {
1344 // TODO: A work-around, becauuse of some bogus database objects
1345 return null;
1346 }
1347
1348 FlowEntry flowEntry = new FlowEntry();
1349 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1350 flowEntry.setDpid(new Dpid(switchDpidStr));
1351
1352 //
1353 // Extract the match conditions
1354 //
1355 FlowEntryMatch match = new FlowEntryMatch();
1356 Short matchInPort = flowEntryObj.getMatchInPort();
1357 if (matchInPort != null)
1358 match.enableInPort(new Port(matchInPort));
1359 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1360 if (matchEthernetFrameType != null)
1361 match.enableEthernetFrameType(matchEthernetFrameType);
1362 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1363 if (matchSrcIPv4Net != null)
1364 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1365 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1366 if (matchDstIPv4Net != null)
1367 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1368 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1369 if (matchSrcMac != null)
1370 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1371 String matchDstMac = flowEntryObj.getMatchDstMac();
1372 if (matchDstMac != null)
1373 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1374 flowEntry.setFlowEntryMatch(match);
1375
1376 //
1377 // Extract the actions
1378 //
1379 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1380 Short actionOutputPort = flowEntryObj.getActionOutput();
1381 if (actionOutputPort != null) {
1382 FlowEntryAction action = new FlowEntryAction();
1383 action.setActionOutput(new Port(actionOutputPort));
1384 actions.add(action);
1385 }
1386 flowEntry.setFlowEntryActions(actions);
1387 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1388 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1389 //
1390 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1391 // and FlowEntryErrorState.
1392 //
1393 return flowEntry;
1394 }
1395
1396 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001397 * Add and maintain a shortest-path flow.
1398 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001399 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001400 *
1401 * @param flowPath the Flow Path with the endpoints and the match
1402 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001403 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001404 */
1405 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001406 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001407 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001408 // Don't do the shortest path computation here.
1409 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001410 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001411
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001412 // We need the DataPath to populate the Network MAP
1413 DataPath dataPath = new DataPath();
1414 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1415 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001416
1417 //
1418 // Prepare the computed Flow Path
1419 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001420 FlowPath computedFlowPath = new FlowPath();
1421 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1422 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1423 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001424 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001425
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001426 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001427 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001428 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001429 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001430
1431 // TODO: Mark the flow for maintenance purpose
1432
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001433 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001434 }
1435
1436 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001437 * Reconcile a flow.
1438 *
1439 * @param flowObj the flow that needs to be reconciliated.
1440 * @param newDataPath the new data path to use.
1441 * @return true on success, otherwise false.
1442 */
1443 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1444 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1445
1446 //
1447 // Set the incoming port matching and the outgoing port output
1448 // actions for each flow entry.
1449 //
1450 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1451 // Set the incoming port matching
1452 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1453 flowEntry.setFlowEntryMatch(flowEntryMatch);
1454 flowEntryMatch.enableInPort(flowEntry.inPort());
1455
1456 // Set the outgoing port output action
1457 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1458 if (flowEntryActions == null) {
1459 flowEntryActions = new ArrayList<FlowEntryAction>();
1460 flowEntry.setFlowEntryActions(flowEntryActions);
1461 }
1462 FlowEntryAction flowEntryAction = new FlowEntryAction();
1463 flowEntryAction.setActionOutput(flowEntry.outPort());
1464 flowEntryActions.add(flowEntryAction);
1465 }
1466
1467 //
1468 // Remove the old Flow Entries, and add the new Flow Entries
1469 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001470 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1471 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1472 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001473 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001474 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001475 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001476 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001477 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001478 }
1479
1480 //
1481 // Set the Data Path Summary
1482 //
1483 String dataPathSummaryStr = newDataPath.dataPathSummary();
1484 flowObj.setDataPathSummary(dataPathSummaryStr);
1485
1486 return true;
1487 }
1488
1489 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001490 * Reconcile all flows in a set.
1491 *
1492 * @param flowObjSet the set of flows that need to be reconciliated.
1493 */
1494 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1495 if (! flowObjSet.iterator().hasNext())
1496 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001497 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001498 }
1499
1500 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001501 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001502 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001503 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001504 * @param flowObj the flow path object for the flow entry to install.
1505 * @param flowEntryObj the flow entry object to install.
1506 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001507 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001508 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1509 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001510 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1511 if (flowEntryIdStr == null)
1512 return false;
1513 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001514 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001515 if (userState == null)
1516 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001517
1518 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001519 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001520 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001521 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1522 .getMessage(OFType.FLOW_MOD);
1523 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001524
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001525 short flowModCommand = OFFlowMod.OFPFC_ADD;
1526 if (userState.equals("FE_USER_ADD")) {
1527 flowModCommand = OFFlowMod.OFPFC_ADD;
1528 } else if (userState.equals("FE_USER_MODIFY")) {
1529 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1530 } else if (userState.equals("FE_USER_DELETE")) {
1531 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1532 } else {
1533 // Unknown user state. Ignore the entry
1534 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1535 flowEntryId.toString(), userState);
1536 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001537 }
1538
1539 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001540 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001541 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001542 // NOTE: The Flow matching conditions common for all Flow Entries are
1543 // used ONLY if a Flow Entry does NOT have the corresponding matching
1544 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001545 //
1546 OFMatch match = new OFMatch();
1547 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001548
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001549 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001550 Short matchInPort = flowEntryObj.getMatchInPort();
1551 if (matchInPort != null) {
1552 match.setInputPort(matchInPort);
1553 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1554 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001555
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001556 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001557 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1558 if (matchEthernetFrameType == null)
1559 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1560 if (matchEthernetFrameType != null) {
1561 match.setDataLayerType(matchEthernetFrameType);
1562 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1563 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001564
1565 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001566 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1567 if (matchSrcIPv4Net == null)
1568 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1569 if (matchSrcIPv4Net != null) {
1570 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1571 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001572
1573 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001574 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1575 if (matchDstIPv4Net == null)
1576 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1577 if (matchDstIPv4Net != null) {
1578 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1579 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001580
1581 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001582 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1583 if (matchSrcMac == null)
1584 matchSrcMac = flowObj.getMatchSrcMac();
1585 if (matchSrcMac != null) {
1586 match.setDataLayerSource(matchSrcMac);
1587 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1588 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001589
1590 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001591 String matchDstMac = flowEntryObj.getMatchDstMac();
1592 if (matchDstMac == null)
1593 matchDstMac = flowObj.getMatchDstMac();
1594 if (matchDstMac != null) {
1595 match.setDataLayerDestination(matchDstMac);
1596 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1597 }
1598
1599 //
1600 // Fetch the actions
1601 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001602 // TODO: For now we support only the "OUTPUT" actions.
1603 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001604 List<OFAction> actions = new ArrayList<OFAction>();
1605 Short actionOutputPort = flowEntryObj.getActionOutput();
1606 if (actionOutputPort != null) {
1607 OFActionOutput action = new OFActionOutput();
1608 // XXX: The max length is hard-coded for now
1609 action.setMaxLength((short)0xffff);
1610 action.setPort(actionOutputPort);
1611 actions.add(action);
1612 }
1613
1614 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1615 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1616 .setPriority(PRIORITY_DEFAULT)
1617 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1618 .setCookie(cookie)
1619 .setCommand(flowModCommand)
1620 .setMatch(match)
1621 .setActions(actions)
1622 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1623 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1624 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1625 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1626 if (actionOutputPort != null)
1627 fm.setOutPort(actionOutputPort);
1628 }
1629
1630 //
1631 // TODO: Set the following flag
1632 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1633 // See method ForwardingBase::pushRoute()
1634 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001635
1636 //
1637 // Write the message to the switch
1638 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001639 log.debug("MEASUREMENT: Installing flow entry " + userState +
1640 " into switch DPID: " +
1641 mySwitch.getStringId() +
1642 " flowEntryId: " + flowEntryId.toString() +
1643 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1644 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1645 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001646 try {
1647 messageDamper.write(mySwitch, fm, null);
1648 mySwitch.flush();
1649 //
1650 // TODO: We should use the OpenFlow Barrier mechanism
1651 // to check for errors, and update the SwitchState
1652 // for a flow entry after the Barrier message is
1653 // is received.
1654 //
1655 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1656 } catch (IOException e) {
1657 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001658 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001659 }
1660
1661 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001662 }
1663
1664 /**
1665 * Install a Flow Entry on a switch.
1666 *
1667 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001668 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001669 * @param flowEntry the flow entry to install.
1670 * @return true on success, otherwise false.
1671 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001672 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1673 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001674 //
1675 // Create the OpenFlow Flow Modification Entry to push
1676 //
1677 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1678 .getMessage(OFType.FLOW_MOD);
1679 long cookie = flowEntry.flowEntryId().value();
1680
1681 short flowModCommand = OFFlowMod.OFPFC_ADD;
1682 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1683 flowModCommand = OFFlowMod.OFPFC_ADD;
1684 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1685 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1686 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1687 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1688 } else {
1689 // Unknown user state. Ignore the entry
1690 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1691 flowEntry.flowEntryId().toString(),
1692 flowEntry.flowEntryUserState());
1693 return false;
1694 }
1695
1696 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001697 // Fetch the match conditions.
1698 //
1699 // NOTE: The Flow matching conditions common for all Flow Entries are
1700 // used ONLY if a Flow Entry does NOT have the corresponding matching
1701 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001702 //
1703 OFMatch match = new OFMatch();
1704 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001705 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1706 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1707
1708 // Match the Incoming Port
1709 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001710 if (matchInPort != null) {
1711 match.setInputPort(matchInPort.value());
1712 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1713 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001714
1715 // Match the Ethernet Frame Type
1716 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1717 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1718 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1719 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001720 if (matchEthernetFrameType != null) {
1721 match.setDataLayerType(matchEthernetFrameType);
1722 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1723 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001724
1725 // Match the Source IPv4 Network prefix
1726 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1727 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1728 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1729 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001730 if (matchSrcIPv4Net != null) {
1731 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1732 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001733
1734 // Natch the Destination IPv4 Network prefix
1735 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1736 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1737 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1738 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001739 if (matchDstIPv4Net != null) {
1740 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1741 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001742
1743 // Match the Source MAC address
1744 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1745 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1746 matchSrcMac = flowPathMatch.srcMac();
1747 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001748 if (matchSrcMac != null) {
1749 match.setDataLayerSource(matchSrcMac.toString());
1750 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1751 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001752
1753 // Match the Destination MAC address
1754 MACAddress matchDstMac = flowEntryMatch.dstMac();
1755 if ((matchDstMac == null) && (flowPathMatch != null)) {
1756 matchDstMac = flowPathMatch.dstMac();
1757 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001758 if (matchDstMac != null) {
1759 match.setDataLayerDestination(matchDstMac.toString());
1760 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1761 }
1762
1763 //
1764 // Fetch the actions
1765 //
1766 // TODO: For now we support only the "OUTPUT" actions.
1767 //
1768 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1769 List<OFAction> actions = new ArrayList<OFAction>();
1770 ArrayList<FlowEntryAction> flowEntryActions =
1771 flowEntry.flowEntryActions();
1772 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1773 FlowEntryAction.ActionOutput actionOutput =
1774 flowEntryAction.actionOutput();
1775 if (actionOutput != null) {
1776 short actionOutputPort = actionOutput.port().value();
1777 OFActionOutput action = new OFActionOutput();
1778 // XXX: The max length is hard-coded for now
1779 action.setMaxLength((short)0xffff);
1780 action.setPort(actionOutputPort);
1781 actions.add(action);
1782 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1783 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1784 fm.setOutPort(actionOutputPort);
1785 }
1786 }
1787 }
1788
1789 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1790 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1791 .setPriority(PRIORITY_DEFAULT)
1792 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1793 .setCookie(cookie)
1794 .setCommand(flowModCommand)
1795 .setMatch(match)
1796 .setActions(actions)
1797 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1798
1799 //
1800 // TODO: Set the following flag
1801 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1802 // See method ForwardingBase::pushRoute()
1803 //
1804
1805 //
1806 // Write the message to the switch
1807 //
1808 try {
1809 messageDamper.write(mySwitch, fm, null);
1810 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001811 //
1812 // TODO: We should use the OpenFlow Barrier mechanism
1813 // to check for errors, and update the SwitchState
1814 // for a flow entry after the Barrier message is
1815 // is received.
1816 //
1817 // TODO: The FlowEntry Object in Titan should be set
1818 // to FE_SWITCH_UPDATED.
1819 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001820 } catch (IOException e) {
1821 log.error("Failure writing flow mod from network map", e);
1822 return false;
1823 }
1824 return true;
1825 }
1826
1827 /**
1828 * Remove a Flow Entry from a switch.
1829 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001830 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001831 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001832 * @param flowEntry the flow entry to remove.
1833 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001834 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001835 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1836 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001837 //
1838 // The installFlowEntry() method implements both installation
1839 // and removal of flow entries.
1840 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001841 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001842 }
1843
1844 /**
1845 * Install a Flow Entry on a remote controller.
1846 *
1847 * TODO: We need it now: Jono
1848 * - For now it will make a REST call to the remote controller.
1849 * - Internally, it needs to know the name of the remote controller.
1850 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001851 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001852 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001853 * @return true on success, otherwise false.
1854 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001855 public boolean installRemoteFlowEntry(FlowPath flowPath,
1856 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001857 // TODO: We need it now: Jono
1858 // - For now it will make a REST call to the remote controller.
1859 // - Internally, it needs to know the name of the remote controller.
1860 return true;
1861 }
1862
1863 /**
1864 * Remove a flow entry on a remote controller.
1865 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001866 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001867 * @param flowEntry the flow entry to remove.
1868 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001869 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001870 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1871 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001872 //
1873 // The installRemoteFlowEntry() method implements both installation
1874 // and removal of flow entries.
1875 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001876 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001877 }
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001878
1879 /**
1880 * Store a path flow for measurement purpose.
1881 *
1882 * NOTE: The Flow Path argument does NOT contain flow entries.
1883 * The Shortest Path is computed, and the corresponding Flow Entries
1884 * are stored in the Flow Path.
1885 *
1886 * @param flowPath the Flow Path with the endpoints and the match
1887 * conditions to store.
1888 * @return the stored shortest-path flow on success, otherwise null.
1889 */
1890 @Override
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001891 public synchronized FlowPath measurementStorePathFlow(FlowPath flowPath) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001892 //
1893 // Prepare the Shortest Path computation if the first Flow Path
1894 //
1895 if (measurementStoredPaths.isEmpty())
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00001896 measurementShortestPathTopo = topoRouteService.prepareShortestPathTopo();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001897
1898 //
1899 // Compute the Shortest Path
1900 //
1901 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00001902 topoRouteService.getTopoShortestPath(measurementShortestPathTopo,
1903 flowPath.dataPath().srcPort(),
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001904 flowPath.dataPath().dstPort());
1905 if (dataPath == null) {
1906 // We need the DataPath to populate the Network MAP
1907 dataPath = new DataPath();
1908 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1909 dataPath.setDstPort(flowPath.dataPath().dstPort());
1910 }
1911
1912 //
1913 // Set the incoming port matching and the outgoing port output
1914 // actions for each flow entry.
1915 //
1916 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1917 // Set the incoming port matching
1918 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1919 flowEntry.setFlowEntryMatch(flowEntryMatch);
1920 flowEntryMatch.enableInPort(flowEntry.inPort());
1921
1922 // Set the outgoing port output action
1923 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1924 if (flowEntryActions == null) {
1925 flowEntryActions = new ArrayList<FlowEntryAction>();
1926 flowEntry.setFlowEntryActions(flowEntryActions);
1927 }
1928 FlowEntryAction flowEntryAction = new FlowEntryAction();
1929 flowEntryAction.setActionOutput(flowEntry.outPort());
1930 flowEntryActions.add(flowEntryAction);
1931 }
1932
1933 //
1934 // Prepare the computed Flow Path
1935 //
1936 FlowPath computedFlowPath = new FlowPath();
1937 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1938 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1939 computedFlowPath.setDataPath(dataPath);
1940 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
1941
1942 //
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001943 // Add the computed Flow Path to the internal storage
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001944 //
1945 measurementStoredPaths.add(computedFlowPath);
1946
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001947 log.debug("Measurement storing path {}",
1948 computedFlowPath.flowId().toString());
1949
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001950 return (computedFlowPath);
1951 }
1952
1953 /**
1954 * Install path flows for measurement purpose.
1955 *
1956 * @param numThreads the number of threads to use to install the path
1957 * flows.
1958 * @return true on success, otherwise false.
1959 */
1960 @Override
1961 public boolean measurementInstallPaths(Integer numThreads) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001962 // Create a copy of the Flow Paths to install
1963 final ConcurrentLinkedQueue<FlowPath> measurementProcessingPaths =
1964 new ConcurrentLinkedQueue<FlowPath>(measurementStoredPaths);
1965
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00001966 /**
1967 * A Thread-wrapper class for executing the threads and collecting
1968 * the measurement data.
1969 */
1970 class MyThread extends Thread {
1971 public long[] execTime = new long[2000];
1972 public int samples = 0;
1973 public int threadId = -1;
1974 @Override
1975 public void run() {
1976 while (true) {
1977 FlowPath flowPath = measurementProcessingPaths.poll();
1978 if (flowPath == null)
1979 return;
1980 // Install the Flow Path
1981 FlowId flowId = new FlowId();
1982 String dataPathSummaryStr =
1983 flowPath.dataPath().dataPathSummary();
1984 long startTime = System.nanoTime();
1985 addFlow(flowPath, flowId, dataPathSummaryStr);
1986 long endTime = System.nanoTime();
1987 execTime[samples] = endTime - startTime;
1988 samples++;
1989 }
1990 }
1991 };
1992
1993 List<MyThread> threads = new LinkedList<MyThread>();
1994
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001995 log.debug("Measurement Installing {} flows",
1996 measurementProcessingPaths.size());
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00001997
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001998 //
1999 // Create the threads to install the Flow Paths
2000 //
2001 for (int i = 0; i < numThreads; i++) {
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002002 MyThread thread = new MyThread();
2003 thread.threadId = i;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002004 threads.add(thread);
2005 }
2006
2007 //
2008 // Start processing
2009 //
2010 measurementEndTimeProcessingPaths = 0;
2011 measurementStartTimeProcessingPaths = System.nanoTime();
2012 for (Thread thread : threads) {
2013 thread.start();
2014 }
2015
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002016 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002017 for (Thread thread : threads) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002018 try {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002019 thread.join();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002020 } catch (InterruptedException e) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002021 log.debug("Exception waiting for a thread to install a Flow Path: ", e);
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002022 }
2023 }
2024
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002025 // Record the end of processing
2026 measurementEndTimeProcessingPaths = System.nanoTime();
2027
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002028 //
2029 // Prepare the string with measurement data per each Flow Path
2030 // installation.
2031 // The string is multiple lines: one line per Flow Path installation:
2032 // ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2033 //
2034 measurementPerFlowStr = new String();
2035 String eol = System.getProperty("line.separator");
2036 for (MyThread thread : threads) {
2037 for (int i = 0; i < thread.samples; i++) {
2038 measurementPerFlowStr += "ThreadAndTimePerFlow " + thread.threadId + " " + numThreads + " " + thread.execTime[i] + eol;
2039 }
2040 }
2041
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002042 return true;
2043 }
2044
2045 /**
2046 * Get the measurement time that took to install the path flows.
2047 *
2048 * @return the measurement time (in nanoseconds) it took to install
2049 * the path flows.
2050 */
2051 @Override
2052 public Long measurementGetInstallPathsTimeNsec() {
2053 return new Long(measurementEndTimeProcessingPaths -
2054 measurementStartTimeProcessingPaths);
2055 }
2056
2057 /**
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002058 * Get the measurement install time per Flow.
2059 *
2060 * @return a multi-line string with the following format per line:
2061 * ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2062 */
2063 @Override
2064 public String measurementGetPerFlowInstallTime() {
2065 return new String(measurementPerFlowStr);
2066 }
2067
2068 /**
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002069 * Clear the path flows stored for measurement purpose.
2070 *
2071 * @return true on success, otherwise false.
2072 */
2073 @Override
2074 public boolean measurementClearAllPaths() {
2075 measurementStoredPaths.clear();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002076 topoRouteService.dropShortestPathTopo(measurementShortestPathTopo);
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002077 measurementStartTimeProcessingPaths = 0;
2078 measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002079 measurementPerFlowStr = new String();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002080
2081 return true;
2082 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002083}