blob: b1578e9c60a2b77f9ea20697569c577c716874de [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;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08006import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07008import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00009import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000012import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070013import java.util.TreeMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
15import java.util.concurrent.ScheduledExecutorService;
16import java.util.concurrent.ScheduledFuture;
17import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080018
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import net.floodlightcontroller.core.IFloodlightProviderService;
20import net.floodlightcontroller.core.INetMapStorage;
21import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
22import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070023import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070024import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070025import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080026import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.core.module.FloodlightModuleContext;
28import net.floodlightcontroller.core.module.FloodlightModuleException;
29import net.floodlightcontroller.core.module.IFloodlightModule;
30import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080031import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
32import net.floodlightcontroller.restserver.IRestApiService;
33import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080034import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080035import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070036import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080037import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070038import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070040import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntrySwitchState;
42import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080043import net.floodlightcontroller.util.FlowId;
44import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070045import net.floodlightcontroller.util.IPv4Net;
46import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080047import net.floodlightcontroller.util.OFMessageDamper;
48import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070049import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080050import net.onrc.onos.util.GraphDBConnection;
51import net.onrc.onos.util.GraphDBConnection.Transaction;
52
53import org.openflow.protocol.OFFlowMod;
54import org.openflow.protocol.OFMatch;
55import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070056import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057import org.openflow.protocol.OFType;
58import org.openflow.protocol.action.OFAction;
59import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080060import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
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;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070069 protected 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 Radoslavov571cff92013-03-20 02:01:32 -070090 private static long measurementFlowId = 100000;
91 private static String measurementFlowIdStr = "0x186a0"; // 100000
92 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070093
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080094 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080095 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
96
97 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070098 private final ScheduledExecutorService mapReaderScheduler =
99 Executors.newScheduledThreadPool(1);
100
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700101 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700103 long startTime = System.nanoTime();
104 int counterAllFlowEntries = 0;
105 int counterMyNotUpdatedFlowEntries = 0;
106 int counterAllFlowPaths = 0;
107 int counterMyFlowPaths = 0;
108
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800109 if (floodlightProvider == null) {
110 log.debug("FloodlightProvider service not found!");
111 return;
112 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000113 Map<Long, IOFSwitch> mySwitches =
114 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700115 LinkedList<IFlowEntry> addFlowEntries =
116 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000117 LinkedList<IFlowEntry> deleteFlowEntries =
118 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700119
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700120
121 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700122 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700123 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700124 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700125 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000126 Iterable<IFlowEntry> allFlowEntries =
127 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700128 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700129 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700131 String userState = flowEntryObj.getUserState();
132 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 String dpidStr = flowEntryObj.getSwitchDpid();
134 if ((flowEntryIdStr == null) ||
135 (userState == null) ||
136 (switchState == null) ||
137 (dpidStr == null)) {
138 log.debug("IGNORING Flow Entry entry with null fields");
139 continue;
140 }
141 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
142 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800143
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000144 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
145 continue; // Ignore the entry: nothing to do
146
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800147 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000148 if (mySwitch == null)
149 continue; // Ignore the entry: not my switch
150
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700151 IFlowPath flowObj =
152 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
153 if (flowObj == null)
154 continue; // Should NOT happen
155 if (flowObj.getFlowId() == null)
156 continue; // Invalid entry
157
158 //
159 // NOTE: For now we process the DELETE before the ADD
160 // to cover the more common scenario.
161 // TODO: This is error prone and needs to be fixed!
162 //
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
182 /*
183 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
184 addFlowEntries.size() + deleteFlowEntries.size());
185 */
186
187 //
188 // Process the Flow Entries that need to be added
189 //
190 for (IFlowEntry flowEntryObj : addFlowEntries) {
191 IFlowPath flowObj =
192 conn.utils().getFlowPathByFlowEntry(conn,
193 flowEntryObj);
194 if (flowObj == null)
195 continue; // Should NOT happen
196 if (flowObj.getFlowId() == null)
197 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700198
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700199 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700200 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000201 if (mySwitch == null)
202 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700203 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800204 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000205
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700206 /*
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700207 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
208 deleteFlowEntries.size());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700209 */
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700210
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700212 // Delete all entries marked for deletion from the
213 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000214 //
215 // TODO: We should use the OpenFlow Barrier mechanism
216 // to check for errors, and delete the Flow Entries after the
217 // Barrier message is received.
218 //
219 while (! deleteFlowEntries.isEmpty()) {
220 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
221 IFlowPath flowObj =
222 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
223 if (flowObj == null) {
224 log.debug("Did not find FlowPath to be deleted");
225 continue;
226 }
227 flowObj.removeFlowEntry(flowEntryObj);
228 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000229 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700230
231
232 //
233 // Fetch and recompute the Shortest Path for those
234 // Flow Paths this controller is responsible for.
235 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700236 topoRouteService.prepareShortestPathTopo();
237 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700238 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700239 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700240 if (flowPathObj == null)
241 continue;
242 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
243 if (dataPathSummaryStr == null)
244 continue; // Could be invalid entry?
245 if (dataPathSummaryStr.isEmpty())
246 continue; // No need to maintain this flow
247
248 // Fetch the fields needed to recompute the shortest path
249 String flowIdStr = flowPathObj.getFlowId();
250 String srcDpidStr = flowPathObj.getSrcSwitch();
251 Short srcPortShort = flowPathObj.getSrcPort();
252 String dstDpidStr = flowPathObj.getDstSwitch();
253 Short dstPortShort = flowPathObj.getDstPort();
254 if ((flowIdStr == null) ||
255 (srcDpidStr == null) ||
256 (srcPortShort == null) ||
257 (dstDpidStr == null) ||
258 (dstPortShort == null)) {
259 log.debug("IGNORING Flow Path entry with null fields");
260 continue;
261 }
262
263 FlowId flowId = new FlowId(flowIdStr);
264 Dpid srcDpid = new Dpid(srcDpidStr);
265 Port srcPort = new Port(srcPortShort);
266 Dpid dstDpid = new Dpid(dstDpidStr);
267 Port dstPort = new Port(dstPortShort);
268 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
269 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700270
271 //
272 // Use the source DPID as a heuristic to decide
273 // which controller is responsible for maintaining the
274 // shortest path.
275 // NOTE: This heuristic is error-prone: if the switch
276 // goes away and no controller is responsible for that
277 // switch, then the original Flow Path is not cleaned-up
278 //
279 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
280 if (mySwitch == null)
281 continue; // Ignore: not my responsibility
282
283 counterMyFlowPaths++;
284
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700285 //
286 // NOTE: Using here the regular getShortestPath() method
287 // won't work here, because that method calls internally
288 // "conn.endTx(Transaction.COMMIT)", and that will
289 // invalidate all handlers to the Titan database.
290 // If we want to experiment with calling here
291 // getShortestPath(), we need to refactor that code
292 // to avoid closing the transaction.
293 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700294 DataPath dataPath =
295 topoRouteService.getTopoShortestPath(srcSwitchPort,
296 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000297 if (dataPath == null) {
298 // We need the DataPath to compare the paths
299 dataPath = new DataPath();
300 dataPath.setSrcPort(srcSwitchPort);
301 dataPath.setDstPort(dstSwitchPort);
302 }
303
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700304 String newDataPathSummaryStr = dataPath.dataPathSummary();
305 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
306 continue; // Nothing changed
307
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700308 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
309 flowId.toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700310 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700311 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700312 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700313
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800314 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700315
316 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700317 long estimatedTime =
318 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700319 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
320 (double)estimatedTime / 1000000000 + " sec";
321 log.debug(logMsg);
322 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700323
324 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700325 double rate = 0.0;
326 if (estimatedTime > 0)
327 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
328 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
329 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
330 counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
331 counterAllFlowPaths + " MyFlowPaths: " +
332 counterMyFlowPaths + " in " +
333 (double)estimatedTime / 1000000000 + " sec: " +
334 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700335 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800336 }
337 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700338
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700339 final ScheduledFuture<?> mapReaderHandle =
340 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800341
342 @Override
343 public void init(String conf) {
344 conn = GraphDBConnection.getInstance(conf);
345 }
346
347 public void finalize() {
348 close();
349 }
350
351 @Override
352 public void close() {
353 conn.close();
354 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800355
356 @Override
357 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
358 Collection<Class<? extends IFloodlightService>> l =
359 new ArrayList<Class<? extends IFloodlightService>>();
360 l.add(IFlowService.class);
361 return l;
362 }
363
364 @Override
365 public Map<Class<? extends IFloodlightService>, IFloodlightService>
366 getServiceImpls() {
367 Map<Class<? extends IFloodlightService>,
368 IFloodlightService> m =
369 new HashMap<Class<? extends IFloodlightService>,
370 IFloodlightService>();
371 m.put(IFlowService.class, this);
372 return m;
373 }
374
375 @Override
376 public Collection<Class<? extends IFloodlightService>>
377 getModuleDependencies() {
378 Collection<Class<? extends IFloodlightService>> l =
379 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800380 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700381 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800382 l.add(IRestApiService.class);
383 return l;
384 }
385
386 @Override
387 public void init(FloodlightModuleContext context)
388 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700389 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800390 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700391 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800392 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800393 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
394 EnumSet.of(OFType.FLOW_MOD),
395 OFMESSAGE_DAMPER_TIMEOUT);
396 // TODO: An ugly hack!
397 String conf = "/tmp/cassandra.titan";
398 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800399 }
400
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000401 private long getNextFlowEntryId() {
402 //
403 // Generate the next Flow Entry ID.
404 // NOTE: For now, the higher 32 bits are random, and
405 // the lower 32 bits are sequential.
406 // In the future, we need a better allocation mechanism.
407 //
408 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
409 nextFlowEntryIdPrefix = randomGenerator.nextInt();
410 nextFlowEntryIdSuffix = 0;
411 } else {
412 nextFlowEntryIdSuffix++;
413 }
414 long result = (long)nextFlowEntryIdPrefix << 32;
415 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
416 return result;
417 }
418
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800419 @Override
420 public void startUp(FloodlightModuleContext context) {
421 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700422
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000423 // Initialize the Flow Entry ID generator
424 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800425 }
426
427 /**
428 * Add a flow.
429 *
430 * Internally, ONOS will automatically register the installer for
431 * receiving Flow Path Notifications for that path.
432 *
433 * @param flowPath the Flow Path to install.
434 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700435 * @param dataPathSummaryStr the data path summary string if the added
436 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800437 * @return true on success, otherwise false.
438 */
439 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700440 public boolean addFlow(FlowPath flowPath, FlowId flowId,
441 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700442 /*
443 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700444 if (flowPath.flowId().value() == measurementFlowId) {
445 modifiedMeasurementFlowTime = System.nanoTime();
446 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700447 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800448
449 IFlowPath flowObj = null;
450 try {
451 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
452 != null) {
453 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
454 flowPath.flowId().toString());
455 } else {
456 flowObj = conn.utils().newFlowPath(conn);
457 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
458 flowPath.flowId().toString());
459 }
460 } catch (Exception e) {
461 // TODO: handle exceptions
462 conn.endTx(Transaction.ROLLBACK);
463 log.error(":addFlow FlowId:{} failed",
464 flowPath.flowId().toString());
465 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700466 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000467 log.error(":addFlow FlowId:{} failed: Flow object not created",
468 flowPath.flowId().toString());
469 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800470 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700471 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800472
473 //
474 // Set the Flow key:
475 // - flowId
476 //
477 flowObj.setFlowId(flowPath.flowId().toString());
478 flowObj.setType("flow");
479
480 //
481 // Set the Flow attributes:
482 // - flowPath.installerId()
483 // - flowPath.dataPath().srcPort()
484 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700485 // - flowPath.matchEthernetFrameType()
486 // - flowPath.matchSrcIPv4Net()
487 // - flowPath.matchDstIPv4Net()
488 // - flowPath.matchSrcMac()
489 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800490 //
491 flowObj.setInstallerId(flowPath.installerId().toString());
492 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
493 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
494 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
495 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700496 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
497 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
498 }
499 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
500 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
501 }
502 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
503 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
504 }
505 if (flowPath.flowEntryMatch().matchSrcMac()) {
506 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
507 }
508 if (flowPath.flowEntryMatch().matchDstMac()) {
509 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
510 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800511
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700512 if (dataPathSummaryStr != null) {
513 flowObj.setDataPathSummary(dataPathSummaryStr);
514 } else {
515 flowObj.setDataPathSummary("");
516 }
517
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800518 // Flow edges:
519 // HeadFE
520
521
522 //
523 // Flow Entries:
524 // flowPath.dataPath().flowEntries()
525 //
526 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700527 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000528 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800529 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700530 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800531 }
532 conn.endTx(Transaction.COMMIT);
533
534 //
535 // TODO: We need a proper Flow ID allocation mechanism.
536 //
537 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700538
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800539 return true;
540 }
541
542 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700543 * Add a flow entry to the Network MAP.
544 *
545 * @param flowObj the corresponding Flow Path object for the Flow Entry.
546 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700547 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700548 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700549 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700550 // Flow edges
551 // HeadFE (TODO)
552
553 //
554 // Assign the FlowEntry ID.
555 //
556 if ((flowEntry.flowEntryId() == null) ||
557 (flowEntry.flowEntryId().value() == 0)) {
558 long id = getNextFlowEntryId();
559 flowEntry.setFlowEntryId(new FlowEntryId(id));
560 }
561
562 IFlowEntry flowEntryObj = null;
563 boolean found = false;
564 try {
565 if ((flowEntryObj =
566 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
567 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
568 flowEntry.flowEntryId().toString());
569 found = true;
570 } else {
571 flowEntryObj = conn.utils().newFlowEntry(conn);
572 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
573 flowEntry.flowEntryId().toString());
574 }
575 } catch (Exception e) {
576 log.error(":addFlow FlowEntryId:{} failed",
577 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700578 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700579 }
580 if (flowEntryObj == null) {
581 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
582 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700583 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700584 }
585
586 //
587 // Set the Flow Entry key:
588 // - flowEntry.flowEntryId()
589 //
590 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
591 flowEntryObj.setType("flow_entry");
592
593 //
594 // Set the Flow Entry Edges and attributes:
595 // - Switch edge
596 // - InPort edge
597 // - OutPort edge
598 //
599 // - flowEntry.flowEntryMatch()
600 // - flowEntry.flowEntryActions()
601 // - flowEntry.dpid()
602 // - flowEntry.flowEntryUserState()
603 // - flowEntry.flowEntrySwitchState()
604 // - flowEntry.flowEntryErrorState()
605 // - flowEntry.matchInPort()
606 // - flowEntry.matchEthernetFrameType()
607 // - flowEntry.matchSrcIPv4Net()
608 // - flowEntry.matchDstIPv4Net()
609 // - flowEntry.matchSrcMac()
610 // - flowEntry.matchDstMac()
611 // - flowEntry.actionOutput()
612 //
613 ISwitchObject sw =
614 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
615 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
616 flowEntryObj.setSwitch(sw);
617 if (flowEntry.flowEntryMatch().matchInPort()) {
618 IPortObject inport =
619 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
620 flowEntry.flowEntryMatch().inPort().value());
621 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
622 flowEntryObj.setInPort(inport);
623 }
624 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
625 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
626 }
627 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
628 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
629 }
630 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
631 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
632 }
633 if (flowEntry.flowEntryMatch().matchSrcMac()) {
634 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
635 }
636 if (flowEntry.flowEntryMatch().matchDstMac()) {
637 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
638 }
639
640 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
641 if (fa.actionOutput() != null) {
642 IPortObject outport =
643 conn.utils().searchPort(conn,
644 flowEntry.dpid().toString(),
645 fa.actionOutput().port().value());
646 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
647 flowEntryObj.setOutPort(outport);
648 }
649 }
650 // TODO: Hacks with hard-coded state names!
651 if (found)
652 flowEntryObj.setUserState("FE_USER_MODIFY");
653 else
654 flowEntryObj.setUserState("FE_USER_ADD");
655 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
656 //
657 // TODO: Take care of the FlowEntryErrorState.
658 //
659
660 // Flow Entries edges:
661 // Flow
662 // NextFE (TODO)
663 if (! found) {
664 flowObj.addFlowEntry(flowEntryObj);
665 flowEntryObj.setFlow(flowObj);
666 }
667
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700668 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700669 }
670
671 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800672 * Delete a previously added flow.
673 *
674 * @param flowId the Flow ID of the flow to delete.
675 * @return true on success, otherwise false.
676 */
677 @Override
678 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700679 /*
680 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700681 if (flowId.value() == measurementFlowId) {
682 modifiedMeasurementFlowTime = System.nanoTime();
683 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700684 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700685
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800686 IFlowPath flowObj = null;
687 //
688 // We just mark the entries for deletion,
689 // and let the switches remove each individual entry after
690 // it has been removed from the switches.
691 //
692 try {
693 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
694 != null) {
695 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
696 flowId.toString());
697 } else {
698 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
699 flowId.toString());
700 }
701 } catch (Exception e) {
702 // TODO: handle exceptions
703 conn.endTx(Transaction.ROLLBACK);
704 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
705 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700706 if (flowObj == null) {
707 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800708 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700709 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800710
711 //
712 // Find and mark for deletion all Flow Entries
713 //
714 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
715 boolean empty = true; // TODO: an ugly hack
716 for (IFlowEntry flowEntryObj : flowEntries) {
717 empty = false;
718 // flowObj.removeFlowEntry(flowEntryObj);
719 // conn.utils().removeFlowEntry(conn, flowEntryObj);
720 flowEntryObj.setUserState("FE_USER_DELETE");
721 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
722 }
723 // Remove from the database empty flows
724 if (empty)
725 conn.utils().removeFlowPath(conn, flowObj);
726 conn.endTx(Transaction.COMMIT);
727
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800728 return true;
729 }
730
731 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700732 * Clear the state for a previously added flow.
733 *
734 * @param flowId the Flow ID of the flow to clear.
735 * @return true on success, otherwise false.
736 */
737 @Override
738 public boolean clearFlow(FlowId flowId) {
739 IFlowPath flowObj = null;
740 try {
741 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
742 != null) {
743 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
744 flowId.toString());
745 } else {
746 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
747 flowId.toString());
748 }
749 } catch (Exception e) {
750 // TODO: handle exceptions
751 conn.endTx(Transaction.ROLLBACK);
752 log.error(":clearFlow FlowId:{} failed", flowId.toString());
753 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700754 if (flowObj == null) {
755 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700756 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700757 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700758
759 //
760 // Remove all Flow Entries
761 //
762 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
763 for (IFlowEntry flowEntryObj : flowEntries) {
764 flowObj.removeFlowEntry(flowEntryObj);
765 conn.utils().removeFlowEntry(conn, flowEntryObj);
766 }
767 // Remove the Flow itself
768 conn.utils().removeFlowPath(conn, flowObj);
769 conn.endTx(Transaction.COMMIT);
770
771 return true;
772 }
773
774 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800775 * Get a previously added flow.
776 *
777 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800778 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800779 */
780 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800781 public FlowPath getFlow(FlowId flowId) {
782 IFlowPath flowObj = null;
783 try {
784 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
785 != null) {
786 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
787 flowId.toString());
788 } else {
789 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
790 flowId.toString());
791 }
792 } catch (Exception e) {
793 // TODO: handle exceptions
794 conn.endTx(Transaction.ROLLBACK);
795 log.error(":getFlow FlowId:{} failed", flowId.toString());
796 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700797 if (flowObj == null) {
798 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800799 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700800 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800801
802 //
803 // Extract the Flow state
804 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800805 FlowPath flowPath = extractFlowPath(flowObj);
806 conn.endTx(Transaction.COMMIT);
807
808 return flowPath;
809 }
810
811 /**
812 * Get all previously added flows by a specific installer for a given
813 * data path endpoints.
814 *
815 * @param installerId the Caller ID of the installer of the flow to get.
816 * @param dataPathEndpoints the data path endpoints of the flow to get.
817 * @return the Flow Paths if found, otherwise null.
818 */
819 @Override
820 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
821 DataPathEndpoints dataPathEndpoints) {
822 //
823 // TODO: The implementation below is not optimal:
824 // We fetch all flows, and then return only the subset that match
825 // the query conditions.
826 // We should use the appropriate Titan/Gremlin query to filter-out
827 // the flows as appropriate.
828 //
829 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700830 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800831
832 if (allFlows == null) {
833 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700834 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800835 }
836
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800837 for (FlowPath flow : allFlows) {
838 //
839 // TODO: String-based comparison is sub-optimal.
840 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800841 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800842 //
843 if (! flow.installerId().toString().equals(installerId.toString()))
844 continue;
845 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
846 continue;
847 }
848 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
849 continue;
850 }
851 flowPaths.add(flow);
852 }
853
854 if (flowPaths.isEmpty()) {
855 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800856 } else {
857 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
858 }
859
860 return flowPaths;
861 }
862
863 /**
864 * Get all installed flows by all installers for given data path endpoints.
865 *
866 * @param dataPathEndpoints the data path endpoints of the flows to get.
867 * @return the Flow Paths if found, otherwise null.
868 */
869 @Override
870 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
871 //
872 // TODO: The implementation below is not optimal:
873 // We fetch all flows, and then return only the subset that match
874 // the query conditions.
875 // We should use the appropriate Titan/Gremlin query to filter-out
876 // the flows as appropriate.
877 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700878 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
879 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800880
881 if (allFlows == null) {
882 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700883 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800884 }
885
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800886 for (FlowPath flow : allFlows) {
887 //
888 // TODO: String-based comparison is sub-optimal.
889 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800890 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800891 //
892 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
893 continue;
894 }
895 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
896 continue;
897 }
898 flowPaths.add(flow);
899 }
900
901 if (flowPaths.isEmpty()) {
902 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800903 } else {
904 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
905 }
906
907 return flowPaths;
908 }
909
910 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700911 * Get summary of all installed flows by all installers in a given range
912 *
913 * @param flowId the data path endpoints of the flows to get.
914 * @param maxFlows: the maximum number of flows to be returned
915 * @return the Flow Paths if found, otherwise null.
916 */
917 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700918 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
919
920
921
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700922 //
923 // TODO: The implementation below is not optimal:
924 // We fetch all flows, and then return only the subset that match
925 // the query conditions.
926 // We should use the appropriate Titan/Gremlin query to filter-out
927 // the flows as appropriate.
928 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700929 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700930
Jonathan Hart01f2d272013-04-04 20:03:46 -0700931 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
932
933 return flowPathsWithoutFlowEntries;
934
935 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700936 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -0700937
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700938 if (allFlows == null) {
939 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700940 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700941 }
942
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -0700943 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700944
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700945 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700946 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700947
Pavlin Radoslavov96b43422013-04-04 19:14:56 -0700948 // start from desired flowId
949 if (flow.flowId().value() < flowId.value()) {
950 continue;
951 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700952
953 // Summarize by making null flow entry fields that are not relevant to report
954 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
955 flowEntry.setFlowEntryActions(null);
956 flowEntry.setFlowEntryMatch(null);
957 }
958
959 flowPaths.add(flow);
960 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
961 break;
962 }
963 }
964
965 if (flowPaths.isEmpty()) {
966 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700967 } else {
968 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
969 }
970
971 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -0700972 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700973 }
974
975 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800976 * Get all installed flows by all installers.
977 *
978 * @return the Flow Paths if found, otherwise null.
979 */
980 @Override
981 public ArrayList<FlowPath> getAllFlows() {
982 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700983 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800984
985 try {
986 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
987 log.debug("Get all FlowPaths: found FlowPaths");
988 } else {
989 log.debug("Get all FlowPaths: no FlowPaths found");
990 }
991 } catch (Exception e) {
992 // TODO: handle exceptions
993 conn.endTx(Transaction.ROLLBACK);
994 log.error(":getAllFlowPaths failed");
995 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700996 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
997 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700998 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700999 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001000
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001001 for (IFlowPath flowObj : flowPathsObj) {
1002 //
1003 // Extract the Flow state
1004 //
1005 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001006 if (flowPath != null)
1007 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001008 }
1009
1010 conn.endTx(Transaction.COMMIT);
1011
1012 return flowPaths;
1013 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001014
1015 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1016 Iterable<IFlowPath> flowPathsObj = null;
1017 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1018 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1019
1020 try {
1021 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1022 log.debug("Get all FlowPaths: found FlowPaths");
1023 } else {
1024 log.debug("Get all FlowPaths: no FlowPaths found");
1025 }
1026 } catch (Exception e) {
1027 // TODO: handle exceptions
1028 conn.endTx(Transaction.ROLLBACK);
1029 log.error(":getAllFlowPaths failed");
1030 }
1031 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1032 return new ArrayList<IFlowPath>(); // No Flows found
1033 }
1034
1035 for (IFlowPath flowObj : flowPathsObj){
1036 flowPathsObjArray.add(flowObj);
1037 }
1038 /*
1039 for (IFlowPath flowObj : flowPathsObj) {
1040 //
1041 // Extract the Flow state
1042 //
1043 FlowPath flowPath = extractFlowPath(flowObj);
1044 if (flowPath != null)
1045 flowPaths.add(flowPath);
1046 }
1047 */
1048
1049 //conn.endTx(Transaction.COMMIT);
1050
1051 return flowPathsObjArray;
1052 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001053
1054 /**
1055 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1056 *
1057 * @param flowObj the object to extract the Flow Path State from.
1058 * @return the extracted Flow Path State.
1059 */
1060 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001061 //
1062 // Extract the Flow state
1063 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001064 String flowIdStr = flowObj.getFlowId();
1065 String installerIdStr = flowObj.getInstallerId();
1066 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001067 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001068 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001069 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001070
1071 if ((flowIdStr == null) ||
1072 (installerIdStr == null) ||
1073 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001074 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001075 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001076 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001077 // TODO: A work-around, becauuse of some bogus database objects
1078 return null;
1079 }
1080
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001081 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001082 flowPath.setFlowId(new FlowId(flowIdStr));
1083 flowPath.setInstallerId(new CallerId(installerIdStr));
1084 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001085 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001086 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001087 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001088 //
1089 // Extract the match conditions common for all Flow Entries
1090 //
1091 {
1092 FlowEntryMatch match = new FlowEntryMatch();
1093 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1094 if (matchEthernetFrameType != null)
1095 match.enableEthernetFrameType(matchEthernetFrameType);
1096 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1097 if (matchSrcIPv4Net != null)
1098 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1099 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1100 if (matchDstIPv4Net != null)
1101 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1102 String matchSrcMac = flowObj.getMatchSrcMac();
1103 if (matchSrcMac != null)
1104 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1105 String matchDstMac = flowObj.getMatchDstMac();
1106 if (matchDstMac != null)
1107 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1108 flowPath.setFlowEntryMatch(match);
1109 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001110
1111 //
1112 // Extract all Flow Entries
1113 //
1114 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1115 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001116 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1117 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001118 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001119 flowPath.dataPath().flowEntries().add(flowEntry);
1120 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001121
1122 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001123 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001124
1125 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001126 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1127 *
1128 * @param flowEntryObj the object to extract the Flow Entry State from.
1129 * @return the extracted Flow Entry State.
1130 */
1131 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1132 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1133 String switchDpidStr = flowEntryObj.getSwitchDpid();
1134 String userState = flowEntryObj.getUserState();
1135 String switchState = flowEntryObj.getSwitchState();
1136
1137 if ((flowEntryIdStr == null) ||
1138 (switchDpidStr == null) ||
1139 (userState == null) ||
1140 (switchState == null)) {
1141 // TODO: A work-around, becauuse of some bogus database objects
1142 return null;
1143 }
1144
1145 FlowEntry flowEntry = new FlowEntry();
1146 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1147 flowEntry.setDpid(new Dpid(switchDpidStr));
1148
1149 //
1150 // Extract the match conditions
1151 //
1152 FlowEntryMatch match = new FlowEntryMatch();
1153 Short matchInPort = flowEntryObj.getMatchInPort();
1154 if (matchInPort != null)
1155 match.enableInPort(new Port(matchInPort));
1156 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1157 if (matchEthernetFrameType != null)
1158 match.enableEthernetFrameType(matchEthernetFrameType);
1159 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1160 if (matchSrcIPv4Net != null)
1161 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1162 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1163 if (matchDstIPv4Net != null)
1164 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1165 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1166 if (matchSrcMac != null)
1167 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1168 String matchDstMac = flowEntryObj.getMatchDstMac();
1169 if (matchDstMac != null)
1170 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1171 flowEntry.setFlowEntryMatch(match);
1172
1173 //
1174 // Extract the actions
1175 //
1176 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1177 Short actionOutputPort = flowEntryObj.getActionOutput();
1178 if (actionOutputPort != null) {
1179 FlowEntryAction action = new FlowEntryAction();
1180 action.setActionOutput(new Port(actionOutputPort));
1181 actions.add(action);
1182 }
1183 flowEntry.setFlowEntryActions(actions);
1184 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1185 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1186 //
1187 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1188 // and FlowEntryErrorState.
1189 //
1190 return flowEntry;
1191 }
1192
1193 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001194 * Add and maintain a shortest-path flow.
1195 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001196 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001197 *
1198 * @param flowPath the Flow Path with the endpoints and the match
1199 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001200 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001201 */
1202 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001203 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001204 String dataPathSummaryStr = null;
1205
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001206 //
1207 // Do the shortest path computation
1208 //
1209 DataPath dataPath =
1210 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1211 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001212 if (dataPath == null) {
1213 // We need the DataPath to populate the Network MAP
1214 dataPath = new DataPath();
1215 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1216 dataPath.setDstPort(flowPath.dataPath().dstPort());
1217 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001218
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001219 // Compute the Data Path summary
1220 dataPathSummaryStr = dataPath.dataPathSummary();
1221
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001222 //
1223 // Set the incoming port matching and the outgoing port output
1224 // actions for each flow entry.
1225 //
1226 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1227 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001228 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001229 flowEntry.setFlowEntryMatch(flowEntryMatch);
1230 flowEntryMatch.enableInPort(flowEntry.inPort());
1231
1232 // Set the outgoing port output action
1233 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1234 if (flowEntryActions == null) {
1235 flowEntryActions = new ArrayList<FlowEntryAction>();
1236 flowEntry.setFlowEntryActions(flowEntryActions);
1237 }
1238 FlowEntryAction flowEntryAction = new FlowEntryAction();
1239 flowEntryAction.setActionOutput(flowEntry.outPort());
1240 flowEntryActions.add(flowEntryAction);
1241 }
1242
1243 //
1244 // Prepare the computed Flow Path
1245 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001246 FlowPath computedFlowPath = new FlowPath();
1247 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1248 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1249 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001250 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001251
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001252 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001253 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001254 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001255
1256 // TODO: Mark the flow for maintenance purpose
1257
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001258 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001259 }
1260
1261 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001262 * Reconcile a flow.
1263 *
1264 * @param flowObj the flow that needs to be reconciliated.
1265 * @param newDataPath the new data path to use.
1266 * @return true on success, otherwise false.
1267 */
1268 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1269 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1270
1271 //
1272 // Set the incoming port matching and the outgoing port output
1273 // actions for each flow entry.
1274 //
1275 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1276 // Set the incoming port matching
1277 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1278 flowEntry.setFlowEntryMatch(flowEntryMatch);
1279 flowEntryMatch.enableInPort(flowEntry.inPort());
1280
1281 // Set the outgoing port output action
1282 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1283 if (flowEntryActions == null) {
1284 flowEntryActions = new ArrayList<FlowEntryAction>();
1285 flowEntry.setFlowEntryActions(flowEntryActions);
1286 }
1287 FlowEntryAction flowEntryAction = new FlowEntryAction();
1288 flowEntryAction.setActionOutput(flowEntry.outPort());
1289 flowEntryActions.add(flowEntryAction);
1290 }
1291
1292 //
1293 // Remove the old Flow Entries, and add the new Flow Entries
1294 //
1295
1296 //
1297 // Remove the Flow Entries from the Network MAP
1298 //
1299 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1300 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1301 for (IFlowEntry flowEntryObj : flowEntries) {
1302 String dpidStr = flowEntryObj.getSwitchDpid();
1303 if (dpidStr == null)
1304 continue;
1305 Dpid dpid = new Dpid(dpidStr);
1306 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1307
1308 flowEntryObj.setUserState("FE_USER_DELETE");
1309 if (mySwitch == null) {
1310 //
1311 // Not my switch. Mark it for deletion in the Network MAP
1312 //
1313 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1314 continue;
1315 }
1316
1317 deleteFlowEntries.add(flowEntryObj);
1318
1319 //
1320 // Delete the flow entry from the switch
1321 //
1322 // flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1323 installFlowEntry(mySwitch, flowObj, flowEntryObj);
1324 // flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1325 }
1326 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
1327 flowObj.removeFlowEntry(flowEntryObj);
1328 conn.utils().removeFlowEntry(conn, flowEntryObj);
1329 }
1330
1331 //
1332 // Install the new shortest path into the Network MAP and the switches.
1333 //
1334 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1335 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1336 IFlowEntry flowEntryObj = addFlowEntry(flowObj, flowEntry);
1337 if (flowEntryObj == null) {
1338 //
1339 // TODO: Remove the "new Object[] wrapper in the statement
1340 // below after the SLF4J logger is upgraded to
1341 // Version 1.7.5
1342 //
1343 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1344 new Object[] {
1345 flowEntry.dpid(),
1346 newDataPath.srcPort(),
1347 newDataPath.dstPort()
1348 });
1349 continue;
1350 }
1351
1352 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1353 if (mySwitch == null) {
1354 // Not my switch: just add to the Network MAP
1355 continue;
1356 }
1357
1358 // Install the Flow Entry into the switch
1359 if (installFlowEntry(mySwitch, flowObj, flowEntryObj)) {
1360 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1361 }
1362 }
1363
1364 //
1365 // Set the Data Path Summary
1366 //
1367 String dataPathSummaryStr = newDataPath.dataPathSummary();
1368 flowObj.setDataPathSummary(dataPathSummaryStr);
1369
1370 return true;
1371 }
1372
1373 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001374 * Reconcile all flows in a set.
1375 *
1376 * @param flowObjSet the set of flows that need to be reconciliated.
1377 */
1378 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1379 if (! flowObjSet.iterator().hasNext())
1380 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001381 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001382 }
1383
1384 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001385 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001386 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001387 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001388 * @param flowObj the flow path object for the flow entry to install.
1389 * @param flowEntryObj the flow entry object to install.
1390 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001391 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001392 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1393 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001394 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1395 if (flowEntryIdStr == null)
1396 return false;
1397 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001398 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001399 if (userState == null)
1400 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001401
1402 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001403 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001404 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001405 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1406 .getMessage(OFType.FLOW_MOD);
1407 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001408
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001409 short flowModCommand = OFFlowMod.OFPFC_ADD;
1410 if (userState.equals("FE_USER_ADD")) {
1411 flowModCommand = OFFlowMod.OFPFC_ADD;
1412 } else if (userState.equals("FE_USER_MODIFY")) {
1413 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1414 } else if (userState.equals("FE_USER_DELETE")) {
1415 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1416 } else {
1417 // Unknown user state. Ignore the entry
1418 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1419 flowEntryId.toString(), userState);
1420 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001421 }
1422
1423 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001424 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001425 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001426 // NOTE: The Flow matching conditions common for all Flow Entries are
1427 // used ONLY if a Flow Entry does NOT have the corresponding matching
1428 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001429 //
1430 OFMatch match = new OFMatch();
1431 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001432
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001433 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001434 Short matchInPort = flowEntryObj.getMatchInPort();
1435 if (matchInPort != null) {
1436 match.setInputPort(matchInPort);
1437 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1438 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001439
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001440 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001441 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1442 if (matchEthernetFrameType == null)
1443 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1444 if (matchEthernetFrameType != null) {
1445 match.setDataLayerType(matchEthernetFrameType);
1446 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1447 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001448
1449 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001450 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1451 if (matchSrcIPv4Net == null)
1452 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1453 if (matchSrcIPv4Net != null) {
1454 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1455 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001456
1457 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001458 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1459 if (matchDstIPv4Net == null)
1460 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1461 if (matchDstIPv4Net != null) {
1462 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1463 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001464
1465 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001466 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1467 if (matchSrcMac == null)
1468 matchSrcMac = flowObj.getMatchSrcMac();
1469 if (matchSrcMac != null) {
1470 match.setDataLayerSource(matchSrcMac);
1471 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1472 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001473
1474 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001475 String matchDstMac = flowEntryObj.getMatchDstMac();
1476 if (matchDstMac == null)
1477 matchDstMac = flowObj.getMatchDstMac();
1478 if (matchDstMac != null) {
1479 match.setDataLayerDestination(matchDstMac);
1480 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1481 }
1482
1483 //
1484 // Fetch the actions
1485 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001486 // TODO: For now we support only the "OUTPUT" actions.
1487 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001488 List<OFAction> actions = new ArrayList<OFAction>();
1489 Short actionOutputPort = flowEntryObj.getActionOutput();
1490 if (actionOutputPort != null) {
1491 OFActionOutput action = new OFActionOutput();
1492 // XXX: The max length is hard-coded for now
1493 action.setMaxLength((short)0xffff);
1494 action.setPort(actionOutputPort);
1495 actions.add(action);
1496 }
1497
1498 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1499 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1500 .setPriority(PRIORITY_DEFAULT)
1501 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1502 .setCookie(cookie)
1503 .setCommand(flowModCommand)
1504 .setMatch(match)
1505 .setActions(actions)
1506 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1507 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1508 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1509 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1510 if (actionOutputPort != null)
1511 fm.setOutPort(actionOutputPort);
1512 }
1513
1514 //
1515 // TODO: Set the following flag
1516 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1517 // See method ForwardingBase::pushRoute()
1518 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001519
1520 //
1521 // Write the message to the switch
1522 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001523 log.debug("MEASUREMENT: Installing flow entry " + userState +
1524 " into switch DPID: " +
1525 mySwitch.getStringId() +
1526 " flowEntryId: " + flowEntryId.toString() +
1527 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1528 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1529 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001530 try {
1531 messageDamper.write(mySwitch, fm, null);
1532 mySwitch.flush();
1533 //
1534 // TODO: We should use the OpenFlow Barrier mechanism
1535 // to check for errors, and update the SwitchState
1536 // for a flow entry after the Barrier message is
1537 // is received.
1538 //
1539 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1540 } catch (IOException e) {
1541 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001542 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001543 }
1544
1545 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001546 }
1547
1548 /**
1549 * Install a Flow Entry on a switch.
1550 *
1551 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001552 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001553 * @param flowEntry the flow entry to install.
1554 * @return true on success, otherwise false.
1555 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001556 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1557 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001558 //
1559 // Create the OpenFlow Flow Modification Entry to push
1560 //
1561 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1562 .getMessage(OFType.FLOW_MOD);
1563 long cookie = flowEntry.flowEntryId().value();
1564
1565 short flowModCommand = OFFlowMod.OFPFC_ADD;
1566 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1567 flowModCommand = OFFlowMod.OFPFC_ADD;
1568 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1569 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1570 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1571 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1572 } else {
1573 // Unknown user state. Ignore the entry
1574 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1575 flowEntry.flowEntryId().toString(),
1576 flowEntry.flowEntryUserState());
1577 return false;
1578 }
1579
1580 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001581 // Fetch the match conditions.
1582 //
1583 // NOTE: The Flow matching conditions common for all Flow Entries are
1584 // used ONLY if a Flow Entry does NOT have the corresponding matching
1585 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001586 //
1587 OFMatch match = new OFMatch();
1588 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001589 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1590 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1591
1592 // Match the Incoming Port
1593 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001594 if (matchInPort != null) {
1595 match.setInputPort(matchInPort.value());
1596 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1597 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001598
1599 // Match the Ethernet Frame Type
1600 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1601 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1602 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1603 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001604 if (matchEthernetFrameType != null) {
1605 match.setDataLayerType(matchEthernetFrameType);
1606 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1607 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001608
1609 // Match the Source IPv4 Network prefix
1610 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1611 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1612 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1613 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001614 if (matchSrcIPv4Net != null) {
1615 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1616 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001617
1618 // Natch the Destination IPv4 Network prefix
1619 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1620 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1621 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1622 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001623 if (matchDstIPv4Net != null) {
1624 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1625 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001626
1627 // Match the Source MAC address
1628 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1629 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1630 matchSrcMac = flowPathMatch.srcMac();
1631 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001632 if (matchSrcMac != null) {
1633 match.setDataLayerSource(matchSrcMac.toString());
1634 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1635 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001636
1637 // Match the Destination MAC address
1638 MACAddress matchDstMac = flowEntryMatch.dstMac();
1639 if ((matchDstMac == null) && (flowPathMatch != null)) {
1640 matchDstMac = flowPathMatch.dstMac();
1641 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001642 if (matchDstMac != null) {
1643 match.setDataLayerDestination(matchDstMac.toString());
1644 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1645 }
1646
1647 //
1648 // Fetch the actions
1649 //
1650 // TODO: For now we support only the "OUTPUT" actions.
1651 //
1652 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1653 List<OFAction> actions = new ArrayList<OFAction>();
1654 ArrayList<FlowEntryAction> flowEntryActions =
1655 flowEntry.flowEntryActions();
1656 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1657 FlowEntryAction.ActionOutput actionOutput =
1658 flowEntryAction.actionOutput();
1659 if (actionOutput != null) {
1660 short actionOutputPort = actionOutput.port().value();
1661 OFActionOutput action = new OFActionOutput();
1662 // XXX: The max length is hard-coded for now
1663 action.setMaxLength((short)0xffff);
1664 action.setPort(actionOutputPort);
1665 actions.add(action);
1666 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1667 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1668 fm.setOutPort(actionOutputPort);
1669 }
1670 }
1671 }
1672
1673 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1674 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1675 .setPriority(PRIORITY_DEFAULT)
1676 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1677 .setCookie(cookie)
1678 .setCommand(flowModCommand)
1679 .setMatch(match)
1680 .setActions(actions)
1681 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1682
1683 //
1684 // TODO: Set the following flag
1685 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1686 // See method ForwardingBase::pushRoute()
1687 //
1688
1689 //
1690 // Write the message to the switch
1691 //
1692 try {
1693 messageDamper.write(mySwitch, fm, null);
1694 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001695 //
1696 // TODO: We should use the OpenFlow Barrier mechanism
1697 // to check for errors, and update the SwitchState
1698 // for a flow entry after the Barrier message is
1699 // is received.
1700 //
1701 // TODO: The FlowEntry Object in Titan should be set
1702 // to FE_SWITCH_UPDATED.
1703 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001704 } catch (IOException e) {
1705 log.error("Failure writing flow mod from network map", e);
1706 return false;
1707 }
1708 return true;
1709 }
1710
1711 /**
1712 * Remove a Flow Entry from a switch.
1713 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001714 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001715 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001716 * @param flowEntry the flow entry to remove.
1717 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001718 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001719 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1720 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001721 //
1722 // The installFlowEntry() method implements both installation
1723 // and removal of flow entries.
1724 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001725 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001726 }
1727
1728 /**
1729 * Install a Flow Entry on a remote controller.
1730 *
1731 * TODO: We need it now: Jono
1732 * - For now it will make a REST call to the remote controller.
1733 * - Internally, it needs to know the name of the remote controller.
1734 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001735 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001736 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001737 * @return true on success, otherwise false.
1738 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001739 public boolean installRemoteFlowEntry(FlowPath flowPath,
1740 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001741 // TODO: We need it now: Jono
1742 // - For now it will make a REST call to the remote controller.
1743 // - Internally, it needs to know the name of the remote controller.
1744 return true;
1745 }
1746
1747 /**
1748 * Remove a flow entry on a remote controller.
1749 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001750 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001751 * @param flowEntry the flow entry to remove.
1752 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001753 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001754 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1755 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001756 //
1757 // The installRemoteFlowEntry() method implements both installation
1758 // and removal of flow entries.
1759 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001760 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001761 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001762}