blob: 4de2cbcd5df353f3145eb1d22fcc835c48fc12c6 [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;
Pavlin Radoslavove0575292013-03-28 05:35:25 -070010import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000011import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000014import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070015import java.util.TreeMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.Executors;
17import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.ScheduledFuture;
19import 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;
53import net.onrc.onos.util.GraphDBConnection.Transaction;
54
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;
Jonathan Hartf5315fb2013-04-05 11:41:56 -070062import org.openflow.util.HexString;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
Jonathan Hartf5315fb2013-04-05 11:41:56 -070066
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070067public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068
69 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070
71 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070073 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070074 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075
76 protected OFMessageDamper messageDamper;
77
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070078 //
79 // TODO: Values copied from elsewhere (class LearningSwitch).
80 // The local copy should go away!
81 //
82 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
83 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
84 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
85 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
86 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080087
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000088 // Flow Entry ID generation state
89 private static Random randomGenerator = new Random();
90 private static int nextFlowEntryIdPrefix = 0;
91 private static int nextFlowEntryIdSuffix = 0;
92 private static long nextFlowEntryId = 0;
93
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 Radoslavov01391c92013-03-14 17:13:21 -070097
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080098 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080099 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
100
101 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700102 private final ScheduledExecutorService mapReaderScheduler =
103 Executors.newScheduledThreadPool(1);
104
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700105 private final ScheduledExecutorService shortestPathReconcileScheduler =
106 Executors.newScheduledThreadPool(1);
107
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700108 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800109 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700110 long startTime = System.nanoTime();
111 int counterAllFlowEntries = 0;
112 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700113
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800114 if (floodlightProvider == null) {
115 log.debug("FloodlightProvider service not found!");
116 return;
117 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000118 Map<Long, IOFSwitch> mySwitches =
119 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700120 LinkedList<IFlowEntry> addFlowEntries =
121 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000122 LinkedList<IFlowEntry> deleteFlowEntries =
123 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700124
125 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700126 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700127 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700128 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700129 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 Iterable<IFlowEntry> allFlowEntries =
131 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700132 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700133 counterAllFlowEntries++;
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700134 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000135 if ((switchState == null) ||
136 (! switchState.equals("FE_SWITCH_NOT_UPDATED"))) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000137 continue; // Ignore the entry: nothing to do
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000138 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000140 String dpidStr = flowEntryObj.getSwitchDpid();
141 if (dpidStr == null)
142 continue;
143 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800144 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000145 if (mySwitch == null)
146 continue; // Ignore the entry: not my switch
147
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700148 IFlowPath flowObj =
149 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
150 if (flowObj == null)
151 continue; // Should NOT happen
152 if (flowObj.getFlowId() == null)
153 continue; // Invalid entry
154
155 //
156 // NOTE: For now we process the DELETE before the ADD
157 // to cover the more common scenario.
158 // TODO: This is error prone and needs to be fixed!
159 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000160 String userState = flowEntryObj.getUserState();
161 if (userState == null)
162 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700163 if (userState.equals("FE_USER_DELETE")) {
164 // An entry that needs to be deleted.
165 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 installFlowEntry(mySwitch, flowObj, flowEntryObj);
167 } else {
168 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700169 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700170 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700171 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700172 // TODO: Commented-out for now
173 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700174 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700175 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700176 processed_measurement_flow = true;
177 }
178 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700179 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700180 }
181
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700182 //
183 // Process the Flow Entries that need to be added
184 //
185 for (IFlowEntry flowEntryObj : addFlowEntries) {
186 IFlowPath flowObj =
187 conn.utils().getFlowPathByFlowEntry(conn,
188 flowEntryObj);
189 if (flowObj == null)
190 continue; // Should NOT happen
191 if (flowObj.getFlowId() == null)
192 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700193
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700194 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700195 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000196 if (mySwitch == null)
197 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700198 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800199 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200
201 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000202 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700203 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204 //
205 // TODO: We should use the OpenFlow Barrier mechanism
206 // to check for errors, and delete the Flow Entries after the
207 // Barrier message is received.
208 //
209 while (! deleteFlowEntries.isEmpty()) {
210 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
211 IFlowPath flowObj =
212 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
213 if (flowObj == null) {
214 log.debug("Did not find FlowPath to be deleted");
215 continue;
216 }
217 flowObj.removeFlowEntry(flowEntryObj);
218 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000219 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700220
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700221 conn.endTx(Transaction.COMMIT);
222
223 if (processed_measurement_flow) {
224 long estimatedTime =
225 System.nanoTime() - modifiedMeasurementFlowTime;
226 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
227 (double)estimatedTime / 1000000000 + " sec";
228 log.debug(logMsg);
229 }
230
231 long estimatedTime = System.nanoTime() - startTime;
232 double rate = 0.0;
233 if (estimatedTime > 0)
234 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
235 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
236 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
237 counterMyNotUpdatedFlowEntries + " in " +
238 (double)estimatedTime / 1000000000 + " sec: " +
239 rate + " paths/s";
240 log.debug(logMsg);
241 }
242 };
243
244 final Runnable shortestPathReconcile = new Runnable() {
245 public void run() {
246 long startTime = System.nanoTime();
247 int counterAllFlowPaths = 0;
248 int counterMyFlowPaths = 0;
249
250 if (floodlightProvider == null) {
251 log.debug("FloodlightProvider service not found!");
252 return;
253 }
254 Map<Long, IOFSwitch> mySwitches =
255 floodlightProvider.getSwitches();
256 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
257
258 boolean processed_measurement_flow = false;
259
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700260 //
261 // Fetch and recompute the Shortest Path for those
262 // Flow Paths this controller is responsible for.
263 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700264 topoRouteService.prepareShortestPathTopo();
265 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700266 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700267 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700268 if (flowPathObj == null)
269 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700270
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700271 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000272 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700273 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700274 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700275 //
276 // Use the source DPID as a heuristic to decide
277 // which controller is responsible for maintaining the
278 // shortest path.
279 // NOTE: This heuristic is error-prone: if the switch
280 // goes away and no controller is responsible for that
281 // switch, then the original Flow Path is not cleaned-up
282 //
283 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
284 if (mySwitch == null)
285 continue; // Ignore: not my responsibility
286
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700287 // Test the Data Path Summary string
288 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
289 if (dataPathSummaryStr == null)
290 continue; // Could be invalid entry?
291 if (dataPathSummaryStr.isEmpty())
292 continue; // No need to maintain this flow
293
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000294 //
295 // Test whether we need to complete the Flow cleanup,
296 // if the Flow has been deleted by the user.
297 //
298 String flowUserState = flowPathObj.getUserState();
299 if ((flowUserState != null)
300 && flowUserState.equals("FE_USER_DELETE")) {
301 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
302 boolean empty = true; // TODO: an ugly hack
303 for (IFlowEntry flowEntryObj : flowEntries) {
304 empty = false;
305 break;
306 }
307 if (empty)
308 deleteFlows.add(flowPathObj);
309 }
310
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000311 // Fetch the fields needed to recompute the shortest path
312 Short srcPortShort = flowPathObj.getSrcPort();
313 String dstDpidStr = flowPathObj.getDstSwitch();
314 Short dstPortShort = flowPathObj.getDstPort();
315 if ((srcPortShort == null) ||
316 (dstDpidStr == null) ||
317 (dstPortShort == null)) {
318 continue;
319 }
320
321 Port srcPort = new Port(srcPortShort);
322 Dpid dstDpid = new Dpid(dstDpidStr);
323 Port dstPort = new Port(dstPortShort);
324 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
325 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
326
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700327 counterMyFlowPaths++;
328
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700329 //
330 // NOTE: Using here the regular getShortestPath() method
331 // won't work here, because that method calls internally
332 // "conn.endTx(Transaction.COMMIT)", and that will
333 // invalidate all handlers to the Titan database.
334 // If we want to experiment with calling here
335 // getShortestPath(), we need to refactor that code
336 // to avoid closing the transaction.
337 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700338 DataPath dataPath =
339 topoRouteService.getTopoShortestPath(srcSwitchPort,
340 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000341 if (dataPath == null) {
342 // We need the DataPath to compare the paths
343 dataPath = new DataPath();
344 dataPath.setSrcPort(srcSwitchPort);
345 dataPath.setDstPort(dstSwitchPort);
346 }
347
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700348 String newDataPathSummaryStr = dataPath.dataPathSummary();
349 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
350 continue; // Nothing changed
351
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700352 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700353 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000354
355 //
356 // Delete all leftover Flows marked for deletion from the
357 // Network MAP.
358 //
359 while (! deleteFlows.isEmpty()) {
360 IFlowPath flowPathObj = deleteFlows.poll();
361 conn.utils().removeFlowPath(conn, flowPathObj);
362 }
363
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700364 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700365
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800366 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700367
368 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700369 long estimatedTime =
370 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700371 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
372 (double)estimatedTime / 1000000000 + " sec";
373 log.debug(logMsg);
374 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700375
376 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700377 double rate = 0.0;
378 if (estimatedTime > 0)
379 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700380 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700381 counterAllFlowPaths + " MyFlowPaths: " +
382 counterMyFlowPaths + " in " +
383 (double)estimatedTime / 1000000000 + " sec: " +
384 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700385 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800386 }
387 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700388
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700389 final ScheduledFuture<?> mapReaderHandle =
390 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800391
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700392 final ScheduledFuture<?> shortestPathReconcileHandle =
393 shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
394
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800395 @Override
396 public void init(String conf) {
397 conn = GraphDBConnection.getInstance(conf);
398 }
399
400 public void finalize() {
401 close();
402 }
403
404 @Override
405 public void close() {
406 conn.close();
407 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800408
409 @Override
410 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
411 Collection<Class<? extends IFloodlightService>> l =
412 new ArrayList<Class<? extends IFloodlightService>>();
413 l.add(IFlowService.class);
414 return l;
415 }
416
417 @Override
418 public Map<Class<? extends IFloodlightService>, IFloodlightService>
419 getServiceImpls() {
420 Map<Class<? extends IFloodlightService>,
421 IFloodlightService> m =
422 new HashMap<Class<? extends IFloodlightService>,
423 IFloodlightService>();
424 m.put(IFlowService.class, this);
425 return m;
426 }
427
428 @Override
429 public Collection<Class<? extends IFloodlightService>>
430 getModuleDependencies() {
431 Collection<Class<? extends IFloodlightService>> l =
432 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800433 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700434 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800435 l.add(IRestApiService.class);
436 return l;
437 }
438
439 @Override
440 public void init(FloodlightModuleContext context)
441 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700442 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800443 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700444 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800445 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800446 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
447 EnumSet.of(OFType.FLOW_MOD),
448 OFMESSAGE_DAMPER_TIMEOUT);
449 // TODO: An ugly hack!
450 String conf = "/tmp/cassandra.titan";
451 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800452 }
453
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000454 private long getNextFlowEntryId() {
455 //
456 // Generate the next Flow Entry ID.
457 // NOTE: For now, the higher 32 bits are random, and
458 // the lower 32 bits are sequential.
459 // In the future, we need a better allocation mechanism.
460 //
461 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
462 nextFlowEntryIdPrefix = randomGenerator.nextInt();
463 nextFlowEntryIdSuffix = 0;
464 } else {
465 nextFlowEntryIdSuffix++;
466 }
467 long result = (long)nextFlowEntryIdPrefix << 32;
468 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
469 return result;
470 }
471
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800472 @Override
473 public void startUp(FloodlightModuleContext context) {
474 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700475
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000476 // Initialize the Flow Entry ID generator
477 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800478 }
479
480 /**
481 * Add a flow.
482 *
483 * Internally, ONOS will automatically register the installer for
484 * receiving Flow Path Notifications for that path.
485 *
486 * @param flowPath the Flow Path to install.
487 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700488 * @param dataPathSummaryStr the data path summary string if the added
489 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800490 * @return true on success, otherwise false.
491 */
492 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700493 public boolean addFlow(FlowPath flowPath, FlowId flowId,
494 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700495 /*
496 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700497 if (flowPath.flowId().value() == measurementFlowId) {
498 modifiedMeasurementFlowTime = System.nanoTime();
499 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700500 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800501
502 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000503 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800504 try {
505 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
506 != null) {
507 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
508 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000509 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800510 } else {
511 flowObj = conn.utils().newFlowPath(conn);
512 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
513 flowPath.flowId().toString());
514 }
515 } catch (Exception e) {
516 // TODO: handle exceptions
517 conn.endTx(Transaction.ROLLBACK);
518 log.error(":addFlow FlowId:{} failed",
519 flowPath.flowId().toString());
520 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700521 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000522 log.error(":addFlow FlowId:{} failed: Flow object not created",
523 flowPath.flowId().toString());
524 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800525 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700526 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800527
528 //
529 // Set the Flow key:
530 // - flowId
531 //
532 flowObj.setFlowId(flowPath.flowId().toString());
533 flowObj.setType("flow");
534
535 //
536 // Set the Flow attributes:
537 // - flowPath.installerId()
538 // - flowPath.dataPath().srcPort()
539 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700540 // - flowPath.matchEthernetFrameType()
541 // - flowPath.matchSrcIPv4Net()
542 // - flowPath.matchDstIPv4Net()
543 // - flowPath.matchSrcMac()
544 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800545 //
546 flowObj.setInstallerId(flowPath.installerId().toString());
547 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
548 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
549 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
550 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700551 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
552 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
553 }
554 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
555 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
556 }
557 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
558 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
559 }
560 if (flowPath.flowEntryMatch().matchSrcMac()) {
561 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
562 }
563 if (flowPath.flowEntryMatch().matchDstMac()) {
564 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
565 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800566
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700567 if (dataPathSummaryStr != null) {
568 flowObj.setDataPathSummary(dataPathSummaryStr);
569 } else {
570 flowObj.setDataPathSummary("");
571 }
572
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000573 if (found)
574 flowObj.setUserState("FE_USER_MODIFY");
575 else
576 flowObj.setUserState("FE_USER_ADD");
577
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800578 // Flow edges:
579 // HeadFE
580
581
582 //
583 // Flow Entries:
584 // flowPath.dataPath().flowEntries()
585 //
586 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700587 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000588 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800589 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700590 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800591 }
592 conn.endTx(Transaction.COMMIT);
593
594 //
595 // TODO: We need a proper Flow ID allocation mechanism.
596 //
597 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700598
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800599 return true;
600 }
601
602 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700603 * Add a flow entry to the Network MAP.
604 *
605 * @param flowObj the corresponding Flow Path object for the Flow Entry.
606 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700607 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700608 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700609 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700610 // Flow edges
611 // HeadFE (TODO)
612
613 //
614 // Assign the FlowEntry ID.
615 //
616 if ((flowEntry.flowEntryId() == null) ||
617 (flowEntry.flowEntryId().value() == 0)) {
618 long id = getNextFlowEntryId();
619 flowEntry.setFlowEntryId(new FlowEntryId(id));
620 }
621
622 IFlowEntry flowEntryObj = null;
623 boolean found = false;
624 try {
625 if ((flowEntryObj =
626 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
627 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
628 flowEntry.flowEntryId().toString());
629 found = true;
630 } else {
631 flowEntryObj = conn.utils().newFlowEntry(conn);
632 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
633 flowEntry.flowEntryId().toString());
634 }
635 } catch (Exception e) {
636 log.error(":addFlow FlowEntryId:{} failed",
637 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700638 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700639 }
640 if (flowEntryObj == null) {
641 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
642 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700643 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700644 }
645
646 //
647 // Set the Flow Entry key:
648 // - flowEntry.flowEntryId()
649 //
650 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
651 flowEntryObj.setType("flow_entry");
652
653 //
654 // Set the Flow Entry Edges and attributes:
655 // - Switch edge
656 // - InPort edge
657 // - OutPort edge
658 //
659 // - flowEntry.flowEntryMatch()
660 // - flowEntry.flowEntryActions()
661 // - flowEntry.dpid()
662 // - flowEntry.flowEntryUserState()
663 // - flowEntry.flowEntrySwitchState()
664 // - flowEntry.flowEntryErrorState()
665 // - flowEntry.matchInPort()
666 // - flowEntry.matchEthernetFrameType()
667 // - flowEntry.matchSrcIPv4Net()
668 // - flowEntry.matchDstIPv4Net()
669 // - flowEntry.matchSrcMac()
670 // - flowEntry.matchDstMac()
671 // - flowEntry.actionOutput()
672 //
673 ISwitchObject sw =
674 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
675 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
676 flowEntryObj.setSwitch(sw);
677 if (flowEntry.flowEntryMatch().matchInPort()) {
678 IPortObject inport =
679 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
680 flowEntry.flowEntryMatch().inPort().value());
681 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
682 flowEntryObj.setInPort(inport);
683 }
684 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
685 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
686 }
687 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
688 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
689 }
690 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
691 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
692 }
693 if (flowEntry.flowEntryMatch().matchSrcMac()) {
694 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
695 }
696 if (flowEntry.flowEntryMatch().matchDstMac()) {
697 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
698 }
699
700 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
701 if (fa.actionOutput() != null) {
702 IPortObject outport =
703 conn.utils().searchPort(conn,
704 flowEntry.dpid().toString(),
705 fa.actionOutput().port().value());
706 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
707 flowEntryObj.setOutPort(outport);
708 }
709 }
710 // TODO: Hacks with hard-coded state names!
711 if (found)
712 flowEntryObj.setUserState("FE_USER_MODIFY");
713 else
714 flowEntryObj.setUserState("FE_USER_ADD");
715 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
716 //
717 // TODO: Take care of the FlowEntryErrorState.
718 //
719
720 // Flow Entries edges:
721 // Flow
722 // NextFE (TODO)
723 if (! found) {
724 flowObj.addFlowEntry(flowEntryObj);
725 flowEntryObj.setFlow(flowObj);
726 }
727
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700728 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700729 }
730
731 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800732 * Delete a previously added flow.
733 *
734 * @param flowId the Flow ID of the flow to delete.
735 * @return true on success, otherwise false.
736 */
737 @Override
738 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700739 /*
740 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700741 if (flowId.value() == measurementFlowId) {
742 modifiedMeasurementFlowTime = System.nanoTime();
743 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700744 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700745
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800746 IFlowPath flowObj = null;
747 //
748 // We just mark the entries for deletion,
749 // and let the switches remove each individual entry after
750 // it has been removed from the switches.
751 //
752 try {
753 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
754 != null) {
755 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
756 flowId.toString());
757 } else {
758 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
759 flowId.toString());
760 }
761 } catch (Exception e) {
762 // TODO: handle exceptions
763 conn.endTx(Transaction.ROLLBACK);
764 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
765 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700766 if (flowObj == null) {
767 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800768 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700769 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800770
771 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000772 // Find and mark for deletion all Flow Entries,
773 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800774 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000775 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800776 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
777 boolean empty = true; // TODO: an ugly hack
778 for (IFlowEntry flowEntryObj : flowEntries) {
779 empty = false;
780 // flowObj.removeFlowEntry(flowEntryObj);
781 // conn.utils().removeFlowEntry(conn, flowEntryObj);
782 flowEntryObj.setUserState("FE_USER_DELETE");
783 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
784 }
785 // Remove from the database empty flows
786 if (empty)
787 conn.utils().removeFlowPath(conn, flowObj);
788 conn.endTx(Transaction.COMMIT);
789
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800790 return true;
791 }
792
793 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700794 * Clear the state for a previously added flow.
795 *
796 * @param flowId the Flow ID of the flow to clear.
797 * @return true on success, otherwise false.
798 */
799 @Override
800 public boolean clearFlow(FlowId flowId) {
801 IFlowPath flowObj = null;
802 try {
803 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
804 != null) {
805 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
806 flowId.toString());
807 } else {
808 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
809 flowId.toString());
810 }
811 } catch (Exception e) {
812 // TODO: handle exceptions
813 conn.endTx(Transaction.ROLLBACK);
814 log.error(":clearFlow FlowId:{} failed", flowId.toString());
815 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700816 if (flowObj == null) {
817 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700818 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700819 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700820
821 //
822 // Remove all Flow Entries
823 //
824 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
825 for (IFlowEntry flowEntryObj : flowEntries) {
826 flowObj.removeFlowEntry(flowEntryObj);
827 conn.utils().removeFlowEntry(conn, flowEntryObj);
828 }
829 // Remove the Flow itself
830 conn.utils().removeFlowPath(conn, flowObj);
831 conn.endTx(Transaction.COMMIT);
832
833 return true;
834 }
835
836 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800837 * Get a previously added flow.
838 *
839 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800840 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800841 */
842 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800843 public FlowPath getFlow(FlowId flowId) {
844 IFlowPath flowObj = null;
845 try {
846 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
847 != null) {
848 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
849 flowId.toString());
850 } else {
851 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
852 flowId.toString());
853 }
854 } catch (Exception e) {
855 // TODO: handle exceptions
856 conn.endTx(Transaction.ROLLBACK);
857 log.error(":getFlow FlowId:{} failed", flowId.toString());
858 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700859 if (flowObj == null) {
860 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800861 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700862 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800863
864 //
865 // Extract the Flow state
866 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800867 FlowPath flowPath = extractFlowPath(flowObj);
868 conn.endTx(Transaction.COMMIT);
869
870 return flowPath;
871 }
872
873 /**
874 * Get all previously added flows by a specific installer for a given
875 * data path endpoints.
876 *
877 * @param installerId the Caller ID of the installer of the flow to get.
878 * @param dataPathEndpoints the data path endpoints of the flow to get.
879 * @return the Flow Paths if found, otherwise null.
880 */
881 @Override
882 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
883 DataPathEndpoints dataPathEndpoints) {
884 //
885 // TODO: The implementation below is not optimal:
886 // We fetch all flows, and then return only the subset that match
887 // the query conditions.
888 // We should use the appropriate Titan/Gremlin query to filter-out
889 // the flows as appropriate.
890 //
891 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700892 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800893
894 if (allFlows == null) {
895 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700896 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800897 }
898
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800899 for (FlowPath flow : allFlows) {
900 //
901 // TODO: String-based comparison is sub-optimal.
902 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800903 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800904 //
905 if (! flow.installerId().toString().equals(installerId.toString()))
906 continue;
907 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
908 continue;
909 }
910 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
911 continue;
912 }
913 flowPaths.add(flow);
914 }
915
916 if (flowPaths.isEmpty()) {
917 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800918 } else {
919 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
920 }
921
922 return flowPaths;
923 }
924
925 /**
926 * Get all installed flows by all installers for given data path endpoints.
927 *
928 * @param dataPathEndpoints the data path endpoints of the flows to get.
929 * @return the Flow Paths if found, otherwise null.
930 */
931 @Override
932 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
933 //
934 // TODO: The implementation below is not optimal:
935 // We fetch all flows, and then return only the subset that match
936 // the query conditions.
937 // We should use the appropriate Titan/Gremlin query to filter-out
938 // the flows as appropriate.
939 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700940 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
941 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800942
943 if (allFlows == null) {
944 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700945 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800946 }
947
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800948 for (FlowPath flow : allFlows) {
949 //
950 // TODO: String-based comparison is sub-optimal.
951 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800952 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800953 //
954 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
955 continue;
956 }
957 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
958 continue;
959 }
960 flowPaths.add(flow);
961 }
962
963 if (flowPaths.isEmpty()) {
964 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800965 } else {
966 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
967 }
968
969 return flowPaths;
970 }
971
972 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700973 * Get summary of all installed flows by all installers in a given range
974 *
975 * @param flowId the data path endpoints of the flows to get.
976 * @param maxFlows: the maximum number of flows to be returned
977 * @return the Flow Paths if found, otherwise null.
978 */
979 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700980 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700981
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700982 // TODO: The implementation below is not optimal:
983 // We fetch all flows, and then return only the subset that match
984 // the query conditions.
985 // We should use the appropriate Titan/Gremlin query to filter-out
986 // the flows as appropriate.
987 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700988 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700989
Jonathan Hart01f2d272013-04-04 20:03:46 -0700990 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
991
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700992 Collections.sort(flowPathsWithoutFlowEntries,
993 new Comparator<IFlowPath>(){
994 @Override
995 public int compare(IFlowPath first, IFlowPath second) {
996 // TODO Auto-generated method stub
997 long result = new FlowId(first.getFlowId()).value()
998 - new FlowId(second.getFlowId()).value();
999 if (result > 0) return 1;
1000 else if (result < 0) return -1;
1001 else return 0;
1002 }
1003 }
1004 );
1005
Jonathan Hart01f2d272013-04-04 20:03:46 -07001006 return flowPathsWithoutFlowEntries;
1007
1008 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001009 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001010
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001011 if (allFlows == null) {
1012 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001013 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001014 }
1015
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001016 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001017
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001018 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001019 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001020
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001021 // start from desired flowId
1022 if (flow.flowId().value() < flowId.value()) {
1023 continue;
1024 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001025
1026 // Summarize by making null flow entry fields that are not relevant to report
1027 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1028 flowEntry.setFlowEntryActions(null);
1029 flowEntry.setFlowEntryMatch(null);
1030 }
1031
1032 flowPaths.add(flow);
1033 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1034 break;
1035 }
1036 }
1037
1038 if (flowPaths.isEmpty()) {
1039 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001040 } else {
1041 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1042 }
1043
1044 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001045 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001046 }
1047
1048 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001049 * Get all installed flows by all installers.
1050 *
1051 * @return the Flow Paths if found, otherwise null.
1052 */
1053 @Override
1054 public ArrayList<FlowPath> getAllFlows() {
1055 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001056 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001057
1058 try {
1059 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1060 log.debug("Get all FlowPaths: found FlowPaths");
1061 } else {
1062 log.debug("Get all FlowPaths: no FlowPaths found");
1063 }
1064 } catch (Exception e) {
1065 // TODO: handle exceptions
1066 conn.endTx(Transaction.ROLLBACK);
1067 log.error(":getAllFlowPaths failed");
1068 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001069 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1070 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001071 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001072 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001073
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001074 for (IFlowPath flowObj : flowPathsObj) {
1075 //
1076 // Extract the Flow state
1077 //
1078 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001079 if (flowPath != null)
1080 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001081 }
1082
1083 conn.endTx(Transaction.COMMIT);
1084
1085 return flowPaths;
1086 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001087
1088 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1089 Iterable<IFlowPath> flowPathsObj = null;
1090 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1091 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1092
1093 try {
1094 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1095 log.debug("Get all FlowPaths: found FlowPaths");
1096 } else {
1097 log.debug("Get all FlowPaths: no FlowPaths found");
1098 }
1099 } catch (Exception e) {
1100 // TODO: handle exceptions
1101 conn.endTx(Transaction.ROLLBACK);
1102 log.error(":getAllFlowPaths failed");
1103 }
1104 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1105 return new ArrayList<IFlowPath>(); // No Flows found
1106 }
1107
1108 for (IFlowPath flowObj : flowPathsObj){
1109 flowPathsObjArray.add(flowObj);
1110 }
1111 /*
1112 for (IFlowPath flowObj : flowPathsObj) {
1113 //
1114 // Extract the Flow state
1115 //
1116 FlowPath flowPath = extractFlowPath(flowObj);
1117 if (flowPath != null)
1118 flowPaths.add(flowPath);
1119 }
1120 */
1121
1122 //conn.endTx(Transaction.COMMIT);
1123
1124 return flowPathsObjArray;
1125 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001126
1127 /**
1128 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1129 *
1130 * @param flowObj the object to extract the Flow Path State from.
1131 * @return the extracted Flow Path State.
1132 */
1133 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001134 //
1135 // Extract the Flow state
1136 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001137 String flowIdStr = flowObj.getFlowId();
1138 String installerIdStr = flowObj.getInstallerId();
1139 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001140 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001141 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001142 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001143
1144 if ((flowIdStr == null) ||
1145 (installerIdStr == null) ||
1146 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001147 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001148 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001149 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001150 // TODO: A work-around, becauuse of some bogus database objects
1151 return null;
1152 }
1153
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001154 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001155 flowPath.setFlowId(new FlowId(flowIdStr));
1156 flowPath.setInstallerId(new CallerId(installerIdStr));
1157 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001158 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001159 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001160 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001161 //
1162 // Extract the match conditions common for all Flow Entries
1163 //
1164 {
1165 FlowEntryMatch match = new FlowEntryMatch();
1166 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1167 if (matchEthernetFrameType != null)
1168 match.enableEthernetFrameType(matchEthernetFrameType);
1169 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1170 if (matchSrcIPv4Net != null)
1171 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1172 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1173 if (matchDstIPv4Net != null)
1174 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1175 String matchSrcMac = flowObj.getMatchSrcMac();
1176 if (matchSrcMac != null)
1177 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1178 String matchDstMac = flowObj.getMatchDstMac();
1179 if (matchDstMac != null)
1180 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1181 flowPath.setFlowEntryMatch(match);
1182 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001183
1184 //
1185 // Extract all Flow Entries
1186 //
1187 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1188 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001189 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1190 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001191 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001192 flowPath.dataPath().flowEntries().add(flowEntry);
1193 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001194
1195 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001196 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001197
1198 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001199 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1200 *
1201 * @param flowEntryObj the object to extract the Flow Entry State from.
1202 * @return the extracted Flow Entry State.
1203 */
1204 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1205 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1206 String switchDpidStr = flowEntryObj.getSwitchDpid();
1207 String userState = flowEntryObj.getUserState();
1208 String switchState = flowEntryObj.getSwitchState();
1209
1210 if ((flowEntryIdStr == null) ||
1211 (switchDpidStr == null) ||
1212 (userState == null) ||
1213 (switchState == null)) {
1214 // TODO: A work-around, becauuse of some bogus database objects
1215 return null;
1216 }
1217
1218 FlowEntry flowEntry = new FlowEntry();
1219 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1220 flowEntry.setDpid(new Dpid(switchDpidStr));
1221
1222 //
1223 // Extract the match conditions
1224 //
1225 FlowEntryMatch match = new FlowEntryMatch();
1226 Short matchInPort = flowEntryObj.getMatchInPort();
1227 if (matchInPort != null)
1228 match.enableInPort(new Port(matchInPort));
1229 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1230 if (matchEthernetFrameType != null)
1231 match.enableEthernetFrameType(matchEthernetFrameType);
1232 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1233 if (matchSrcIPv4Net != null)
1234 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1235 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1236 if (matchDstIPv4Net != null)
1237 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1238 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1239 if (matchSrcMac != null)
1240 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1241 String matchDstMac = flowEntryObj.getMatchDstMac();
1242 if (matchDstMac != null)
1243 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1244 flowEntry.setFlowEntryMatch(match);
1245
1246 //
1247 // Extract the actions
1248 //
1249 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1250 Short actionOutputPort = flowEntryObj.getActionOutput();
1251 if (actionOutputPort != null) {
1252 FlowEntryAction action = new FlowEntryAction();
1253 action.setActionOutput(new Port(actionOutputPort));
1254 actions.add(action);
1255 }
1256 flowEntry.setFlowEntryActions(actions);
1257 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1258 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1259 //
1260 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1261 // and FlowEntryErrorState.
1262 //
1263 return flowEntry;
1264 }
1265
1266 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001267 * Add and maintain a shortest-path flow.
1268 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001269 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001270 *
1271 * @param flowPath the Flow Path with the endpoints and the match
1272 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001273 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001274 */
1275 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001276 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001277 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001278 // Don't do the shortest path computation here.
1279 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001280 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001281
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001282 // We need the DataPath to populate the Network MAP
1283 DataPath dataPath = new DataPath();
1284 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1285 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001286
1287 //
1288 // Prepare the computed Flow Path
1289 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001290 FlowPath computedFlowPath = new FlowPath();
1291 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1292 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1293 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001294 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001295
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001296 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001297 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001298 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001299 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001300
1301 // TODO: Mark the flow for maintenance purpose
1302
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001303 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001304 }
1305
1306 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001307 * Reconcile a flow.
1308 *
1309 * @param flowObj the flow that needs to be reconciliated.
1310 * @param newDataPath the new data path to use.
1311 * @return true on success, otherwise false.
1312 */
1313 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1314 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1315
1316 //
1317 // Set the incoming port matching and the outgoing port output
1318 // actions for each flow entry.
1319 //
1320 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1321 // Set the incoming port matching
1322 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1323 flowEntry.setFlowEntryMatch(flowEntryMatch);
1324 flowEntryMatch.enableInPort(flowEntry.inPort());
1325
1326 // Set the outgoing port output action
1327 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1328 if (flowEntryActions == null) {
1329 flowEntryActions = new ArrayList<FlowEntryAction>();
1330 flowEntry.setFlowEntryActions(flowEntryActions);
1331 }
1332 FlowEntryAction flowEntryAction = new FlowEntryAction();
1333 flowEntryAction.setActionOutput(flowEntry.outPort());
1334 flowEntryActions.add(flowEntryAction);
1335 }
1336
1337 //
1338 // Remove the old Flow Entries, and add the new Flow Entries
1339 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001340 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1341 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1342 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001343 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001344 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001345 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001346 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001347 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001348 }
1349
1350 //
1351 // Set the Data Path Summary
1352 //
1353 String dataPathSummaryStr = newDataPath.dataPathSummary();
1354 flowObj.setDataPathSummary(dataPathSummaryStr);
1355
1356 return true;
1357 }
1358
1359 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001360 * Reconcile all flows in a set.
1361 *
1362 * @param flowObjSet the set of flows that need to be reconciliated.
1363 */
1364 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1365 if (! flowObjSet.iterator().hasNext())
1366 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001367 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001368 }
1369
1370 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001371 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001372 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001373 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001374 * @param flowObj the flow path object for the flow entry to install.
1375 * @param flowEntryObj the flow entry object to install.
1376 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001377 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001378 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1379 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001380 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1381 if (flowEntryIdStr == null)
1382 return false;
1383 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001384 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001385 if (userState == null)
1386 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001387
1388 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001389 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001390 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001391 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1392 .getMessage(OFType.FLOW_MOD);
1393 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001394
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001395 short flowModCommand = OFFlowMod.OFPFC_ADD;
1396 if (userState.equals("FE_USER_ADD")) {
1397 flowModCommand = OFFlowMod.OFPFC_ADD;
1398 } else if (userState.equals("FE_USER_MODIFY")) {
1399 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1400 } else if (userState.equals("FE_USER_DELETE")) {
1401 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1402 } else {
1403 // Unknown user state. Ignore the entry
1404 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1405 flowEntryId.toString(), userState);
1406 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001407 }
1408
1409 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001410 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001411 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001412 // NOTE: The Flow matching conditions common for all Flow Entries are
1413 // used ONLY if a Flow Entry does NOT have the corresponding matching
1414 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001415 //
1416 OFMatch match = new OFMatch();
1417 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001418
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001419 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001420 Short matchInPort = flowEntryObj.getMatchInPort();
1421 if (matchInPort != null) {
1422 match.setInputPort(matchInPort);
1423 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1424 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001425
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001426 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001427 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1428 if (matchEthernetFrameType == null)
1429 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1430 if (matchEthernetFrameType != null) {
1431 match.setDataLayerType(matchEthernetFrameType);
1432 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1433 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001434
1435 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001436 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1437 if (matchSrcIPv4Net == null)
1438 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1439 if (matchSrcIPv4Net != null) {
1440 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1441 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001442
1443 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001444 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1445 if (matchDstIPv4Net == null)
1446 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1447 if (matchDstIPv4Net != null) {
1448 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1449 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001450
1451 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001452 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1453 if (matchSrcMac == null)
1454 matchSrcMac = flowObj.getMatchSrcMac();
1455 if (matchSrcMac != null) {
1456 match.setDataLayerSource(matchSrcMac);
1457 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1458 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001459
1460 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001461 String matchDstMac = flowEntryObj.getMatchDstMac();
1462 if (matchDstMac == null)
1463 matchDstMac = flowObj.getMatchDstMac();
1464 if (matchDstMac != null) {
1465 match.setDataLayerDestination(matchDstMac);
1466 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1467 }
1468
1469 //
1470 // Fetch the actions
1471 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001472 // TODO: For now we support only the "OUTPUT" actions.
1473 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001474 List<OFAction> actions = new ArrayList<OFAction>();
1475 Short actionOutputPort = flowEntryObj.getActionOutput();
1476 if (actionOutputPort != null) {
1477 OFActionOutput action = new OFActionOutput();
1478 // XXX: The max length is hard-coded for now
1479 action.setMaxLength((short)0xffff);
1480 action.setPort(actionOutputPort);
1481 actions.add(action);
1482 }
1483
1484 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1485 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1486 .setPriority(PRIORITY_DEFAULT)
1487 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1488 .setCookie(cookie)
1489 .setCommand(flowModCommand)
1490 .setMatch(match)
1491 .setActions(actions)
1492 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1493 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1494 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1495 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1496 if (actionOutputPort != null)
1497 fm.setOutPort(actionOutputPort);
1498 }
1499
1500 //
1501 // TODO: Set the following flag
1502 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1503 // See method ForwardingBase::pushRoute()
1504 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001505
1506 //
1507 // Write the message to the switch
1508 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001509 log.debug("MEASUREMENT: Installing flow entry " + userState +
1510 " into switch DPID: " +
1511 mySwitch.getStringId() +
1512 " flowEntryId: " + flowEntryId.toString() +
1513 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1514 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1515 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001516 try {
1517 messageDamper.write(mySwitch, fm, null);
1518 mySwitch.flush();
1519 //
1520 // TODO: We should use the OpenFlow Barrier mechanism
1521 // to check for errors, and update the SwitchState
1522 // for a flow entry after the Barrier message is
1523 // is received.
1524 //
1525 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1526 } catch (IOException e) {
1527 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001528 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001529 }
1530
1531 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001532 }
1533
1534 /**
1535 * Install a Flow Entry on a switch.
1536 *
1537 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001538 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001539 * @param flowEntry the flow entry to install.
1540 * @return true on success, otherwise false.
1541 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001542 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1543 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001544 //
1545 // Create the OpenFlow Flow Modification Entry to push
1546 //
1547 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1548 .getMessage(OFType.FLOW_MOD);
1549 long cookie = flowEntry.flowEntryId().value();
1550
1551 short flowModCommand = OFFlowMod.OFPFC_ADD;
1552 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1553 flowModCommand = OFFlowMod.OFPFC_ADD;
1554 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1555 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1556 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1557 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1558 } else {
1559 // Unknown user state. Ignore the entry
1560 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1561 flowEntry.flowEntryId().toString(),
1562 flowEntry.flowEntryUserState());
1563 return false;
1564 }
1565
1566 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001567 // Fetch the match conditions.
1568 //
1569 // NOTE: The Flow matching conditions common for all Flow Entries are
1570 // used ONLY if a Flow Entry does NOT have the corresponding matching
1571 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001572 //
1573 OFMatch match = new OFMatch();
1574 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001575 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1576 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1577
1578 // Match the Incoming Port
1579 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001580 if (matchInPort != null) {
1581 match.setInputPort(matchInPort.value());
1582 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1583 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001584
1585 // Match the Ethernet Frame Type
1586 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1587 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1588 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1589 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001590 if (matchEthernetFrameType != null) {
1591 match.setDataLayerType(matchEthernetFrameType);
1592 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1593 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001594
1595 // Match the Source IPv4 Network prefix
1596 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1597 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1598 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1599 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001600 if (matchSrcIPv4Net != null) {
1601 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1602 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001603
1604 // Natch the Destination IPv4 Network prefix
1605 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1606 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1607 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1608 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001609 if (matchDstIPv4Net != null) {
1610 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1611 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001612
1613 // Match the Source MAC address
1614 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1615 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1616 matchSrcMac = flowPathMatch.srcMac();
1617 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001618 if (matchSrcMac != null) {
1619 match.setDataLayerSource(matchSrcMac.toString());
1620 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1621 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001622
1623 // Match the Destination MAC address
1624 MACAddress matchDstMac = flowEntryMatch.dstMac();
1625 if ((matchDstMac == null) && (flowPathMatch != null)) {
1626 matchDstMac = flowPathMatch.dstMac();
1627 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001628 if (matchDstMac != null) {
1629 match.setDataLayerDestination(matchDstMac.toString());
1630 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1631 }
1632
1633 //
1634 // Fetch the actions
1635 //
1636 // TODO: For now we support only the "OUTPUT" actions.
1637 //
1638 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1639 List<OFAction> actions = new ArrayList<OFAction>();
1640 ArrayList<FlowEntryAction> flowEntryActions =
1641 flowEntry.flowEntryActions();
1642 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1643 FlowEntryAction.ActionOutput actionOutput =
1644 flowEntryAction.actionOutput();
1645 if (actionOutput != null) {
1646 short actionOutputPort = actionOutput.port().value();
1647 OFActionOutput action = new OFActionOutput();
1648 // XXX: The max length is hard-coded for now
1649 action.setMaxLength((short)0xffff);
1650 action.setPort(actionOutputPort);
1651 actions.add(action);
1652 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1653 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1654 fm.setOutPort(actionOutputPort);
1655 }
1656 }
1657 }
1658
1659 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1660 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1661 .setPriority(PRIORITY_DEFAULT)
1662 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1663 .setCookie(cookie)
1664 .setCommand(flowModCommand)
1665 .setMatch(match)
1666 .setActions(actions)
1667 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1668
1669 //
1670 // TODO: Set the following flag
1671 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1672 // See method ForwardingBase::pushRoute()
1673 //
1674
1675 //
1676 // Write the message to the switch
1677 //
1678 try {
1679 messageDamper.write(mySwitch, fm, null);
1680 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001681 //
1682 // TODO: We should use the OpenFlow Barrier mechanism
1683 // to check for errors, and update the SwitchState
1684 // for a flow entry after the Barrier message is
1685 // is received.
1686 //
1687 // TODO: The FlowEntry Object in Titan should be set
1688 // to FE_SWITCH_UPDATED.
1689 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001690 } catch (IOException e) {
1691 log.error("Failure writing flow mod from network map", e);
1692 return false;
1693 }
1694 return true;
1695 }
1696
1697 /**
1698 * Remove a Flow Entry from a switch.
1699 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001700 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001701 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001702 * @param flowEntry the flow entry to remove.
1703 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001704 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001705 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1706 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001707 //
1708 // The installFlowEntry() method implements both installation
1709 // and removal of flow entries.
1710 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001711 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001712 }
1713
1714 /**
1715 * Install a Flow Entry on a remote controller.
1716 *
1717 * TODO: We need it now: Jono
1718 * - For now it will make a REST call to the remote controller.
1719 * - Internally, it needs to know the name of the remote controller.
1720 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001721 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001722 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001723 * @return true on success, otherwise false.
1724 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001725 public boolean installRemoteFlowEntry(FlowPath flowPath,
1726 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001727 // TODO: We need it now: Jono
1728 // - For now it will make a REST call to the remote controller.
1729 // - Internally, it needs to know the name of the remote controller.
1730 return true;
1731 }
1732
1733 /**
1734 * Remove a flow entry on a remote controller.
1735 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001736 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001737 * @param flowEntry the flow entry to remove.
1738 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001739 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001740 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1741 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001742 //
1743 // The installRemoteFlowEntry() method implements both installation
1744 // and removal of flow entries.
1745 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001746 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001747 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001748}