blob: 251620ccdc71d27ef683207e67e48ffd93feaaf1 [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 Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07006import java.util.Collections;
7import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000010import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000013import java.util.Random;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
15import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080017
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import net.floodlightcontroller.core.IFloodlightProviderService;
19import net.floodlightcontroller.core.INetMapStorage;
20import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
21import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070022import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070023import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070024import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080025import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080026import net.floodlightcontroller.core.module.FloodlightModuleContext;
27import net.floodlightcontroller.core.module.FloodlightModuleException;
28import net.floodlightcontroller.core.module.IFloodlightModule;
29import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080030import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
31import net.floodlightcontroller.restserver.IRestApiService;
32import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080034import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070035import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070037import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070039import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080040import net.floodlightcontroller.util.FlowEntrySwitchState;
41import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080042import net.floodlightcontroller.util.FlowId;
43import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.IPv4Net;
45import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.OFMessageDamper;
47import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070048import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.onrc.onos.util.GraphDBConnection;
50import net.onrc.onos.util.GraphDBConnection.Transaction;
51
52import org.openflow.protocol.OFFlowMod;
53import org.openflow.protocol.OFMatch;
54import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070055import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import org.openflow.protocol.OFType;
57import org.openflow.protocol.action.OFAction;
58import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
Jonathan Hartf5315fb2013-04-05 11:41:56 -070062
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070063public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080064
65 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066
67 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070068 protected volatile IFloodlightProviderService floodlightProvider;
69 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070070 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 protected OFMessageDamper messageDamper;
73
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070074 //
75 // TODO: Values copied from elsewhere (class LearningSwitch).
76 // The local copy should go away!
77 //
78 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
79 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
80 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
81 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
82 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080083
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000084 // Flow Entry ID generation state
85 private static Random randomGenerator = new Random();
86 private static int nextFlowEntryIdPrefix = 0;
87 private static int nextFlowEntryIdSuffix = 0;
88 private static long nextFlowEntryId = 0;
89
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070090 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070091 private static long measurementFlowId = 100000;
92 private static String measurementFlowIdStr = "0x186a0"; // 100000
93 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070094 //
95 private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
96 private LinkedList<FlowPath> measurementProcessingPaths = null;
97 private long measurementStartTimeProcessingPaths = 0;
98 private long measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070099
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800100 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800101 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
102
103 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700104 private ScheduledExecutorService mapReaderScheduler;
105 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700106
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700107 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800108 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700109 try {
110 runImpl();
111 } catch (Exception e) {
112 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
113 conn.endTx(Transaction.ROLLBACK);
114 return;
115 }
116 }
117
118 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700119 long startTime = System.nanoTime();
120 int counterAllFlowEntries = 0;
121 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700122
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800123 if (floodlightProvider == null) {
124 log.debug("FloodlightProvider service not found!");
125 return;
126 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000127 Map<Long, IOFSwitch> mySwitches =
128 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700129 LinkedList<IFlowEntry> addFlowEntries =
130 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000131 LinkedList<IFlowEntry> deleteFlowEntries =
132 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700133
134 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700135 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700136 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700137 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700138 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139 Iterable<IFlowEntry> allFlowEntries =
Pankaj Berded1c38592013-04-10 22:46:40 -0700140 conn.utils().getAllSwitchNotUpdatedFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700141 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700142 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000143
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000144 String dpidStr = flowEntryObj.getSwitchDpid();
145 if (dpidStr == null)
146 continue;
147 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800148 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000149 if (mySwitch == null)
150 continue; // Ignore the entry: not my switch
151
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700152 IFlowPath flowObj =
153 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
154 if (flowObj == null)
155 continue; // Should NOT happen
156 if (flowObj.getFlowId() == null)
157 continue; // Invalid entry
158
159 //
160 // NOTE: For now we process the DELETE before the ADD
161 // to cover the more common scenario.
162 // TODO: This is error prone and needs to be fixed!
163 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000164 String userState = flowEntryObj.getUserState();
165 if (userState == null)
166 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700167 if (userState.equals("FE_USER_DELETE")) {
168 // An entry that needs to be deleted.
169 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700170 installFlowEntry(mySwitch, flowObj, flowEntryObj);
171 } else {
172 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700173 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700174 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700176 // TODO: Commented-out for now
177 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700178 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700179 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700180 processed_measurement_flow = true;
181 }
182 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700183 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700184 }
185
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700186 //
187 // Process the Flow Entries that need to be added
188 //
189 for (IFlowEntry flowEntryObj : addFlowEntries) {
190 IFlowPath flowObj =
191 conn.utils().getFlowPathByFlowEntry(conn,
192 flowEntryObj);
193 if (flowObj == null)
194 continue; // Should NOT happen
195 if (flowObj.getFlowId() == null)
196 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700197
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700198 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700199 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200 if (mySwitch == null)
201 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700202 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800203 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204
205 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000206 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700207 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000208 //
209 // TODO: We should use the OpenFlow Barrier mechanism
210 // to check for errors, and delete the Flow Entries after the
211 // Barrier message is received.
212 //
213 while (! deleteFlowEntries.isEmpty()) {
214 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
215 IFlowPath flowObj =
216 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
217 if (flowObj == null) {
218 log.debug("Did not find FlowPath to be deleted");
219 continue;
220 }
221 flowObj.removeFlowEntry(flowEntryObj);
222 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000223 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700224
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700225 conn.endTx(Transaction.COMMIT);
226
227 if (processed_measurement_flow) {
228 long estimatedTime =
229 System.nanoTime() - modifiedMeasurementFlowTime;
230 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
231 (double)estimatedTime / 1000000000 + " sec";
232 log.debug(logMsg);
233 }
234
235 long estimatedTime = System.nanoTime() - startTime;
236 double rate = 0.0;
237 if (estimatedTime > 0)
238 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
239 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
240 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
241 counterMyNotUpdatedFlowEntries + " in " +
242 (double)estimatedTime / 1000000000 + " sec: " +
243 rate + " paths/s";
244 log.debug(logMsg);
245 }
246 };
247
248 final Runnable shortestPathReconcile = new Runnable() {
249 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700250 try {
251 runImpl();
252 } catch (Exception e) {
253 log.debug("Exception processing All Flows from the Network MAP: ", e);
254 conn.endTx(Transaction.ROLLBACK);
255 return;
256 }
257 }
258
259 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700260 long startTime = System.nanoTime();
261 int counterAllFlowPaths = 0;
262 int counterMyFlowPaths = 0;
263
264 if (floodlightProvider == null) {
265 log.debug("FloodlightProvider service not found!");
266 return;
267 }
268 Map<Long, IOFSwitch> mySwitches =
269 floodlightProvider.getSwitches();
270 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
271
272 boolean processed_measurement_flow = false;
273
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700274 //
275 // Fetch and recompute the Shortest Path for those
276 // Flow Paths this controller is responsible for.
277 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700278 topoRouteService.prepareShortestPathTopo();
279 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700280 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700281 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700282 if (flowPathObj == null)
283 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700284
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700285 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000286 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700287 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700288 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700289 //
290 // Use the source DPID as a heuristic to decide
291 // which controller is responsible for maintaining the
292 // shortest path.
293 // NOTE: This heuristic is error-prone: if the switch
294 // goes away and no controller is responsible for that
295 // switch, then the original Flow Path is not cleaned-up
296 //
297 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
298 if (mySwitch == null)
299 continue; // Ignore: not my responsibility
300
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700301 // Test the Data Path Summary string
302 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
303 if (dataPathSummaryStr == null)
304 continue; // Could be invalid entry?
305 if (dataPathSummaryStr.isEmpty())
306 continue; // No need to maintain this flow
307
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000308 //
309 // Test whether we need to complete the Flow cleanup,
310 // if the Flow has been deleted by the user.
311 //
312 String flowUserState = flowPathObj.getUserState();
313 if ((flowUserState != null)
314 && flowUserState.equals("FE_USER_DELETE")) {
315 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
316 boolean empty = true; // TODO: an ugly hack
317 for (IFlowEntry flowEntryObj : flowEntries) {
318 empty = false;
319 break;
320 }
321 if (empty)
322 deleteFlows.add(flowPathObj);
323 }
324
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000325 // Fetch the fields needed to recompute the shortest path
326 Short srcPortShort = flowPathObj.getSrcPort();
327 String dstDpidStr = flowPathObj.getDstSwitch();
328 Short dstPortShort = flowPathObj.getDstPort();
329 if ((srcPortShort == null) ||
330 (dstDpidStr == null) ||
331 (dstPortShort == null)) {
332 continue;
333 }
334
335 Port srcPort = new Port(srcPortShort);
336 Dpid dstDpid = new Dpid(dstDpidStr);
337 Port dstPort = new Port(dstPortShort);
338 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
339 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
340
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700341 counterMyFlowPaths++;
342
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700343 //
344 // NOTE: Using here the regular getShortestPath() method
345 // won't work here, because that method calls internally
346 // "conn.endTx(Transaction.COMMIT)", and that will
347 // invalidate all handlers to the Titan database.
348 // If we want to experiment with calling here
349 // getShortestPath(), we need to refactor that code
350 // to avoid closing the transaction.
351 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700352 DataPath dataPath =
353 topoRouteService.getTopoShortestPath(srcSwitchPort,
354 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000355 if (dataPath == null) {
356 // We need the DataPath to compare the paths
357 dataPath = new DataPath();
358 dataPath.setSrcPort(srcSwitchPort);
359 dataPath.setDstPort(dstSwitchPort);
360 }
361
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700362 String newDataPathSummaryStr = dataPath.dataPathSummary();
363 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
364 continue; // Nothing changed
365
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700366 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700367 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000368
369 //
370 // Delete all leftover Flows marked for deletion from the
371 // Network MAP.
372 //
373 while (! deleteFlows.isEmpty()) {
374 IFlowPath flowPathObj = deleteFlows.poll();
375 conn.utils().removeFlowPath(conn, flowPathObj);
376 }
377
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700378 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700379
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800380 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700381
382 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700383 long estimatedTime =
384 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700385 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
386 (double)estimatedTime / 1000000000 + " sec";
387 log.debug(logMsg);
388 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700389
390 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700391 double rate = 0.0;
392 if (estimatedTime > 0)
393 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700394 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700395 counterAllFlowPaths + " MyFlowPaths: " +
396 counterMyFlowPaths + " in " +
397 (double)estimatedTime / 1000000000 + " sec: " +
398 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700399 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800400 }
401 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700402
Jonathan Hart50a94982013-04-10 14:49:51 -0700403 //final ScheduledFuture<?> mapReaderHandle =
404 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800405
Jonathan Hart50a94982013-04-10 14:49:51 -0700406 //final ScheduledFuture<?> shortestPathReconcileHandle =
407 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700408
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800409 @Override
410 public void init(String conf) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700411 conn = GraphDBConnection.getInstance(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800412 }
413
414 public void finalize() {
415 close();
416 }
417
418 @Override
419 public void close() {
420 conn.close();
421 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800422
423 @Override
424 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
425 Collection<Class<? extends IFloodlightService>> l =
426 new ArrayList<Class<? extends IFloodlightService>>();
427 l.add(IFlowService.class);
428 return l;
429 }
430
431 @Override
432 public Map<Class<? extends IFloodlightService>, IFloodlightService>
433 getServiceImpls() {
434 Map<Class<? extends IFloodlightService>,
435 IFloodlightService> m =
436 new HashMap<Class<? extends IFloodlightService>,
437 IFloodlightService>();
438 m.put(IFlowService.class, this);
439 return m;
440 }
441
442 @Override
443 public Collection<Class<? extends IFloodlightService>>
444 getModuleDependencies() {
445 Collection<Class<? extends IFloodlightService>> l =
446 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700448 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800449 l.add(IRestApiService.class);
450 return l;
451 }
452
453 @Override
454 public void init(FloodlightModuleContext context)
455 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700456 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800457 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700458 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800459 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800460 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
461 EnumSet.of(OFType.FLOW_MOD),
462 OFMESSAGE_DAMPER_TIMEOUT);
463 // TODO: An ugly hack!
464 String conf = "/tmp/cassandra.titan";
465 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700466
467 mapReaderScheduler = Executors.newScheduledThreadPool(1);
468 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800469 }
470
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700471 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000472 //
473 // Generate the next Flow Entry ID.
474 // NOTE: For now, the higher 32 bits are random, and
475 // the lower 32 bits are sequential.
476 // In the future, we need a better allocation mechanism.
477 //
478 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
479 nextFlowEntryIdPrefix = randomGenerator.nextInt();
480 nextFlowEntryIdSuffix = 0;
481 } else {
482 nextFlowEntryIdSuffix++;
483 }
484 long result = (long)nextFlowEntryIdPrefix << 32;
485 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
486 return result;
487 }
488
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800489 @Override
490 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700491 restApi.addRestletRoutable(new FlowWebRoutable());
492
493 // Initialize the Flow Entry ID generator
494 nextFlowEntryIdPrefix = randomGenerator.nextInt();
495
496 mapReaderScheduler.scheduleAtFixedRate(
Pankaj Berde55f121a2013-04-23 15:42:54 -0700497 mapReader, 1, 1, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700498 shortestPathReconcileScheduler.scheduleAtFixedRate(
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700499 shortestPathReconcile, 100, 100, TimeUnit.MILLISECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800500 }
501
502 /**
503 * Add a flow.
504 *
505 * Internally, ONOS will automatically register the installer for
506 * receiving Flow Path Notifications for that path.
507 *
508 * @param flowPath the Flow Path to install.
509 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700510 * @param dataPathSummaryStr the data path summary string if the added
511 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800512 * @return true on success, otherwise false.
513 */
514 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700515 public boolean addFlow(FlowPath flowPath, FlowId flowId,
516 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700517 /*
518 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700519 if (flowPath.flowId().value() == measurementFlowId) {
520 modifiedMeasurementFlowTime = System.nanoTime();
521 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700522 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800523
524 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000525 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800526 try {
527 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
528 != null) {
529 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
530 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000531 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800532 } else {
533 flowObj = conn.utils().newFlowPath(conn);
534 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
535 flowPath.flowId().toString());
536 }
537 } catch (Exception e) {
538 // TODO: handle exceptions
539 conn.endTx(Transaction.ROLLBACK);
540 log.error(":addFlow FlowId:{} failed",
541 flowPath.flowId().toString());
542 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700543 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000544 log.error(":addFlow FlowId:{} failed: Flow object not created",
545 flowPath.flowId().toString());
546 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800547 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700548 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800549
550 //
551 // Set the Flow key:
552 // - flowId
553 //
554 flowObj.setFlowId(flowPath.flowId().toString());
555 flowObj.setType("flow");
556
557 //
558 // Set the Flow attributes:
559 // - flowPath.installerId()
560 // - flowPath.dataPath().srcPort()
561 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700562 // - flowPath.matchEthernetFrameType()
563 // - flowPath.matchSrcIPv4Net()
564 // - flowPath.matchDstIPv4Net()
565 // - flowPath.matchSrcMac()
566 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800567 //
568 flowObj.setInstallerId(flowPath.installerId().toString());
569 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
570 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
571 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
572 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700573 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
574 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
575 }
576 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
577 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
578 }
579 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
580 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
581 }
582 if (flowPath.flowEntryMatch().matchSrcMac()) {
583 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
584 }
585 if (flowPath.flowEntryMatch().matchDstMac()) {
586 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
587 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800588
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700589 if (dataPathSummaryStr != null) {
590 flowObj.setDataPathSummary(dataPathSummaryStr);
591 } else {
592 flowObj.setDataPathSummary("");
593 }
594
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000595 if (found)
596 flowObj.setUserState("FE_USER_MODIFY");
597 else
598 flowObj.setUserState("FE_USER_ADD");
599
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800600 // Flow edges:
601 // HeadFE
602
603
604 //
605 // Flow Entries:
606 // flowPath.dataPath().flowEntries()
607 //
608 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700609 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000610 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800611 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700612 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800613 }
614 conn.endTx(Transaction.COMMIT);
615
616 //
617 // TODO: We need a proper Flow ID allocation mechanism.
618 //
619 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700620
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800621 return true;
622 }
623
624 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700625 * Add a flow entry to the Network MAP.
626 *
627 * @param flowObj the corresponding Flow Path object for the Flow Entry.
628 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700629 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700630 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700631 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700632 // Flow edges
633 // HeadFE (TODO)
634
635 //
636 // Assign the FlowEntry ID.
637 //
638 if ((flowEntry.flowEntryId() == null) ||
639 (flowEntry.flowEntryId().value() == 0)) {
640 long id = getNextFlowEntryId();
641 flowEntry.setFlowEntryId(new FlowEntryId(id));
642 }
643
644 IFlowEntry flowEntryObj = null;
645 boolean found = false;
646 try {
647 if ((flowEntryObj =
648 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
649 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
650 flowEntry.flowEntryId().toString());
651 found = true;
652 } else {
653 flowEntryObj = conn.utils().newFlowEntry(conn);
654 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
655 flowEntry.flowEntryId().toString());
656 }
657 } catch (Exception e) {
658 log.error(":addFlow FlowEntryId:{} failed",
659 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700660 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700661 }
662 if (flowEntryObj == null) {
663 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
664 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700665 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700666 }
667
668 //
669 // Set the Flow Entry key:
670 // - flowEntry.flowEntryId()
671 //
672 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
673 flowEntryObj.setType("flow_entry");
674
675 //
676 // Set the Flow Entry Edges and attributes:
677 // - Switch edge
678 // - InPort edge
679 // - OutPort edge
680 //
681 // - flowEntry.flowEntryMatch()
682 // - flowEntry.flowEntryActions()
683 // - flowEntry.dpid()
684 // - flowEntry.flowEntryUserState()
685 // - flowEntry.flowEntrySwitchState()
686 // - flowEntry.flowEntryErrorState()
687 // - flowEntry.matchInPort()
688 // - flowEntry.matchEthernetFrameType()
689 // - flowEntry.matchSrcIPv4Net()
690 // - flowEntry.matchDstIPv4Net()
691 // - flowEntry.matchSrcMac()
692 // - flowEntry.matchDstMac()
693 // - flowEntry.actionOutput()
694 //
695 ISwitchObject sw =
696 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
697 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
698 flowEntryObj.setSwitch(sw);
699 if (flowEntry.flowEntryMatch().matchInPort()) {
700 IPortObject inport =
701 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
702 flowEntry.flowEntryMatch().inPort().value());
703 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
704 flowEntryObj.setInPort(inport);
705 }
706 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
707 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
708 }
709 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
710 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
711 }
712 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
713 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
714 }
715 if (flowEntry.flowEntryMatch().matchSrcMac()) {
716 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
717 }
718 if (flowEntry.flowEntryMatch().matchDstMac()) {
719 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
720 }
721
722 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
723 if (fa.actionOutput() != null) {
724 IPortObject outport =
725 conn.utils().searchPort(conn,
726 flowEntry.dpid().toString(),
727 fa.actionOutput().port().value());
728 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
729 flowEntryObj.setOutPort(outport);
730 }
731 }
732 // TODO: Hacks with hard-coded state names!
733 if (found)
734 flowEntryObj.setUserState("FE_USER_MODIFY");
735 else
736 flowEntryObj.setUserState("FE_USER_ADD");
737 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
738 //
739 // TODO: Take care of the FlowEntryErrorState.
740 //
741
742 // Flow Entries edges:
743 // Flow
744 // NextFE (TODO)
745 if (! found) {
746 flowObj.addFlowEntry(flowEntryObj);
747 flowEntryObj.setFlow(flowObj);
748 }
749
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700750 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700751 }
752
753 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000754 * Delete all previously added flows.
755 *
756 * @return true on success, otherwise false.
757 */
758 @Override
759 public boolean deleteAllFlows() {
760
761 // Get all flows and delete them one-by-one
762 ArrayList<FlowPath> allFlows = getAllFlows();
763 for (FlowPath flowPath : allFlows) {
764 deleteFlow(flowPath.flowId());
765 }
766
767 return true;
768 }
769
770 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800771 * Delete a previously added flow.
772 *
773 * @param flowId the Flow ID of the flow to delete.
774 * @return true on success, otherwise false.
775 */
776 @Override
777 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700778 /*
779 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700780 if (flowId.value() == measurementFlowId) {
781 modifiedMeasurementFlowTime = System.nanoTime();
782 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700783 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700784
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800785 IFlowPath flowObj = null;
786 //
787 // We just mark the entries for deletion,
788 // and let the switches remove each individual entry after
789 // it has been removed from the switches.
790 //
791 try {
792 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
793 != null) {
794 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
795 flowId.toString());
796 } else {
797 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
798 flowId.toString());
799 }
800 } catch (Exception e) {
801 // TODO: handle exceptions
802 conn.endTx(Transaction.ROLLBACK);
803 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
804 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700805 if (flowObj == null) {
806 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800807 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700808 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800809
810 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000811 // Find and mark for deletion all Flow Entries,
812 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800813 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000814 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800815 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
816 boolean empty = true; // TODO: an ugly hack
817 for (IFlowEntry flowEntryObj : flowEntries) {
818 empty = false;
819 // flowObj.removeFlowEntry(flowEntryObj);
820 // conn.utils().removeFlowEntry(conn, flowEntryObj);
821 flowEntryObj.setUserState("FE_USER_DELETE");
822 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
823 }
824 // Remove from the database empty flows
825 if (empty)
826 conn.utils().removeFlowPath(conn, flowObj);
827 conn.endTx(Transaction.COMMIT);
828
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800829 return true;
830 }
831
832 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000833 * Clear the state for all previously added flows.
834 *
835 * @return true on success, otherwise false.
836 */
837 @Override
838 public boolean clearAllFlows() {
839
840 // Get all flows and clear them one-by-one
841 ArrayList<FlowPath> allFlows = getAllFlows();
842 for (FlowPath flowPath : allFlows) {
843 clearFlow(flowPath.flowId());
844 }
845
846 return true;
847 }
848
849 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700850 * Clear the state for a previously added flow.
851 *
852 * @param flowId the Flow ID of the flow to clear.
853 * @return true on success, otherwise false.
854 */
855 @Override
856 public boolean clearFlow(FlowId flowId) {
857 IFlowPath flowObj = null;
858 try {
859 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
860 != null) {
861 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
862 flowId.toString());
863 } else {
864 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
865 flowId.toString());
866 }
867 } catch (Exception e) {
868 // TODO: handle exceptions
869 conn.endTx(Transaction.ROLLBACK);
870 log.error(":clearFlow FlowId:{} failed", flowId.toString());
871 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700872 if (flowObj == null) {
873 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700874 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700875 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700876
877 //
878 // Remove all Flow Entries
879 //
880 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
881 for (IFlowEntry flowEntryObj : flowEntries) {
882 flowObj.removeFlowEntry(flowEntryObj);
883 conn.utils().removeFlowEntry(conn, flowEntryObj);
884 }
885 // Remove the Flow itself
886 conn.utils().removeFlowPath(conn, flowObj);
887 conn.endTx(Transaction.COMMIT);
888
889 return true;
890 }
891
892 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800893 * Get a previously added flow.
894 *
895 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800896 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800897 */
898 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800899 public FlowPath getFlow(FlowId flowId) {
900 IFlowPath flowObj = null;
901 try {
902 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
903 != null) {
904 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
905 flowId.toString());
906 } else {
907 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
908 flowId.toString());
909 }
910 } catch (Exception e) {
911 // TODO: handle exceptions
912 conn.endTx(Transaction.ROLLBACK);
913 log.error(":getFlow FlowId:{} failed", flowId.toString());
914 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700915 if (flowObj == null) {
916 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800917 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700918 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800919
920 //
921 // Extract the Flow state
922 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800923 FlowPath flowPath = extractFlowPath(flowObj);
924 conn.endTx(Transaction.COMMIT);
925
926 return flowPath;
927 }
928
929 /**
930 * Get all previously added flows by a specific installer for a given
931 * data path endpoints.
932 *
933 * @param installerId the Caller ID of the installer of the flow to get.
934 * @param dataPathEndpoints the data path endpoints of the flow to get.
935 * @return the Flow Paths if found, otherwise null.
936 */
937 @Override
938 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
939 DataPathEndpoints dataPathEndpoints) {
940 //
941 // TODO: The implementation below is not optimal:
942 // We fetch all flows, and then return only the subset that match
943 // the query conditions.
944 // We should use the appropriate Titan/Gremlin query to filter-out
945 // the flows as appropriate.
946 //
947 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700948 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800949
950 if (allFlows == null) {
951 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700952 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800953 }
954
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800955 for (FlowPath flow : allFlows) {
956 //
957 // TODO: String-based comparison is sub-optimal.
958 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800959 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800960 //
961 if (! flow.installerId().toString().equals(installerId.toString()))
962 continue;
963 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
964 continue;
965 }
966 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
967 continue;
968 }
969 flowPaths.add(flow);
970 }
971
972 if (flowPaths.isEmpty()) {
973 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800974 } else {
975 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
976 }
977
978 return flowPaths;
979 }
980
981 /**
982 * Get all installed flows by all installers for given data path endpoints.
983 *
984 * @param dataPathEndpoints the data path endpoints of the flows to get.
985 * @return the Flow Paths if found, otherwise null.
986 */
987 @Override
988 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
989 //
990 // TODO: The implementation below is not optimal:
991 // We fetch all flows, and then return only the subset that match
992 // the query conditions.
993 // We should use the appropriate Titan/Gremlin query to filter-out
994 // the flows as appropriate.
995 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700996 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
997 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800998
999 if (allFlows == null) {
1000 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001001 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001002 }
1003
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001004 for (FlowPath flow : allFlows) {
1005 //
1006 // TODO: String-based comparison is sub-optimal.
1007 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001008 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001009 //
1010 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1011 continue;
1012 }
1013 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1014 continue;
1015 }
1016 flowPaths.add(flow);
1017 }
1018
1019 if (flowPaths.isEmpty()) {
1020 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001021 } else {
1022 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1023 }
1024
1025 return flowPaths;
1026 }
1027
1028 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001029 * Get summary of all installed flows by all installers in a given range
1030 *
1031 * @param flowId the data path endpoints of the flows to get.
1032 * @param maxFlows: the maximum number of flows to be returned
1033 * @return the Flow Paths if found, otherwise null.
1034 */
1035 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001036 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001037
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001038 // TODO: The implementation below is not optimal:
1039 // We fetch all flows, and then return only the subset that match
1040 // the query conditions.
1041 // We should use the appropriate Titan/Gremlin query to filter-out
1042 // the flows as appropriate.
1043 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001044 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001045
Jonathan Hart01f2d272013-04-04 20:03:46 -07001046 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1047
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001048 Collections.sort(flowPathsWithoutFlowEntries,
1049 new Comparator<IFlowPath>(){
1050 @Override
1051 public int compare(IFlowPath first, IFlowPath second) {
1052 // TODO Auto-generated method stub
1053 long result = new FlowId(first.getFlowId()).value()
1054 - new FlowId(second.getFlowId()).value();
1055 if (result > 0) return 1;
1056 else if (result < 0) return -1;
1057 else return 0;
1058 }
1059 }
1060 );
1061
Jonathan Hart01f2d272013-04-04 20:03:46 -07001062 return flowPathsWithoutFlowEntries;
1063
1064 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001065 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001066
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001067 if (allFlows == null) {
1068 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001069 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001070 }
1071
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001072 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001073
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001074 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001075 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001076
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001077 // start from desired flowId
1078 if (flow.flowId().value() < flowId.value()) {
1079 continue;
1080 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001081
1082 // Summarize by making null flow entry fields that are not relevant to report
1083 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1084 flowEntry.setFlowEntryActions(null);
1085 flowEntry.setFlowEntryMatch(null);
1086 }
1087
1088 flowPaths.add(flow);
1089 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1090 break;
1091 }
1092 }
1093
1094 if (flowPaths.isEmpty()) {
1095 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001096 } else {
1097 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1098 }
1099
1100 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001101 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001102 }
1103
1104 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001105 * Get all installed flows by all installers.
1106 *
1107 * @return the Flow Paths if found, otherwise null.
1108 */
1109 @Override
1110 public ArrayList<FlowPath> getAllFlows() {
1111 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001112 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001113
1114 try {
1115 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1116 log.debug("Get all FlowPaths: found FlowPaths");
1117 } else {
1118 log.debug("Get all FlowPaths: no FlowPaths found");
1119 }
1120 } catch (Exception e) {
1121 // TODO: handle exceptions
1122 conn.endTx(Transaction.ROLLBACK);
1123 log.error(":getAllFlowPaths failed");
1124 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001125 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1126 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001127 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001128 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001129
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001130 for (IFlowPath flowObj : flowPathsObj) {
1131 //
1132 // Extract the Flow state
1133 //
1134 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001135 if (flowPath != null)
1136 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001137 }
1138
1139 conn.endTx(Transaction.COMMIT);
1140
1141 return flowPaths;
1142 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001143
1144 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1145 Iterable<IFlowPath> flowPathsObj = null;
1146 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1147 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1148
Jonathan Harte6e91872013-04-13 11:10:32 -07001149 conn.endTx(Transaction.COMMIT);
1150
Jonathan Hart01f2d272013-04-04 20:03:46 -07001151 try {
1152 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1153 log.debug("Get all FlowPaths: found FlowPaths");
1154 } else {
1155 log.debug("Get all FlowPaths: no FlowPaths found");
1156 }
1157 } catch (Exception e) {
1158 // TODO: handle exceptions
1159 conn.endTx(Transaction.ROLLBACK);
1160 log.error(":getAllFlowPaths failed");
1161 }
1162 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1163 return new ArrayList<IFlowPath>(); // No Flows found
1164 }
1165
1166 for (IFlowPath flowObj : flowPathsObj){
1167 flowPathsObjArray.add(flowObj);
1168 }
1169 /*
1170 for (IFlowPath flowObj : flowPathsObj) {
1171 //
1172 // Extract the Flow state
1173 //
1174 FlowPath flowPath = extractFlowPath(flowObj);
1175 if (flowPath != null)
1176 flowPaths.add(flowPath);
1177 }
1178 */
1179
1180 //conn.endTx(Transaction.COMMIT);
1181
1182 return flowPathsObjArray;
1183 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001184
1185 /**
1186 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1187 *
1188 * @param flowObj the object to extract the Flow Path State from.
1189 * @return the extracted Flow Path State.
1190 */
1191 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001192 //
1193 // Extract the Flow state
1194 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001195 String flowIdStr = flowObj.getFlowId();
1196 String installerIdStr = flowObj.getInstallerId();
1197 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001198 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001199 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001200 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001201
1202 if ((flowIdStr == null) ||
1203 (installerIdStr == null) ||
1204 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001205 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001206 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001207 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001208 // TODO: A work-around, becauuse of some bogus database objects
1209 return null;
1210 }
1211
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001212 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001213 flowPath.setFlowId(new FlowId(flowIdStr));
1214 flowPath.setInstallerId(new CallerId(installerIdStr));
1215 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001216 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001217 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001218 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001219 //
1220 // Extract the match conditions common for all Flow Entries
1221 //
1222 {
1223 FlowEntryMatch match = new FlowEntryMatch();
1224 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1225 if (matchEthernetFrameType != null)
1226 match.enableEthernetFrameType(matchEthernetFrameType);
1227 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1228 if (matchSrcIPv4Net != null)
1229 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1230 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1231 if (matchDstIPv4Net != null)
1232 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1233 String matchSrcMac = flowObj.getMatchSrcMac();
1234 if (matchSrcMac != null)
1235 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1236 String matchDstMac = flowObj.getMatchDstMac();
1237 if (matchDstMac != null)
1238 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1239 flowPath.setFlowEntryMatch(match);
1240 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001241
1242 //
1243 // Extract all Flow Entries
1244 //
1245 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1246 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001247 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1248 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001249 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001250 flowPath.dataPath().flowEntries().add(flowEntry);
1251 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001252
1253 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001254 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001255
1256 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001257 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1258 *
1259 * @param flowEntryObj the object to extract the Flow Entry State from.
1260 * @return the extracted Flow Entry State.
1261 */
1262 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1263 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1264 String switchDpidStr = flowEntryObj.getSwitchDpid();
1265 String userState = flowEntryObj.getUserState();
1266 String switchState = flowEntryObj.getSwitchState();
1267
1268 if ((flowEntryIdStr == null) ||
1269 (switchDpidStr == null) ||
1270 (userState == null) ||
1271 (switchState == null)) {
1272 // TODO: A work-around, becauuse of some bogus database objects
1273 return null;
1274 }
1275
1276 FlowEntry flowEntry = new FlowEntry();
1277 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1278 flowEntry.setDpid(new Dpid(switchDpidStr));
1279
1280 //
1281 // Extract the match conditions
1282 //
1283 FlowEntryMatch match = new FlowEntryMatch();
1284 Short matchInPort = flowEntryObj.getMatchInPort();
1285 if (matchInPort != null)
1286 match.enableInPort(new Port(matchInPort));
1287 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1288 if (matchEthernetFrameType != null)
1289 match.enableEthernetFrameType(matchEthernetFrameType);
1290 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1291 if (matchSrcIPv4Net != null)
1292 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1293 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1294 if (matchDstIPv4Net != null)
1295 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1296 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1297 if (matchSrcMac != null)
1298 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1299 String matchDstMac = flowEntryObj.getMatchDstMac();
1300 if (matchDstMac != null)
1301 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1302 flowEntry.setFlowEntryMatch(match);
1303
1304 //
1305 // Extract the actions
1306 //
1307 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1308 Short actionOutputPort = flowEntryObj.getActionOutput();
1309 if (actionOutputPort != null) {
1310 FlowEntryAction action = new FlowEntryAction();
1311 action.setActionOutput(new Port(actionOutputPort));
1312 actions.add(action);
1313 }
1314 flowEntry.setFlowEntryActions(actions);
1315 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1316 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1317 //
1318 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1319 // and FlowEntryErrorState.
1320 //
1321 return flowEntry;
1322 }
1323
1324 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001325 * Add and maintain a shortest-path flow.
1326 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001327 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001328 *
1329 * @param flowPath the Flow Path with the endpoints and the match
1330 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001331 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001332 */
1333 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001334 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001335 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001336 // Don't do the shortest path computation here.
1337 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001338 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001339
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001340 // We need the DataPath to populate the Network MAP
1341 DataPath dataPath = new DataPath();
1342 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1343 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001344
1345 //
1346 // Prepare the computed Flow Path
1347 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001348 FlowPath computedFlowPath = new FlowPath();
1349 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1350 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1351 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001352 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001353
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001354 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001355 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001356 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001357 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001358
1359 // TODO: Mark the flow for maintenance purpose
1360
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001361 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001362 }
1363
1364 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001365 * Reconcile a flow.
1366 *
1367 * @param flowObj the flow that needs to be reconciliated.
1368 * @param newDataPath the new data path to use.
1369 * @return true on success, otherwise false.
1370 */
1371 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1372 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1373
1374 //
1375 // Set the incoming port matching and the outgoing port output
1376 // actions for each flow entry.
1377 //
1378 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1379 // Set the incoming port matching
1380 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1381 flowEntry.setFlowEntryMatch(flowEntryMatch);
1382 flowEntryMatch.enableInPort(flowEntry.inPort());
1383
1384 // Set the outgoing port output action
1385 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1386 if (flowEntryActions == null) {
1387 flowEntryActions = new ArrayList<FlowEntryAction>();
1388 flowEntry.setFlowEntryActions(flowEntryActions);
1389 }
1390 FlowEntryAction flowEntryAction = new FlowEntryAction();
1391 flowEntryAction.setActionOutput(flowEntry.outPort());
1392 flowEntryActions.add(flowEntryAction);
1393 }
1394
1395 //
1396 // Remove the old Flow Entries, and add the new Flow Entries
1397 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001398 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1399 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1400 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001401 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001402 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001403 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001404 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001405 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001406 }
1407
1408 //
1409 // Set the Data Path Summary
1410 //
1411 String dataPathSummaryStr = newDataPath.dataPathSummary();
1412 flowObj.setDataPathSummary(dataPathSummaryStr);
1413
1414 return true;
1415 }
1416
1417 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001418 * Reconcile all flows in a set.
1419 *
1420 * @param flowObjSet the set of flows that need to be reconciliated.
1421 */
1422 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1423 if (! flowObjSet.iterator().hasNext())
1424 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001425 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001426 }
1427
1428 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001429 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001430 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001431 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001432 * @param flowObj the flow path object for the flow entry to install.
1433 * @param flowEntryObj the flow entry object to install.
1434 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001435 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001436 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1437 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001438 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1439 if (flowEntryIdStr == null)
1440 return false;
1441 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001442 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001443 if (userState == null)
1444 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001445
1446 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001447 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001448 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001449 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1450 .getMessage(OFType.FLOW_MOD);
1451 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001452
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001453 short flowModCommand = OFFlowMod.OFPFC_ADD;
1454 if (userState.equals("FE_USER_ADD")) {
1455 flowModCommand = OFFlowMod.OFPFC_ADD;
1456 } else if (userState.equals("FE_USER_MODIFY")) {
1457 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1458 } else if (userState.equals("FE_USER_DELETE")) {
1459 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1460 } else {
1461 // Unknown user state. Ignore the entry
1462 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1463 flowEntryId.toString(), userState);
1464 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001465 }
1466
1467 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001468 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001469 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001470 // NOTE: The Flow matching conditions common for all Flow Entries are
1471 // used ONLY if a Flow Entry does NOT have the corresponding matching
1472 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001473 //
1474 OFMatch match = new OFMatch();
1475 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001476
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001477 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001478 Short matchInPort = flowEntryObj.getMatchInPort();
1479 if (matchInPort != null) {
1480 match.setInputPort(matchInPort);
1481 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1482 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001483
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001484 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001485 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1486 if (matchEthernetFrameType == null)
1487 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1488 if (matchEthernetFrameType != null) {
1489 match.setDataLayerType(matchEthernetFrameType);
1490 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1491 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001492
1493 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001494 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1495 if (matchSrcIPv4Net == null)
1496 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1497 if (matchSrcIPv4Net != null) {
1498 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1499 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001500
1501 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001502 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1503 if (matchDstIPv4Net == null)
1504 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1505 if (matchDstIPv4Net != null) {
1506 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1507 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001508
1509 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001510 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1511 if (matchSrcMac == null)
1512 matchSrcMac = flowObj.getMatchSrcMac();
1513 if (matchSrcMac != null) {
1514 match.setDataLayerSource(matchSrcMac);
1515 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1516 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001517
1518 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001519 String matchDstMac = flowEntryObj.getMatchDstMac();
1520 if (matchDstMac == null)
1521 matchDstMac = flowObj.getMatchDstMac();
1522 if (matchDstMac != null) {
1523 match.setDataLayerDestination(matchDstMac);
1524 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1525 }
1526
1527 //
1528 // Fetch the actions
1529 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001530 // TODO: For now we support only the "OUTPUT" actions.
1531 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001532 List<OFAction> actions = new ArrayList<OFAction>();
1533 Short actionOutputPort = flowEntryObj.getActionOutput();
1534 if (actionOutputPort != null) {
1535 OFActionOutput action = new OFActionOutput();
1536 // XXX: The max length is hard-coded for now
1537 action.setMaxLength((short)0xffff);
1538 action.setPort(actionOutputPort);
1539 actions.add(action);
1540 }
1541
1542 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1543 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1544 .setPriority(PRIORITY_DEFAULT)
1545 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1546 .setCookie(cookie)
1547 .setCommand(flowModCommand)
1548 .setMatch(match)
1549 .setActions(actions)
1550 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1551 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1552 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1553 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1554 if (actionOutputPort != null)
1555 fm.setOutPort(actionOutputPort);
1556 }
1557
1558 //
1559 // TODO: Set the following flag
1560 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1561 // See method ForwardingBase::pushRoute()
1562 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001563
1564 //
1565 // Write the message to the switch
1566 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001567 log.debug("MEASUREMENT: Installing flow entry " + userState +
1568 " into switch DPID: " +
1569 mySwitch.getStringId() +
1570 " flowEntryId: " + flowEntryId.toString() +
1571 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1572 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1573 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001574 try {
1575 messageDamper.write(mySwitch, fm, null);
1576 mySwitch.flush();
1577 //
1578 // TODO: We should use the OpenFlow Barrier mechanism
1579 // to check for errors, and update the SwitchState
1580 // for a flow entry after the Barrier message is
1581 // is received.
1582 //
1583 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1584 } catch (IOException e) {
1585 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001586 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001587 }
1588
1589 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001590 }
1591
1592 /**
1593 * Install a Flow Entry on a switch.
1594 *
1595 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001596 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001597 * @param flowEntry the flow entry to install.
1598 * @return true on success, otherwise false.
1599 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001600 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1601 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001602 //
1603 // Create the OpenFlow Flow Modification Entry to push
1604 //
1605 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1606 .getMessage(OFType.FLOW_MOD);
1607 long cookie = flowEntry.flowEntryId().value();
1608
1609 short flowModCommand = OFFlowMod.OFPFC_ADD;
1610 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1611 flowModCommand = OFFlowMod.OFPFC_ADD;
1612 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1613 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1614 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1615 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1616 } else {
1617 // Unknown user state. Ignore the entry
1618 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1619 flowEntry.flowEntryId().toString(),
1620 flowEntry.flowEntryUserState());
1621 return false;
1622 }
1623
1624 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001625 // Fetch the match conditions.
1626 //
1627 // NOTE: The Flow matching conditions common for all Flow Entries are
1628 // used ONLY if a Flow Entry does NOT have the corresponding matching
1629 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001630 //
1631 OFMatch match = new OFMatch();
1632 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001633 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1634 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1635
1636 // Match the Incoming Port
1637 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001638 if (matchInPort != null) {
1639 match.setInputPort(matchInPort.value());
1640 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1641 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001642
1643 // Match the Ethernet Frame Type
1644 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1645 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1646 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1647 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001648 if (matchEthernetFrameType != null) {
1649 match.setDataLayerType(matchEthernetFrameType);
1650 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1651 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001652
1653 // Match the Source IPv4 Network prefix
1654 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1655 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1656 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1657 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001658 if (matchSrcIPv4Net != null) {
1659 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1660 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001661
1662 // Natch the Destination IPv4 Network prefix
1663 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1664 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1665 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1666 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001667 if (matchDstIPv4Net != null) {
1668 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1669 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001670
1671 // Match the Source MAC address
1672 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1673 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1674 matchSrcMac = flowPathMatch.srcMac();
1675 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001676 if (matchSrcMac != null) {
1677 match.setDataLayerSource(matchSrcMac.toString());
1678 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1679 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001680
1681 // Match the Destination MAC address
1682 MACAddress matchDstMac = flowEntryMatch.dstMac();
1683 if ((matchDstMac == null) && (flowPathMatch != null)) {
1684 matchDstMac = flowPathMatch.dstMac();
1685 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001686 if (matchDstMac != null) {
1687 match.setDataLayerDestination(matchDstMac.toString());
1688 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1689 }
1690
1691 //
1692 // Fetch the actions
1693 //
1694 // TODO: For now we support only the "OUTPUT" actions.
1695 //
1696 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1697 List<OFAction> actions = new ArrayList<OFAction>();
1698 ArrayList<FlowEntryAction> flowEntryActions =
1699 flowEntry.flowEntryActions();
1700 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1701 FlowEntryAction.ActionOutput actionOutput =
1702 flowEntryAction.actionOutput();
1703 if (actionOutput != null) {
1704 short actionOutputPort = actionOutput.port().value();
1705 OFActionOutput action = new OFActionOutput();
1706 // XXX: The max length is hard-coded for now
1707 action.setMaxLength((short)0xffff);
1708 action.setPort(actionOutputPort);
1709 actions.add(action);
1710 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1711 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1712 fm.setOutPort(actionOutputPort);
1713 }
1714 }
1715 }
1716
1717 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1718 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1719 .setPriority(PRIORITY_DEFAULT)
1720 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1721 .setCookie(cookie)
1722 .setCommand(flowModCommand)
1723 .setMatch(match)
1724 .setActions(actions)
1725 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1726
1727 //
1728 // TODO: Set the following flag
1729 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1730 // See method ForwardingBase::pushRoute()
1731 //
1732
1733 //
1734 // Write the message to the switch
1735 //
1736 try {
1737 messageDamper.write(mySwitch, fm, null);
1738 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001739 //
1740 // TODO: We should use the OpenFlow Barrier mechanism
1741 // to check for errors, and update the SwitchState
1742 // for a flow entry after the Barrier message is
1743 // is received.
1744 //
1745 // TODO: The FlowEntry Object in Titan should be set
1746 // to FE_SWITCH_UPDATED.
1747 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001748 } catch (IOException e) {
1749 log.error("Failure writing flow mod from network map", e);
1750 return false;
1751 }
1752 return true;
1753 }
1754
1755 /**
1756 * Remove a Flow Entry from a switch.
1757 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001758 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001759 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001760 * @param flowEntry the flow entry to remove.
1761 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001762 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001763 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1764 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001765 //
1766 // The installFlowEntry() method implements both installation
1767 // and removal of flow entries.
1768 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001769 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001770 }
1771
1772 /**
1773 * Install a Flow Entry on a remote controller.
1774 *
1775 * TODO: We need it now: Jono
1776 * - For now it will make a REST call to the remote controller.
1777 * - Internally, it needs to know the name of the remote controller.
1778 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001779 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001780 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001781 * @return true on success, otherwise false.
1782 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001783 public boolean installRemoteFlowEntry(FlowPath flowPath,
1784 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001785 // TODO: We need it now: Jono
1786 // - For now it will make a REST call to the remote controller.
1787 // - Internally, it needs to know the name of the remote controller.
1788 return true;
1789 }
1790
1791 /**
1792 * Remove a flow entry on a remote controller.
1793 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001794 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001795 * @param flowEntry the flow entry to remove.
1796 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001797 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001798 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1799 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001800 //
1801 // The installRemoteFlowEntry() method implements both installation
1802 // and removal of flow entries.
1803 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001804 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001805 }
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001806
1807 /**
1808 * Store a path flow for measurement purpose.
1809 *
1810 * NOTE: The Flow Path argument does NOT contain flow entries.
1811 * The Shortest Path is computed, and the corresponding Flow Entries
1812 * are stored in the Flow Path.
1813 *
1814 * @param flowPath the Flow Path with the endpoints and the match
1815 * conditions to store.
1816 * @return the stored shortest-path flow on success, otherwise null.
1817 */
1818 @Override
1819 public FlowPath measurementStorePathFlow(FlowPath flowPath) {
1820 //
1821 // Prepare the Shortest Path computation if the first Flow Path
1822 //
1823 if (measurementStoredPaths.isEmpty())
1824 topoRouteService.prepareShortestPathTopo();
1825
1826 //
1827 // Compute the Shortest Path
1828 //
1829 DataPath dataPath =
1830 topoRouteService.getTopoShortestPath(flowPath.dataPath().srcPort(),
1831 flowPath.dataPath().dstPort());
1832 if (dataPath == null) {
1833 // We need the DataPath to populate the Network MAP
1834 dataPath = new DataPath();
1835 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1836 dataPath.setDstPort(flowPath.dataPath().dstPort());
1837 }
1838
1839 //
1840 // Set the incoming port matching and the outgoing port output
1841 // actions for each flow entry.
1842 //
1843 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1844 // Set the incoming port matching
1845 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1846 flowEntry.setFlowEntryMatch(flowEntryMatch);
1847 flowEntryMatch.enableInPort(flowEntry.inPort());
1848
1849 // Set the outgoing port output action
1850 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1851 if (flowEntryActions == null) {
1852 flowEntryActions = new ArrayList<FlowEntryAction>();
1853 flowEntry.setFlowEntryActions(flowEntryActions);
1854 }
1855 FlowEntryAction flowEntryAction = new FlowEntryAction();
1856 flowEntryAction.setActionOutput(flowEntry.outPort());
1857 flowEntryActions.add(flowEntryAction);
1858 }
1859
1860 //
1861 // Prepare the computed Flow Path
1862 //
1863 FlowPath computedFlowPath = new FlowPath();
1864 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1865 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1866 computedFlowPath.setDataPath(dataPath);
1867 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
1868
1869 //
1870 // Add the computed Flow Path the the internal storage
1871 //
1872 measurementStoredPaths.add(computedFlowPath);
1873
1874 return (computedFlowPath);
1875 }
1876
1877 /**
1878 * Install path flows for measurement purpose.
1879 *
1880 * @param numThreads the number of threads to use to install the path
1881 * flows.
1882 * @return true on success, otherwise false.
1883 */
1884 @Override
1885 public boolean measurementInstallPaths(Integer numThreads) {
1886 List<Thread> threads = new LinkedList<Thread>();
1887
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00001888 // Create a copy of the paths to install
1889 measurementProcessingPaths = new LinkedList<FlowPath>(measurementStoredPaths);
1890
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001891 //
1892 // Create the threads to install the Flow Paths
1893 //
1894 for (int i = 0; i < numThreads; i++) {
1895 Thread thread = new Thread(new Runnable() {
1896 @Override
1897 public void run() {
1898 while (true) {
1899 FlowPath flowPath = measurementPollFirstFlowPath();
1900 if (flowPath == null)
1901 return;
1902 // Install the Flow Path
1903 FlowId flowId = new FlowId();
1904 String dataPathSummaryStr =
1905 flowPath.dataPath().dataPathSummary();
1906 addFlow(flowPath, flowId, dataPathSummaryStr);
1907 }
1908 }}, "Measurement Add Flow Path");
1909 threads.add(thread);
1910 }
1911
1912 //
1913 // Start processing
1914 //
1915 measurementEndTimeProcessingPaths = 0;
1916 measurementStartTimeProcessingPaths = System.nanoTime();
1917 for (Thread thread : threads) {
1918 thread.start();
1919 }
1920
1921 //
1922 // Wait until the end of processing time
1923 //
1924 while (measurementEndTimeProcessingPaths == 0) {
1925 try {
1926 Thread.sleep(100);
1927 } catch (InterruptedException e) {
1928 // Continue waiting
1929 }
1930 }
1931
1932 return true;
1933 }
1934
1935 /**
1936 * Get the measurement time that took to install the path flows.
1937 *
1938 * @return the measurement time (in nanoseconds) it took to install
1939 * the path flows.
1940 */
1941 @Override
1942 public Long measurementGetInstallPathsTimeNsec() {
1943 return new Long(measurementEndTimeProcessingPaths -
1944 measurementStartTimeProcessingPaths);
1945 }
1946
1947 /**
1948 * Get a Flow Path that needs to be installed for measurement purpose.
1949 *
1950 * If there is no next Flow Path to install, the end time measurement
1951 * is recorded.
1952 *
1953 * @return the next Flow Path to install if exists, otherwise null.
1954 */
1955 private synchronized FlowPath measurementPollFirstFlowPath() {
1956 FlowPath flowPath = measurementProcessingPaths.pollFirst();
1957
1958 // Record the end of processing, if the first call
1959 if ((flowPath == null) && (measurementEndTimeProcessingPaths == 0))
1960 measurementEndTimeProcessingPaths = System.nanoTime();
1961
1962 return flowPath;
1963 }
1964
1965 /**
1966 * Clear the path flows stored for measurement purpose.
1967 *
1968 * @return true on success, otherwise false.
1969 */
1970 @Override
1971 public boolean measurementClearAllPaths() {
1972 measurementStoredPaths.clear();
1973 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00001974 measurementStartTimeProcessingPaths = 0;
1975 measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07001976
1977 return true;
1978 }
1979
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001980}