blob: ba87666fc8d2ec349365925045d613d493114df6 [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 Radoslavov01391c92013-03-14 17:13:21 -070012import java.util.TreeMap;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070013import java.util.Collections;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070014import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080015import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070016import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070019import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080020import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080021
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IFloodlightProviderService;
23import net.floodlightcontroller.core.INetMapStorage;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
25import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070026import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070027import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070028import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080030import net.floodlightcontroller.core.module.FloodlightModuleContext;
31import net.floodlightcontroller.core.module.FloodlightModuleException;
32import net.floodlightcontroller.core.module.IFloodlightModule;
33import net.floodlightcontroller.core.module.IFloodlightService;
34import net.floodlightcontroller.flowcache.IFlowService;
35import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
36import net.floodlightcontroller.restserver.IRestApiService;
37import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.DataPath;
39import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080040import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070042import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080045import net.floodlightcontroller.util.FlowEntrySwitchState;
46import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080047import net.floodlightcontroller.util.FlowId;
48import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070049import net.floodlightcontroller.util.IPv4Net;
50import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080051import net.floodlightcontroller.util.OFMessageDamper;
52import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070053import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070054import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080055import net.onrc.onos.util.GraphDBConnection;
56import net.onrc.onos.util.GraphDBConnection.Transaction;
57
58import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
60import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070061import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080065
66import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070069public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080072
73 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070075 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070076 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077
78 protected OFMessageDamper messageDamper;
79
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070080 //
81 // TODO: Values copied from elsewhere (class LearningSwitch).
82 // The local copy should go away!
83 //
84 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
85 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
86 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
87 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
88 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080089
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070090 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070091 private static long measurementFlowId = 100000;
92 private static String measurementFlowIdStr = "0x186a0"; // 100000
93 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070094
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080095 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080096 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
97
98 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070099 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800100 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700101 private final ScheduledExecutorService measureMapReaderScheduler =
102 Executors.newScheduledThreadPool(1);
103 private final ScheduledExecutorService mapReaderScheduler =
104 Executors.newScheduledThreadPool(1);
105
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700106 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
107 private ThreadPoolExecutor shortestPathExecutor =
108 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
109
110 class ShortestPathTask implements Runnable {
111 private int hint;
112 private ITopoRouteService topoRouteService;
113 private ArrayList<DataPath> dpList;
114
115 public ShortestPathTask(int hint,
116 ITopoRouteService topoRouteService,
117 ArrayList<DataPath> dpList) {
118 this.hint = hint;
119 this.topoRouteService = topoRouteService;
120 this.dpList = dpList;
121 }
122
123 @Override
124 public void run() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700125 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700126 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
127 log.debug(logMsg);
128 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700129 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700130 for (DataPath dp : this.dpList) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700131 topoRouteService.getTopoShortestPath(dp.srcPort(), dp.dstPort());
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700132 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700133 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700134 long estimatedTime = System.nanoTime() - startTime;
135 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
136 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
137 log.debug(logMsg);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700138 */
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700139 }
140 }
141
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700142 final Runnable measureShortestPath = new Runnable() {
143 public void run() {
144 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
145 if (floodlightProvider == null) {
146 log.debug("FloodlightProvider service not found!");
147 return;
148 }
149
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700150 if (topoRouteService == null) {
151 log.debug("Topology Route Service not found");
152 return;
153 }
154
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700155 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
156 if (leftoverQueueSize > 0) {
157 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
158 log.debug(logMsg);
159 return;
160 }
161 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
162
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700163 //
164 // Recompute the Shortest Paths for all Flows
165 //
166 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700167 int hint = 0;
168 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700169 long startTime = System.nanoTime();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700170
171 topoRouteService.prepareShortestPathTopo();
172
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700173 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
174 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 FlowId flowId = new FlowId(flowPathObj.getFlowId());
176
177 // log.debug("Found Path {}", flowId.toString());
178 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
179 Port srcPort = new Port(flowPathObj.getSrcPort());
180 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
181 Port dstPort = new Port(flowPathObj.getDstPort());
182 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
183 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700184
185 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700186 DataPath dp = new DataPath();
187 dp.setSrcPort(srcSwitchPort);
188 dp.setDstPort(dstSwitchPort);
189 dpList.add(dp);
190 if ((dpList.size() % 10) == 0) {
191 shortestPathExecutor.execute(
192 new ShortestPathTask(hint, topoRouteService,
193 dpList));
194 dpList = new ArrayList<DataPath>();
195 hint++;
196 }
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700197 */
198
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700199 DataPath dataPath =
200 topoRouteService.getTopoShortestPath(srcSwitchPort,
201 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700202 counter++;
203 }
204 if (dpList.size() > 0) {
205 shortestPathExecutor.execute(
206 new ShortestPathTask(hint, topoRouteService,
207 dpList));
208 }
209
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700210 /*
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700211 // Wait for all tasks to finish
212 try {
213 while (shortestPathExecutor.getQueue().size() > 0) {
214 Thread.sleep(100);
215 }
216 } catch (InterruptedException ex) {
217 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700218 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700219 */
220
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700221 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700222 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700223
224 long estimatedTime = System.nanoTime() - startTime;
225 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
226 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
227 log.debug(logMsg);
228 }
229 };
230
231 final Runnable measureMapReader = new Runnable() {
232 public void run() {
233 if (floodlightProvider == null) {
234 log.debug("FloodlightProvider service not found!");
235 return;
236 }
237
238 //
239 // Fetch all Flow Entries
240 //
241 int counter = 0;
242 long startTime = System.nanoTime();
243 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
244 for (IFlowEntry flowEntryObj : allFlowEntries) {
245 counter++;
246 FlowEntryId flowEntryId =
247 new FlowEntryId(flowEntryObj.getFlowEntryId());
248 String userState = flowEntryObj.getUserState();
249 String switchState = flowEntryObj.getSwitchState();
250 }
251 conn.endTx(Transaction.COMMIT);
252
253 long estimatedTime = System.nanoTime() - startTime;
254 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
255 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
256 log.debug(logMsg);
257 }
258 };
259
260 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800261 public void run() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800262 if (floodlightProvider == null) {
263 log.debug("FloodlightProvider service not found!");
264 return;
265 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000266 Map<Long, IOFSwitch> mySwitches =
267 floodlightProvider.getSwitches();
268 Map<Long, IFlowEntry> myFlowEntries =
269 new TreeMap<Long, IFlowEntry>();
270 LinkedList<IFlowEntry> deleteFlowEntries =
271 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700272
273 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700274 // Fetch and recompute the Shortest Path for those
275 // Flow Paths this controller is responsible for.
276 //
277
278 /*
279 * TODO: For now, the computation of the reconciliation is
280 * commented-out.
281 */
282 /*
283 topoRouteService.prepareShortestPathTopo();
284 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
285 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
286 for (IFlowPath flowPathObj : allFlowPaths) {
287 if (flowPathObj == null)
288 continue;
289 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
290 if (dataPathSummaryStr == null)
291 continue; // Could be invalid entry?
292 if (dataPathSummaryStr.isEmpty())
293 continue; // No need to maintain this flow
294
295 // Fetch the fields needed to recompute the shortest path
296 String flowIdStr = flowPathObj.getFlowId();
297 String srcDpidStr = flowPathObj.getSrcSwitch();
298 Short srcPortShort = flowPathObj.getSrcPort();
299 String dstDpidStr = flowPathObj.getDstSwitch();
300 Short dstPortShort = flowPathObj.getDstPort();
301 if ((flowIdStr == null) ||
302 (srcDpidStr == null) ||
303 (srcPortShort == null) ||
304 (dstDpidStr == null) ||
305 (dstPortShort == null)) {
306 log.debug("IGNORING Flow Path entry with null fields");
307 continue;
308 }
309
310 FlowId flowId = new FlowId(flowIdStr);
311 Dpid srcDpid = new Dpid(srcDpidStr);
312 Port srcPort = new Port(srcPortShort);
313 Dpid dstDpid = new Dpid(dstDpidStr);
314 Port dstPort = new Port(dstPortShort);
315 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
316 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
317 DataPath dataPath =
318 topoRouteService.getTopoShortestPath(srcSwitchPort,
319 dstSwitchPort);
320 String newDataPathSummaryStr = dataPath.dataPathSummary();
321 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
322 continue; // Nothing changed
323
324 //
325 // Use the source DPID as a heuristic to decide
326 // which controller is responsible for maintaining the
327 // shortest path.
328 // NOTE: This heuristic is error-prone: if the switch
329 // goes away and no controller is responsible for that
330 // switch, then the original Flow Path is not cleaned-up
331 //
332 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
333 if (mySwitch == null)
334 continue; // Ignore: not my responsibility
335
336 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
337 flowId.toString());
338 flowObjSet.add(flowPathObj);
339 }
340 reconcileFlows(flowObjSet);
341 topoRouteService.dropShortestPathTopo();
342 */
343
344 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700345 // Fetch all Flow Entries and select only my Flow Entries
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000346 // that need to be undated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700347 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000348 Iterable<IFlowEntry> allFlowEntries =
349 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700350 for (IFlowEntry flowEntryObj : allFlowEntries) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000351 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700352 String userState = flowEntryObj.getUserState();
353 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000354 String dpidStr = flowEntryObj.getSwitchDpid();
355 if ((flowEntryIdStr == null) ||
356 (userState == null) ||
357 (switchState == null) ||
358 (dpidStr == null)) {
359 log.debug("IGNORING Flow Entry entry with null fields");
360 continue;
361 }
362 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
363 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800364
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000365 /*
366 log.debug("Found Flow Entry Id = {} {}",
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700367 flowEntryId.toString(),
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000368 "DPID = " + dpid.toString() +
369 " User State: " + userState +
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700370 " Switch State: " + switchState);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000371 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800372
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000373 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
374 continue; // Ignore the entry: nothing to do
375
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800376 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000377 if (mySwitch == null)
378 continue; // Ignore the entry: not my switch
379
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700380 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
381 }
382
383 //
384 // Process my Flow Entries
385 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700386 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700387 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
388 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700389 // Code for measurement purpose
390 {
391 IFlowPath flowObj =
392 conn.utils().getFlowPathByFlowEntry(conn,
393 flowEntryObj);
394 if ((flowObj != null) &&
395 flowObj.getFlowId().equals(measurementFlowIdStr)) {
396 processed_measurement_flow = true;
397 }
398 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700399
400 //
401 // TODO: Eliminate the re-fetching of flowEntryId,
402 // userState, switchState, and dpid from the flowEntryObj.
403 //
404 FlowEntryId flowEntryId =
405 new FlowEntryId(flowEntryObj.getFlowEntryId());
406 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
407 String userState = flowEntryObj.getUserState();
408 String switchState = flowEntryObj.getSwitchState();
409 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000410 if (mySwitch == null)
411 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800412
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700413 // TODO: PAVPAVPAV: FROM HERE...
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 //
415 // Create the Open Flow Flow Modification Entry to push
416 //
417 OFFlowMod fm =
418 (OFFlowMod) floodlightProvider.getOFMessageFactory()
419 .getMessage(OFType.FLOW_MOD);
420 long cookie = flowEntryId.value();
421
422 short flowModCommand = OFFlowMod.OFPFC_ADD;
423 if (userState.equals("FE_USER_ADD")) {
424 flowModCommand = OFFlowMod.OFPFC_ADD;
425 } else if (userState.equals("FE_USER_MODIFY")) {
426 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
427 } else if (userState.equals("FE_USER_DELETE")) {
428 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
429 } else {
430 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700431 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
432 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800433 continue;
434 }
435
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700436 //
437 // Fetch the match conditions
438 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700440 match.setWildcards(OFMatch.OFPFW_ALL);
441 Short matchInPort = flowEntryObj.getMatchInPort();
442 if (matchInPort != null) {
443 match.setInputPort(matchInPort);
444 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
445 }
446 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
447 if (matchEthernetFrameType != null) {
448 match.setDataLayerType(matchEthernetFrameType);
449 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
450 }
451 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
452 if (matchSrcIPv4Net != null) {
453 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
454 }
455 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
456 if (matchDstIPv4Net != null) {
457 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
458 }
459 String matchSrcMac = flowEntryObj.getMatchSrcMac();
460 if (matchSrcMac != null) {
461 match.setDataLayerSource(matchSrcMac);
462 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
463 }
464 String matchDstMac = flowEntryObj.getMatchDstMac();
465 if (matchDstMac != null) {
466 match.setDataLayerDestination(matchDstMac);
467 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
468 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700469
470 //
471 // Fetch the actions
472 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800473 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700474 Short actionOutputPort = flowEntryObj.getActionOutput();
475 if (actionOutputPort != null) {
476 OFActionOutput action = new OFActionOutput();
477 // XXX: The max length is hard-coded for now
478 action.setMaxLength((short)0xffff);
479 action.setPort(actionOutputPort);
480 actions.add(action);
481 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800482
483 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
484 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700485 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800486 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
487 .setCookie(cookie)
488 .setCommand(flowModCommand)
489 .setMatch(match)
490 .setActions(actions)
491 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700492 fm.setOutPort(OFPort.OFPP_NONE.getValue());
493 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
494 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
495 if (actionOutputPort != null)
496 fm.setOutPort(actionOutputPort);
497 }
498
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800499 //
500 // TODO: Set the following flag
501 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
502 // See method ForwardingBase::pushRoute()
503 //
504 try {
505 messageDamper.write(mySwitch, fm, null);
506 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000507 //
508 // TODO: We should use the OpenFlow Barrier mechanism
509 // to check for errors, and update the SwitchState
510 // for a flow entry after the Barrier message is
511 // is received.
512 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800513 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
514 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000515 // An entry that needs to be deleted.
516 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800517 }
518 } catch (IOException e) {
519 log.error("Failure writing flow mod from network map", e);
520 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700521 // TODO: XXX: PAVPAVPAV: TO HERE.
522 // TODO: XXX: PAVPAVPAV: Update the flowEntryObj
523 // to "FE_SWITCH_UPDATED" in the new (refactored) code.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800524 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000525
526 //
527 // Delete all entries marked for deletion
528 //
529 // TODO: We should use the OpenFlow Barrier mechanism
530 // to check for errors, and delete the Flow Entries after the
531 // Barrier message is received.
532 //
533 while (! deleteFlowEntries.isEmpty()) {
534 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
535 IFlowPath flowObj =
536 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
537 if (flowObj == null) {
538 log.debug("Did not find FlowPath to be deleted");
539 continue;
540 }
541 flowObj.removeFlowEntry(flowEntryObj);
542 conn.utils().removeFlowEntry(conn, flowEntryObj);
543
544 // Test whether the last flow entry
545 Iterable<IFlowEntry> tmpflowEntries =
546 flowObj.getFlowEntries();
547 boolean found = false;
548 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
549 found = true;
550 break;
551 }
552 if (! found) {
553 // Remove the Flow Path as well
554 conn.utils().removeFlowPath(conn, flowObj);
555 }
556 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800557 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700558
559 if (processed_measurement_flow) {
560 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
561 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
562 (double)estimatedTime / 1000000000 + " sec";
563 log.debug(logMsg);
564 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800565 }
566 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700567
568 /*
569 final ScheduledFuture<?> measureShortestPathHandle =
570 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
571 */
572
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700573 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700574 final ScheduledFuture<?> measureMapReaderHandle =
575 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700576 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700577
578 final ScheduledFuture<?> mapReaderHandle =
579 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800580
581 @Override
582 public void init(String conf) {
583 conn = GraphDBConnection.getInstance(conf);
584 }
585
586 public void finalize() {
587 close();
588 }
589
590 @Override
591 public void close() {
592 conn.close();
593 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800594
595 @Override
596 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
597 Collection<Class<? extends IFloodlightService>> l =
598 new ArrayList<Class<? extends IFloodlightService>>();
599 l.add(IFlowService.class);
600 return l;
601 }
602
603 @Override
604 public Map<Class<? extends IFloodlightService>, IFloodlightService>
605 getServiceImpls() {
606 Map<Class<? extends IFloodlightService>,
607 IFloodlightService> m =
608 new HashMap<Class<? extends IFloodlightService>,
609 IFloodlightService>();
610 m.put(IFlowService.class, this);
611 return m;
612 }
613
614 @Override
615 public Collection<Class<? extends IFloodlightService>>
616 getModuleDependencies() {
617 Collection<Class<? extends IFloodlightService>> l =
618 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800619 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700620 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800621 l.add(IRestApiService.class);
622 return l;
623 }
624
625 @Override
626 public void init(FloodlightModuleContext context)
627 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700628 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800629 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700630 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800631 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800632 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
633 EnumSet.of(OFType.FLOW_MOD),
634 OFMESSAGE_DAMPER_TIMEOUT);
635 // TODO: An ugly hack!
636 String conf = "/tmp/cassandra.titan";
637 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800638 }
639
640 @Override
641 public void startUp(FloodlightModuleContext context) {
642 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700643
644 //
645 // Extract all flow entries and assign the next Flow Entry ID
646 // to be larger than the largest Flow Entry ID
647 //
648 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
649 for (IFlowEntry flowEntryObj : allFlowEntries) {
650 FlowEntryId flowEntryId =
651 new FlowEntryId(flowEntryObj.getFlowEntryId());
652 if (flowEntryId.value() >= nextFlowEntryId)
653 nextFlowEntryId = flowEntryId.value() + 1;
654 }
655 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800656 }
657
658 /**
659 * Add a flow.
660 *
661 * Internally, ONOS will automatically register the installer for
662 * receiving Flow Path Notifications for that path.
663 *
664 * @param flowPath the Flow Path to install.
665 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700666 * @param dataPathSummaryStr the data path summary string if the added
667 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800668 * @return true on success, otherwise false.
669 */
670 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700671 public boolean addFlow(FlowPath flowPath, FlowId flowId,
672 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700673 if (flowPath.flowId().value() == measurementFlowId) {
674 modifiedMeasurementFlowTime = System.nanoTime();
675 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800676
677 //
678 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700679 // Right now every new flow entry gets a new flow entry ID
680 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800681 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800682 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700683 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800684 flowEntry.setFlowEntryId(new FlowEntryId(id));
685 }
686
687 IFlowPath flowObj = null;
688 try {
689 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
690 != null) {
691 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
692 flowPath.flowId().toString());
693 } else {
694 flowObj = conn.utils().newFlowPath(conn);
695 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
696 flowPath.flowId().toString());
697 }
698 } catch (Exception e) {
699 // TODO: handle exceptions
700 conn.endTx(Transaction.ROLLBACK);
701 log.error(":addFlow FlowId:{} failed",
702 flowPath.flowId().toString());
703 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700704 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000705 log.error(":addFlow FlowId:{} failed: Flow object not created",
706 flowPath.flowId().toString());
707 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800708 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700709 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800710
711 //
712 // Set the Flow key:
713 // - flowId
714 //
715 flowObj.setFlowId(flowPath.flowId().toString());
716 flowObj.setType("flow");
717
718 //
719 // Set the Flow attributes:
720 // - flowPath.installerId()
721 // - flowPath.dataPath().srcPort()
722 // - flowPath.dataPath().dstPort()
723 //
724 flowObj.setInstallerId(flowPath.installerId().toString());
725 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
726 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
727 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
728 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
729
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700730 if (dataPathSummaryStr != null) {
731 flowObj.setDataPathSummary(dataPathSummaryStr);
732 } else {
733 flowObj.setDataPathSummary("");
734 }
735
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800736 // Flow edges:
737 // HeadFE
738
739
740 //
741 // Flow Entries:
742 // flowPath.dataPath().flowEntries()
743 //
744 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
745 IFlowEntry flowEntryObj = null;
746 boolean found = false;
747 try {
748 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
749 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
750 flowEntry.flowEntryId().toString());
751 found = true;
752 } else {
753 flowEntryObj = conn.utils().newFlowEntry(conn);
754 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
755 flowEntry.flowEntryId().toString());
756 }
757 } catch (Exception e) {
758 // TODO: handle exceptions
759 conn.endTx(Transaction.ROLLBACK);
760 log.error(":addFlow FlowEntryId:{} failed",
761 flowEntry.flowEntryId().toString());
762 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700763 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000764 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
765 flowEntry.flowEntryId().toString());
766 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800767 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700768 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800769
770 //
771 // Set the Flow Entry key:
772 // - flowEntry.flowEntryId()
773 //
774 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
775 flowEntryObj.setType("flow_entry");
776
777 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700778 // Set the Flow Entry Edges and attributes:
779 // - Switch edge
780 // - InPort edge
781 // - OutPort edge
782 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800783 // - flowEntry.flowEntryMatch()
784 // - flowEntry.flowEntryActions()
785 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800786 // - flowEntry.flowEntryUserState()
787 // - flowEntry.flowEntrySwitchState()
788 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700789 // - flowEntry.matchInPort()
790 // - flowEntry.matchEthernetFrameType()
791 // - flowEntry.matchSrcIPv4Net()
792 // - flowEntry.matchDstIPv4Net()
793 // - flowEntry.matchSrcMac()
794 // - flowEntry.matchDstMac()
795 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800796 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700797 ISwitchObject sw =
798 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800799 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700800 flowEntryObj.setSwitch(sw);
801 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700802 IPortObject inport =
803 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
804 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700805 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
806 flowEntryObj.setInPort(inport);
807 }
808 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
809 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
810 }
811 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
812 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
813 }
814 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
815 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
816 }
817 if (flowEntry.flowEntryMatch().matchSrcMac()) {
818 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
819 }
820 if (flowEntry.flowEntryMatch().matchDstMac()) {
821 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
822 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700823
824 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700825 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700826 IPortObject outport =
827 conn.utils().searchPort(conn,
828 flowEntry.dpid().toString(),
829 fa.actionOutput().port().value());
830 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
831 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700832 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700833 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800834 // TODO: Hacks with hard-coded state names!
835 if (found)
836 flowEntryObj.setUserState("FE_USER_MODIFY");
837 else
838 flowEntryObj.setUserState("FE_USER_ADD");
839 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
840 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700841 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800842 //
843
844 // Flow Entries edges:
845 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700846 // NextFE (TODO)
847 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800848 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700849 flowEntryObj.setFlow(flowObj);
850 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800851 }
852 conn.endTx(Transaction.COMMIT);
853
854 //
855 // TODO: We need a proper Flow ID allocation mechanism.
856 //
857 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700858
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800859 return true;
860 }
861
862 /**
863 * Delete a previously added flow.
864 *
865 * @param flowId the Flow ID of the flow to delete.
866 * @return true on success, otherwise false.
867 */
868 @Override
869 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700870 if (flowId.value() == measurementFlowId) {
871 modifiedMeasurementFlowTime = System.nanoTime();
872 }
873
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800874 IFlowPath flowObj = null;
875 //
876 // We just mark the entries for deletion,
877 // and let the switches remove each individual entry after
878 // it has been removed from the switches.
879 //
880 try {
881 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
882 != null) {
883 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
884 flowId.toString());
885 } else {
886 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
887 flowId.toString());
888 }
889 } catch (Exception e) {
890 // TODO: handle exceptions
891 conn.endTx(Transaction.ROLLBACK);
892 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
893 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700894 if (flowObj == null) {
895 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800896 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700897 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800898
899 //
900 // Find and mark for deletion all Flow Entries
901 //
902 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
903 boolean empty = true; // TODO: an ugly hack
904 for (IFlowEntry flowEntryObj : flowEntries) {
905 empty = false;
906 // flowObj.removeFlowEntry(flowEntryObj);
907 // conn.utils().removeFlowEntry(conn, flowEntryObj);
908 flowEntryObj.setUserState("FE_USER_DELETE");
909 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
910 }
911 // Remove from the database empty flows
912 if (empty)
913 conn.utils().removeFlowPath(conn, flowObj);
914 conn.endTx(Transaction.COMMIT);
915
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800916 return true;
917 }
918
919 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700920 * Clear the state for a previously added flow.
921 *
922 * @param flowId the Flow ID of the flow to clear.
923 * @return true on success, otherwise false.
924 */
925 @Override
926 public boolean clearFlow(FlowId flowId) {
927 IFlowPath flowObj = null;
928 try {
929 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
930 != null) {
931 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
932 flowId.toString());
933 } else {
934 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
935 flowId.toString());
936 }
937 } catch (Exception e) {
938 // TODO: handle exceptions
939 conn.endTx(Transaction.ROLLBACK);
940 log.error(":clearFlow FlowId:{} failed", flowId.toString());
941 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700942 if (flowObj == null) {
943 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700944 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700945 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700946
947 //
948 // Remove all Flow Entries
949 //
950 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
951 for (IFlowEntry flowEntryObj : flowEntries) {
952 flowObj.removeFlowEntry(flowEntryObj);
953 conn.utils().removeFlowEntry(conn, flowEntryObj);
954 }
955 // Remove the Flow itself
956 conn.utils().removeFlowPath(conn, flowObj);
957 conn.endTx(Transaction.COMMIT);
958
959 return true;
960 }
961
962 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800963 * Get a previously added flow.
964 *
965 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800966 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800967 */
968 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800969 public FlowPath getFlow(FlowId flowId) {
970 IFlowPath flowObj = null;
971 try {
972 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
973 != null) {
974 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
975 flowId.toString());
976 } else {
977 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
978 flowId.toString());
979 }
980 } catch (Exception e) {
981 // TODO: handle exceptions
982 conn.endTx(Transaction.ROLLBACK);
983 log.error(":getFlow FlowId:{} failed", flowId.toString());
984 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700985 if (flowObj == null) {
986 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800987 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700988 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800989
990 //
991 // Extract the Flow state
992 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800993 FlowPath flowPath = extractFlowPath(flowObj);
994 conn.endTx(Transaction.COMMIT);
995
996 return flowPath;
997 }
998
999 /**
1000 * Get all previously added flows by a specific installer for a given
1001 * data path endpoints.
1002 *
1003 * @param installerId the Caller ID of the installer of the flow to get.
1004 * @param dataPathEndpoints the data path endpoints of the flow to get.
1005 * @return the Flow Paths if found, otherwise null.
1006 */
1007 @Override
1008 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1009 DataPathEndpoints dataPathEndpoints) {
1010 //
1011 // TODO: The implementation below is not optimal:
1012 // We fetch all flows, and then return only the subset that match
1013 // the query conditions.
1014 // We should use the appropriate Titan/Gremlin query to filter-out
1015 // the flows as appropriate.
1016 //
1017 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001018 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001019
1020 if (allFlows == null) {
1021 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001022 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001023 }
1024
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001025 for (FlowPath flow : allFlows) {
1026 //
1027 // TODO: String-based comparison is sub-optimal.
1028 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001029 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001030 //
1031 if (! flow.installerId().toString().equals(installerId.toString()))
1032 continue;
1033 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1034 continue;
1035 }
1036 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1037 continue;
1038 }
1039 flowPaths.add(flow);
1040 }
1041
1042 if (flowPaths.isEmpty()) {
1043 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001044 } else {
1045 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1046 }
1047
1048 return flowPaths;
1049 }
1050
1051 /**
1052 * Get all installed flows by all installers for given data path endpoints.
1053 *
1054 * @param dataPathEndpoints the data path endpoints of the flows to get.
1055 * @return the Flow Paths if found, otherwise null.
1056 */
1057 @Override
1058 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1059 //
1060 // TODO: The implementation below is not optimal:
1061 // We fetch all flows, and then return only the subset that match
1062 // the query conditions.
1063 // We should use the appropriate Titan/Gremlin query to filter-out
1064 // the flows as appropriate.
1065 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001066 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1067 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001068
1069 if (allFlows == null) {
1070 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001071 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001072 }
1073
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001074 for (FlowPath flow : allFlows) {
1075 //
1076 // TODO: String-based comparison is sub-optimal.
1077 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001078 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001079 //
1080 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1081 continue;
1082 }
1083 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1084 continue;
1085 }
1086 flowPaths.add(flow);
1087 }
1088
1089 if (flowPaths.isEmpty()) {
1090 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001091 } else {
1092 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1093 }
1094
1095 return flowPaths;
1096 }
1097
1098 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001099 * Get summary of all installed flows by all installers in a given range
1100 *
1101 * @param flowId the data path endpoints of the flows to get.
1102 * @param maxFlows: the maximum number of flows to be returned
1103 * @return the Flow Paths if found, otherwise null.
1104 */
1105 @Override
1106 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1107 //
1108 // TODO: The implementation below is not optimal:
1109 // We fetch all flows, and then return only the subset that match
1110 // the query conditions.
1111 // We should use the appropriate Titan/Gremlin query to filter-out
1112 // the flows as appropriate.
1113 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001114 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1115
1116 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001117
1118 if (allFlows == null) {
1119 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001120 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001121 }
1122
1123 Collections.sort(allFlows);
1124
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001125 for (FlowPath flow : allFlows) {
1126
1127 // start from desired flowId
1128 if (flow.flowId().value() < flowId.value()) {
1129 continue;
1130 }
1131
1132 // Summarize by making null flow entry fields that are not relevant to report
1133 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1134 flowEntry.setFlowEntryActions(null);
1135 flowEntry.setFlowEntryMatch(null);
1136 }
1137
1138 flowPaths.add(flow);
1139 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1140 break;
1141 }
1142 }
1143
1144 if (flowPaths.isEmpty()) {
1145 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001146 } else {
1147 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1148 }
1149
1150 return flowPaths;
1151 }
1152
1153 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001154 * Get all installed flows by all installers.
1155 *
1156 * @return the Flow Paths if found, otherwise null.
1157 */
1158 @Override
1159 public ArrayList<FlowPath> getAllFlows() {
1160 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001161 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001162
1163 try {
1164 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1165 log.debug("Get all FlowPaths: found FlowPaths");
1166 } else {
1167 log.debug("Get all FlowPaths: no FlowPaths found");
1168 }
1169 } catch (Exception e) {
1170 // TODO: handle exceptions
1171 conn.endTx(Transaction.ROLLBACK);
1172 log.error(":getAllFlowPaths failed");
1173 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001174 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1175 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001176 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001177 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001178
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001179 for (IFlowPath flowObj : flowPathsObj) {
1180 //
1181 // Extract the Flow state
1182 //
1183 FlowPath flowPath = extractFlowPath(flowObj);
1184 flowPaths.add(flowPath);
1185 }
1186
1187 conn.endTx(Transaction.COMMIT);
1188
1189 return flowPaths;
1190 }
1191
1192 /**
1193 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1194 *
1195 * @param flowObj the object to extract the Flow Path State from.
1196 * @return the extracted Flow Path State.
1197 */
1198 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001199 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001200
1201 //
1202 // Extract the Flow state
1203 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001204 String flowIdStr = flowObj.getFlowId();
1205 String installerIdStr = flowObj.getInstallerId();
1206 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001207 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001208 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001209 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001210
1211 if ((flowIdStr == null) ||
1212 (installerIdStr == null) ||
1213 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001214 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001215 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001216 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001217 // TODO: A work-around, becauuse of some bogus database objects
1218 return null;
1219 }
1220
1221 flowPath.setFlowId(new FlowId(flowIdStr));
1222 flowPath.setInstallerId(new CallerId(installerIdStr));
1223 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001224 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001225 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001226 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001227
1228 //
1229 // Extract all Flow Entries
1230 //
1231 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1232 for (IFlowEntry flowEntryObj : flowEntries) {
1233 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001234 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1235 String switchDpidStr = flowEntryObj.getSwitchDpid();
1236 String userState = flowEntryObj.getUserState();
1237 String switchState = flowEntryObj.getSwitchState();
1238
1239 if ((flowEntryIdStr == null) ||
1240 (switchDpidStr == null) ||
1241 (userState == null) ||
1242 (switchState == null)) {
1243 // TODO: A work-around, becauuse of some bogus database objects
1244 continue;
1245 }
1246 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1247 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001248
1249 //
1250 // Extract the match conditions
1251 //
1252 FlowEntryMatch match = new FlowEntryMatch();
1253 Short matchInPort = flowEntryObj.getMatchInPort();
1254 if (matchInPort != null)
1255 match.enableInPort(new Port(matchInPort));
1256 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1257 if (matchEthernetFrameType != null)
1258 match.enableEthernetFrameType(matchEthernetFrameType);
1259 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1260 if (matchSrcIPv4Net != null)
1261 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1262 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1263 if (matchDstIPv4Net != null)
1264 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1265 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1266 if (matchSrcMac != null)
1267 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1268 String matchDstMac = flowEntryObj.getMatchDstMac();
1269 if (matchDstMac != null)
1270 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1271 flowEntry.setFlowEntryMatch(match);
1272
1273 //
1274 // Extract the actions
1275 //
1276 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1277 Short actionOutputPort = flowEntryObj.getActionOutput();
1278 if (actionOutputPort != null) {
1279 FlowEntryAction action = new FlowEntryAction();
1280 action.setActionOutput(new Port(actionOutputPort));
1281 actions.add(action);
1282 }
1283 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001284 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001285 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1286 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001287 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001288 // and FlowEntryErrorState.
1289 //
1290 flowPath.dataPath().flowEntries().add(flowEntry);
1291 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001292
1293 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001294 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001295
1296 /**
1297 * Add and maintain a shortest-path flow.
1298 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001299 * NOTE: The Flow Path argument does NOT contain all flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001300 * Instead, it contains a single dummy flow entry that is used to
1301 * store the matching condition(s).
1302 * That entry is replaced by the appropriate entries from the
1303 * internally performed shortest-path computation.
1304 *
1305 * @param flowPath the Flow Path with the endpoints and the match
1306 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001307 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001308 */
1309 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001310 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001311 String dataPathSummaryStr = null;
1312
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001313 //
1314 // Do the shortest path computation
1315 //
1316 DataPath dataPath =
1317 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1318 flowPath.dataPath().dstPort());
1319 if (dataPath == null)
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001320 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001321
1322 FlowEntryMatch userFlowEntryMatch = null;
1323 if (! flowPath.dataPath().flowEntries().isEmpty()) {
1324 userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
1325 }
1326
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001327 // Compute the Data Path summary
1328 dataPathSummaryStr = dataPath.dataPathSummary();
1329
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001330 //
1331 // Set the incoming port matching and the outgoing port output
1332 // actions for each flow entry.
1333 //
1334 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1335 // Set the incoming port matching
1336 FlowEntryMatch flowEntryMatch = null;
1337 if (userFlowEntryMatch != null)
1338 flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
1339 else
1340 flowEntryMatch = new FlowEntryMatch();
1341 flowEntry.setFlowEntryMatch(flowEntryMatch);
1342 flowEntryMatch.enableInPort(flowEntry.inPort());
1343
1344 // Set the outgoing port output action
1345 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1346 if (flowEntryActions == null) {
1347 flowEntryActions = new ArrayList<FlowEntryAction>();
1348 flowEntry.setFlowEntryActions(flowEntryActions);
1349 }
1350 FlowEntryAction flowEntryAction = new FlowEntryAction();
1351 flowEntryAction.setActionOutput(flowEntry.outPort());
1352 flowEntryActions.add(flowEntryAction);
1353 }
1354
1355 //
1356 // Prepare the computed Flow Path
1357 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001358 FlowPath computedFlowPath = new FlowPath();
1359 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1360 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1361 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001362
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001363 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001364 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001365 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001366
1367 // TODO: Mark the flow for maintenance purpose
1368
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001369 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001370 }
1371
1372 /**
1373 * Create a Flow from port to port.
1374 *
1375 * TODO: We don't need it for now.
1376 *
1377 * @param src_port the source port.
1378 * @param dest_port the destination port.
1379 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001380 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001381 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1382 // TODO: We don't need it for now.
1383 }
1384
1385 /**
1386 * Get all Flows matching a source and a destination port.
1387 *
1388 * TODO: Pankaj might be implementing it later.
1389 *
1390 * @param src_port the source port to match.
1391 * @param dest_port the destination port to match.
1392 * @return all flows matching the source and the destination port.
1393 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001394 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001395 public Iterable<FlowPath> getFlows(IPortObject src_port,
1396 IPortObject dest_port) {
1397 // TODO: Pankaj might be implementing it later.
1398 return null;
1399 }
1400
1401 /**
1402 * Get all Flows going out from a port.
1403 *
1404 * TODO: We need it now: Pankaj
1405 *
1406 * @param port the port to match.
1407 * @return the list of flows that are going out from the port.
1408 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001409 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001410 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001411 // TODO: We need it now: Pankaj
1412 return null;
1413 }
1414
1415 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001416 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001417 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001418 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001419 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001420 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001421 public void reconcileFlows(IPortObject portObject) {
1422 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1423 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001424
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001425 //
1426 // Collect all affected Flow IDs from the affected flow entries
1427 //
1428 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1429 for (IFlowEntry flowEntryObj: inFlowEntries) {
1430 IFlowPath flowObj = flowEntryObj.getFlow();
1431 if (flowObj != null)
1432 flowObjSet.add(flowObj);
1433 }
1434 for (IFlowEntry flowEntryObj: outFlowEntries) {
1435 IFlowPath flowObj = flowEntryObj.getFlow();
1436 if (flowObj != null)
1437 flowObjSet.add(flowObj);
1438 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001439
1440 // Reconcile the affected flows
1441 reconcileFlows(flowObjSet);
1442 }
1443
1444 /**
1445 * Reconcile all flows in a set.
1446 *
1447 * @param flowObjSet the set of flows that need to be reconciliated.
1448 */
1449 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1450 if (! flowObjSet.iterator().hasNext())
1451 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001452
1453 //
1454 // Remove the old Flow Entries, and add the new Flow Entries
1455 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001456
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001457 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001458 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001459 for (IFlowPath flowObj : flowObjSet) {
1460 FlowPath flowPath = extractFlowPath(flowObj);
1461 if (flowPath == null)
1462 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001463 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001464
1465 //
1466 // Remove my Flow Entries from the Network MAP
1467 //
1468 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001469 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001470 for (IFlowEntry flowEntryObj : flowEntries) {
1471 String dpidStr = flowEntryObj.getSwitchDpid();
1472 if (dpidStr == null)
1473 continue;
1474 Dpid dpid = new Dpid(dpidStr);
1475 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1476 if (mySwitch == null)
1477 continue; // Ignore the entry: not my switch
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001478 deleteFlowEntries.add(flowEntryObj);
1479 }
1480 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001481 flowObj.removeFlowEntry(flowEntryObj);
1482 conn.utils().removeFlowEntry(conn, flowEntryObj);
1483 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001484 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001485
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001486 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001487 //
1488 // Delete the flow entries from the switches
1489 //
1490 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1491 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001492 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1493 if (mySwitch == null) {
1494 // Not my switch
1495 installRemoteFlowEntry(flowEntry);
1496 } else {
1497 installFlowEntry(mySwitch, flowEntry);
1498 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001499 }
1500
1501 //
1502 // Calculate the new shortest path and install it in the
1503 // Network MAP.
1504 //
1505 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1506 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001507 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001508 flowPath.dataPath().srcPort().toString(),
1509 flowPath.dataPath().dstPort().toString());
1510 continue;
1511 }
1512
1513 //
1514 // Add the flow entries to the switches
1515 //
1516 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1517 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001518 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1519 if (mySwitch == null) {
1520 // Not my switch
1521 installRemoteFlowEntry(flowEntry);
1522 continue;
1523 }
1524
1525 IFlowEntry flowEntryObj =
1526 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1527 if (flowEntryObj == null) {
1528 //
1529 // TODO: Remove the "new Object[] wrapper in the statement
1530 // below after the SLF4J logger is upgraded to
1531 // Version 1.7.5
1532 //
1533 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1534 new Object[] {
1535 flowEntry.dpid(),
1536 flowPath.dataPath().srcPort(),
1537 flowPath.dataPath().dstPort()
1538 });
1539 continue;
1540 }
1541 // Update the Flow Entry Switch State in the Network MAP
1542 if (installFlowEntry(mySwitch, flowEntry)) {
1543 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1544 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001545 }
1546 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001547 }
1548
1549 /**
1550 * Reconcile all flows between a source and a destination port.
1551 *
1552 * TODO: We don't need it for now.
1553 *
1554 * @param src_port the source port.
1555 * @param dest_port the destination port.
1556 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001557 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001558 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1559 // TODO: We don't need it for now.
1560 }
1561
1562 /**
1563 * Compute the shortest path between a source and a destination ports.
1564 *
1565 * @param src_port the source port.
1566 * @param dest_port the destination port.
1567 * @return the computed shortest path between the source and the
1568 * destination ports. The flow entries in the path itself would
1569 * contain the incoming port matching and the outgoing port output
1570 * actions set. However, the path itself will NOT have the Flow ID,
1571 * Installer ID, and any additional matching conditions for the
1572 * flow entries (e.g., source or destination MAC address, etc).
1573 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001574 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001575 public FlowPath computeFlowPath(IPortObject src_port,
1576 IPortObject dest_port) {
1577 //
1578 // Prepare the arguments
1579 //
1580 String dpidStr = src_port.getSwitch().getDPID();
1581 Dpid srcDpid = new Dpid(dpidStr);
1582 Port srcPort = new Port(src_port.getNumber());
1583
1584 dpidStr = dest_port.getSwitch().getDPID();
1585 Dpid dstDpid = new Dpid(dpidStr);
1586 Port dstPort = new Port(dest_port.getNumber());
1587
1588 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1589 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1590
1591 //
1592 // Do the shortest path computation
1593 //
1594 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1595 if (dataPath == null)
1596 return null;
1597
1598 //
1599 // Set the incoming port matching and the outgoing port output
1600 // actions for each flow entry.
1601 //
1602 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1603 // Set the incoming port matching
1604 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1605 if (flowEntryMatch == null) {
1606 flowEntryMatch = new FlowEntryMatch();
1607 flowEntry.setFlowEntryMatch(flowEntryMatch);
1608 }
1609 flowEntryMatch.enableInPort(flowEntry.inPort());
1610
1611 // Set the outgoing port output action
1612 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1613 if (flowEntryActions == null) {
1614 flowEntryActions = new ArrayList<FlowEntryAction>();
1615 flowEntry.setFlowEntryActions(flowEntryActions);
1616 }
1617 FlowEntryAction flowEntryAction = new FlowEntryAction();
1618 flowEntryAction.setActionOutput(flowEntry.outPort());
1619 flowEntryActions.add(flowEntryAction);
1620 }
1621
1622 //
1623 // Prepare the return result
1624 //
1625 FlowPath flowPath = new FlowPath();
1626 flowPath.setDataPath(dataPath);
1627
1628 return flowPath;
1629 }
1630
1631 /**
1632 * Get all Flow Entries of a Flow.
1633 *
1634 * @param flow the flow whose flow entries should be returned.
1635 * @return the flow entries of the flow.
1636 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001637 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001638 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1639 return flow.dataPath().flowEntries();
1640 }
1641
1642 /**
1643 * Install a Flow Entry on a switch.
1644 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001645 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001646 * @param flowEntry the flow entry to install.
1647 * @return true on success, otherwise false.
1648 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001649 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001650 public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001651 //
1652 // Create the OpenFlow Flow Modification Entry to push
1653 //
1654 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1655 .getMessage(OFType.FLOW_MOD);
1656 long cookie = flowEntry.flowEntryId().value();
1657
1658 short flowModCommand = OFFlowMod.OFPFC_ADD;
1659 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1660 flowModCommand = OFFlowMod.OFPFC_ADD;
1661 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1662 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1663 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1664 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1665 } else {
1666 // Unknown user state. Ignore the entry
1667 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1668 flowEntry.flowEntryId().toString(),
1669 flowEntry.flowEntryUserState());
1670 return false;
1671 }
1672
1673 //
1674 // Fetch the match conditions
1675 //
1676 OFMatch match = new OFMatch();
1677 match.setWildcards(OFMatch.OFPFW_ALL);
1678 Port matchInPort = flowEntry.flowEntryMatch().inPort();
1679 if (matchInPort != null) {
1680 match.setInputPort(matchInPort.value());
1681 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1682 }
1683 Short matchEthernetFrameType =
1684 flowEntry.flowEntryMatch().ethernetFrameType();
1685 if (matchEthernetFrameType != null) {
1686 match.setDataLayerType(matchEthernetFrameType);
1687 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1688 }
1689 IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
1690 if (matchSrcIPv4Net != null) {
1691 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1692 }
1693 IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
1694 if (matchDstIPv4Net != null) {
1695 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1696 }
1697 MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
1698 if (matchSrcMac != null) {
1699 match.setDataLayerSource(matchSrcMac.toString());
1700 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1701 }
1702 MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
1703 if (matchDstMac != null) {
1704 match.setDataLayerDestination(matchDstMac.toString());
1705 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1706 }
1707
1708 //
1709 // Fetch the actions
1710 //
1711 // TODO: For now we support only the "OUTPUT" actions.
1712 //
1713 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1714 List<OFAction> actions = new ArrayList<OFAction>();
1715 ArrayList<FlowEntryAction> flowEntryActions =
1716 flowEntry.flowEntryActions();
1717 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1718 FlowEntryAction.ActionOutput actionOutput =
1719 flowEntryAction.actionOutput();
1720 if (actionOutput != null) {
1721 short actionOutputPort = actionOutput.port().value();
1722 OFActionOutput action = new OFActionOutput();
1723 // XXX: The max length is hard-coded for now
1724 action.setMaxLength((short)0xffff);
1725 action.setPort(actionOutputPort);
1726 actions.add(action);
1727 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1728 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1729 fm.setOutPort(actionOutputPort);
1730 }
1731 }
1732 }
1733
1734 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1735 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1736 .setPriority(PRIORITY_DEFAULT)
1737 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1738 .setCookie(cookie)
1739 .setCommand(flowModCommand)
1740 .setMatch(match)
1741 .setActions(actions)
1742 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1743
1744 //
1745 // TODO: Set the following flag
1746 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1747 // See method ForwardingBase::pushRoute()
1748 //
1749
1750 //
1751 // Write the message to the switch
1752 //
1753 try {
1754 messageDamper.write(mySwitch, fm, null);
1755 mySwitch.flush();
1756 } catch (IOException e) {
1757 log.error("Failure writing flow mod from network map", e);
1758 return false;
1759 }
1760 return true;
1761 }
1762
1763 /**
1764 * Remove a Flow Entry from a switch.
1765 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001766 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001767 * @param flowEntry the flow entry to remove.
1768 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001769 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001770 @Override
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001771 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001772 //
1773 // The installFlowEntry() method implements both installation
1774 // and removal of flow entries.
1775 //
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001776 return (installFlowEntry(mySwitch, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001777 }
1778
1779 /**
1780 * Install a Flow Entry on a remote controller.
1781 *
1782 * TODO: We need it now: Jono
1783 * - For now it will make a REST call to the remote controller.
1784 * - Internally, it needs to know the name of the remote controller.
1785 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001786 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001787 * @return true on success, otherwise false.
1788 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001789 @Override
1790 public boolean installRemoteFlowEntry(FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001791 // TODO: We need it now: Jono
1792 // - For now it will make a REST call to the remote controller.
1793 // - Internally, it needs to know the name of the remote controller.
1794 return true;
1795 }
1796
1797 /**
1798 * Remove a flow entry on a remote controller.
1799 *
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001800 * @param flowEntry the flow entry to remove.
1801 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001802 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001803 @Override
1804 public boolean removeRemoteFlowEntry(FlowEntry flowEntry) {
1805 //
1806 // The installRemoteFlowEntry() method implements both installation
1807 // and removal of flow entries.
1808 //
1809 return (installRemoteFlowEntry(flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001810 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001811}