blob: 51e0509a5ccb859728e9d71ae5edf94b9f76e818 [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 Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070010import java.util.TreeMap;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070011import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070013import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.ScheduledExecutorService;
15import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070016import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import 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 Radoslavov571cff92013-03-20 02:01:32 -070023import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080024import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080025import net.floodlightcontroller.core.module.FloodlightModuleContext;
26import net.floodlightcontroller.core.module.FloodlightModuleException;
27import net.floodlightcontroller.core.module.IFloodlightModule;
28import net.floodlightcontroller.core.module.IFloodlightService;
29import net.floodlightcontroller.flowcache.IFlowService;
30import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
31import net.floodlightcontroller.restserver.IRestApiService;
32import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033import net.floodlightcontroller.util.DataPath;
34import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080035import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070037import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080038import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070039import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080040import net.floodlightcontroller.util.FlowEntrySwitchState;
41import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080042import net.floodlightcontroller.util.FlowId;
43import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070044import net.floodlightcontroller.util.IPv4Net;
45import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.OFMessageDamper;
47import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070048import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.onrc.onos.util.GraphDBConnection;
50import net.onrc.onos.util.GraphDBConnection.Transaction;
51
52import org.openflow.protocol.OFFlowMod;
53import org.openflow.protocol.OFMatch;
54import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070055import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import org.openflow.protocol.OFType;
57import org.openflow.protocol.action.OFAction;
58import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080059
60import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080063public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
64
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 Radoslavov571cff92013-03-20 02:01:32 -070069 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 protected OFMessageDamper messageDamper;
72
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070073 //
74 // TODO: Values copied from elsewhere (class LearningSwitch).
75 // The local copy should go away!
76 //
77 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
78 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
79 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
80 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
81 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080082
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070083 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070084 private static long measurementFlowId = 100000;
85 private static String measurementFlowIdStr = "0x186a0"; // 100000
86 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070087
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080088 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080089 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
90
91 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070092 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080093 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070094 private final ScheduledExecutorService measureMapReaderScheduler =
95 Executors.newScheduledThreadPool(1);
96 private final ScheduledExecutorService mapReaderScheduler =
97 Executors.newScheduledThreadPool(1);
98
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070099 private BlockingQueue<Runnable> shortestPathQueue = new LinkedBlockingQueue<Runnable>();
100 private ThreadPoolExecutor shortestPathExecutor =
101 new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, shortestPathQueue);
102
103 class ShortestPathTask implements Runnable {
104 private int hint;
105 private ITopoRouteService topoRouteService;
106 private ArrayList<DataPath> dpList;
107
108 public ShortestPathTask(int hint,
109 ITopoRouteService topoRouteService,
110 ArrayList<DataPath> dpList) {
111 this.hint = hint;
112 this.topoRouteService = topoRouteService;
113 this.dpList = dpList;
114 }
115
116 @Override
117 public void run() {
118 String logMsg = "MEASUREMENT: Running Thread hint " + this.hint;
119 log.debug(logMsg);
120 long startTime = System.nanoTime();
121 for (DataPath dp : this.dpList) {
122 topoRouteService.getShortestPath(dp.srcPort(), dp.dstPort());
123 }
124 long estimatedTime = System.nanoTime() - startTime;
125 double rate = (estimatedTime > 0)? ((double)dpList.size() * 1000000000) / estimatedTime: 0.0;
126 logMsg = "MEASUREMENT: Computed Thread hint " + hint + ": " + dpList.size() + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
127 log.debug(logMsg);
128 }
129 }
130
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700131 final Runnable measureShortestPath = new Runnable() {
132 public void run() {
133 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
134 if (floodlightProvider == null) {
135 log.debug("FloodlightProvider service not found!");
136 return;
137 }
138
139 ITopoRouteService topoRouteService =
140 context.getServiceImpl(ITopoRouteService.class);
141 if (topoRouteService == null) {
142 log.debug("Topology Route Service not found");
143 return;
144 }
145
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700146 int leftoverQueueSize = shortestPathExecutor.getQueue().size();
147 if (leftoverQueueSize > 0) {
148 String logMsg = "MEASUREMENT: Leftover Shortest Path Queue Size: " + leftoverQueueSize;
149 log.debug(logMsg);
150 return;
151 }
152 log.debug("MEASUREMENT: Beginning Shortest Path Computation");
153
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700154 //
155 // Recompute the Shortest Paths for all Flows
156 //
157 int counter = 0;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700158 int hint = 0;
159 ArrayList<DataPath> dpList = new ArrayList<DataPath>();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700160 long startTime = System.nanoTime();
161 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
162 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700163 FlowId flowId = new FlowId(flowPathObj.getFlowId());
164
165 // log.debug("Found Path {}", flowId.toString());
166 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
167 Port srcPort = new Port(flowPathObj.getSrcPort());
168 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
169 Port dstPort = new Port(flowPathObj.getDstPort());
170 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
171 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700172 DataPath dp = new DataPath();
173 dp.setSrcPort(srcSwitchPort);
174 dp.setDstPort(dstSwitchPort);
175 dpList.add(dp);
176 if ((dpList.size() % 10) == 0) {
177 shortestPathExecutor.execute(
178 new ShortestPathTask(hint, topoRouteService,
179 dpList));
180 dpList = new ArrayList<DataPath>();
181 hint++;
182 }
183 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700184 DataPath dataPath =
185 topoRouteService.getShortestPath(srcSwitchPort,
186 dstSwitchPort);
Pavlin Radoslavov4da61282013-03-20 20:31:36 -0700187 */
188
189 /*
190 shortestPathExecutor.execute(
191 new ShortestPathTask(topoRouteService,
192 srcSwitchPort,
193 dstSwitchPort));
194 */
195 counter++;
196 }
197 if (dpList.size() > 0) {
198 shortestPathExecutor.execute(
199 new ShortestPathTask(hint, topoRouteService,
200 dpList));
201 }
202
203 // Wait for all tasks to finish
204 try {
205 while (shortestPathExecutor.getQueue().size() > 0) {
206 Thread.sleep(100);
207 }
208 } catch (InterruptedException ex) {
209 log.debug("MEASUREMENT: Shortest Path Computation interrupted");
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700210 }
211 conn.endTx(Transaction.COMMIT);
212
213 long estimatedTime = System.nanoTime() - startTime;
214 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
215 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
216 log.debug(logMsg);
217 }
218 };
219
220 final Runnable measureMapReader = new Runnable() {
221 public void run() {
222 if (floodlightProvider == null) {
223 log.debug("FloodlightProvider service not found!");
224 return;
225 }
226
227 //
228 // Fetch all Flow Entries
229 //
230 int counter = 0;
231 long startTime = System.nanoTime();
232 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
233 for (IFlowEntry flowEntryObj : allFlowEntries) {
234 counter++;
235 FlowEntryId flowEntryId =
236 new FlowEntryId(flowEntryObj.getFlowEntryId());
237 String userState = flowEntryObj.getUserState();
238 String switchState = flowEntryObj.getSwitchState();
239 }
240 conn.endTx(Transaction.COMMIT);
241
242 long estimatedTime = System.nanoTime() - startTime;
243 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
244 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
245 log.debug(logMsg);
246 }
247 };
248
249 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800250 public void run() {
251 // log.debug("Reading Flow Entries from the Network Map...");
252 if (floodlightProvider == null) {
253 log.debug("FloodlightProvider service not found!");
254 return;
255 }
256
257 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
258
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700259 Map<Long, IFlowEntry> myFlowEntries = new TreeMap<Long, IFlowEntry>();
260
261 //
262 // Fetch all Flow Entries and select only my Flow Entries
263 //
264 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
265 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800266 FlowEntryId flowEntryId =
267 new FlowEntryId(flowEntryObj.getFlowEntryId());
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700268 String userState = flowEntryObj.getUserState();
269 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800270
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700271 log.debug("Found Flow Entry {}: {}",
272 flowEntryId.toString(),
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700273 "User State: " + userState +
274 " Switch State: " + switchState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800275
276 if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
277 // Ignore the entry: nothing to do
278 continue;
279 }
280
281 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
282 IOFSwitch mySwitch = mySwitches.get(dpid.value());
283 if (mySwitch == null) {
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700284 log.debug("Flow Entry ignored: not my switch (FlowEntryId = {} DPID = {})", flowEntryId.toString(), dpid.toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800285 continue;
286 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700287 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
288 }
289
290 //
291 // Process my Flow Entries
292 //
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700293 Boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700294 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
295 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700296 // Code for measurement purpose
297 {
298 IFlowPath flowObj =
299 conn.utils().getFlowPathByFlowEntry(conn,
300 flowEntryObj);
301 if ((flowObj != null) &&
302 flowObj.getFlowId().equals(measurementFlowIdStr)) {
303 processed_measurement_flow = true;
304 }
305 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700306
307 //
308 // TODO: Eliminate the re-fetching of flowEntryId,
309 // userState, switchState, and dpid from the flowEntryObj.
310 //
311 FlowEntryId flowEntryId =
312 new FlowEntryId(flowEntryObj.getFlowEntryId());
313 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
314 String userState = flowEntryObj.getUserState();
315 String switchState = flowEntryObj.getSwitchState();
316 IOFSwitch mySwitch = mySwitches.get(dpid.value());
317 if (mySwitch == null) {
318 log.debug("Flow Entry ignored: not my switch");
319 continue;
320 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800321
322 //
323 // Create the Open Flow Flow Modification Entry to push
324 //
325 OFFlowMod fm =
326 (OFFlowMod) floodlightProvider.getOFMessageFactory()
327 .getMessage(OFType.FLOW_MOD);
328 long cookie = flowEntryId.value();
329
330 short flowModCommand = OFFlowMod.OFPFC_ADD;
331 if (userState.equals("FE_USER_ADD")) {
332 flowModCommand = OFFlowMod.OFPFC_ADD;
333 } else if (userState.equals("FE_USER_MODIFY")) {
334 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
335 } else if (userState.equals("FE_USER_DELETE")) {
336 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
337 } else {
338 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700339 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
340 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800341 continue;
342 }
343
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700344 //
345 // Fetch the match conditions
346 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800347 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700348 match.setWildcards(OFMatch.OFPFW_ALL);
349 Short matchInPort = flowEntryObj.getMatchInPort();
350 if (matchInPort != null) {
351 match.setInputPort(matchInPort);
352 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
353 }
354 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
355 if (matchEthernetFrameType != null) {
356 match.setDataLayerType(matchEthernetFrameType);
357 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
358 }
359 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
360 if (matchSrcIPv4Net != null) {
361 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
362 }
363 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
364 if (matchDstIPv4Net != null) {
365 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
366 }
367 String matchSrcMac = flowEntryObj.getMatchSrcMac();
368 if (matchSrcMac != null) {
369 match.setDataLayerSource(matchSrcMac);
370 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
371 }
372 String matchDstMac = flowEntryObj.getMatchDstMac();
373 if (matchDstMac != null) {
374 match.setDataLayerDestination(matchDstMac);
375 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
376 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700377
378 //
379 // Fetch the actions
380 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800381 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700382 Short actionOutputPort = flowEntryObj.getActionOutput();
383 if (actionOutputPort != null) {
384 OFActionOutput action = new OFActionOutput();
385 // XXX: The max length is hard-coded for now
386 action.setMaxLength((short)0xffff);
387 action.setPort(actionOutputPort);
388 actions.add(action);
389 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800390
391 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
392 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700393 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800394 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
395 .setCookie(cookie)
396 .setCommand(flowModCommand)
397 .setMatch(match)
398 .setActions(actions)
399 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700400 fm.setOutPort(OFPort.OFPP_NONE.getValue());
401 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
402 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
403 if (actionOutputPort != null)
404 fm.setOutPort(actionOutputPort);
405 }
406
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800407 //
408 // TODO: Set the following flag
409 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
410 // See method ForwardingBase::pushRoute()
411 //
412 try {
413 messageDamper.write(mySwitch, fm, null);
414 mySwitch.flush();
415 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
416 if (userState.equals("FE_USER_DELETE")) {
417 // Delete the entry
418 IFlowPath flowObj = null;
419 flowObj = conn.utils().getFlowPathByFlowEntry(conn,
420 flowEntryObj);
421 if (flowObj != null)
422 log.debug("Found FlowPath to be deleted");
423 else
424 log.debug("Did not find FlowPath to be deleted");
425 flowObj.removeFlowEntry(flowEntryObj);
426 conn.utils().removeFlowEntry(conn, flowEntryObj);
427
428 // Test whether the last flow entry
429 Iterable<IFlowEntry> tmpflowEntries =
430 flowObj.getFlowEntries();
431 boolean found = false;
432 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
433 found = true;
434 break;
435 }
436 if (! found) {
437 // Remove the Flow Path as well
438 conn.utils().removeFlowPath(conn, flowObj);
439 }
440 }
441 } catch (IOException e) {
442 log.error("Failure writing flow mod from network map", e);
443 }
444 }
445 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700446
447 if (processed_measurement_flow) {
448 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
449 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
450 (double)estimatedTime / 1000000000 + " sec";
451 log.debug(logMsg);
452 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800453 }
454 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700455
456 /*
457 final ScheduledFuture<?> measureShortestPathHandle =
458 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
459 */
460
461 /*
462 final ScheduledFuture<?> measureMapReaderHandle =
463 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
464 */
465
466 final ScheduledFuture<?> mapReaderHandle =
467 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800468
469 @Override
470 public void init(String conf) {
471 conn = GraphDBConnection.getInstance(conf);
472 }
473
474 public void finalize() {
475 close();
476 }
477
478 @Override
479 public void close() {
480 conn.close();
481 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800482
483 @Override
484 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
485 Collection<Class<? extends IFloodlightService>> l =
486 new ArrayList<Class<? extends IFloodlightService>>();
487 l.add(IFlowService.class);
488 return l;
489 }
490
491 @Override
492 public Map<Class<? extends IFloodlightService>, IFloodlightService>
493 getServiceImpls() {
494 Map<Class<? extends IFloodlightService>,
495 IFloodlightService> m =
496 new HashMap<Class<? extends IFloodlightService>,
497 IFloodlightService>();
498 m.put(IFlowService.class, this);
499 return m;
500 }
501
502 @Override
503 public Collection<Class<? extends IFloodlightService>>
504 getModuleDependencies() {
505 Collection<Class<? extends IFloodlightService>> l =
506 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800507 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800508 l.add(IRestApiService.class);
509 return l;
510 }
511
512 @Override
513 public void init(FloodlightModuleContext context)
514 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700515 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800516 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800517 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800518 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
519 EnumSet.of(OFType.FLOW_MOD),
520 OFMESSAGE_DAMPER_TIMEOUT);
521 // TODO: An ugly hack!
522 String conf = "/tmp/cassandra.titan";
523 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800524 }
525
526 @Override
527 public void startUp(FloodlightModuleContext context) {
528 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700529
530 //
531 // Extract all flow entries and assign the next Flow Entry ID
532 // to be larger than the largest Flow Entry ID
533 //
534 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
535 for (IFlowEntry flowEntryObj : allFlowEntries) {
536 FlowEntryId flowEntryId =
537 new FlowEntryId(flowEntryObj.getFlowEntryId());
538 if (flowEntryId.value() >= nextFlowEntryId)
539 nextFlowEntryId = flowEntryId.value() + 1;
540 }
541 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800542 }
543
544 /**
545 * Add a flow.
546 *
547 * Internally, ONOS will automatically register the installer for
548 * receiving Flow Path Notifications for that path.
549 *
550 * @param flowPath the Flow Path to install.
551 * @param flowId the return-by-reference Flow ID as assigned internally.
552 * @return true on success, otherwise false.
553 */
554 @Override
555 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700556 if (flowPath.flowId().value() == measurementFlowId) {
557 modifiedMeasurementFlowTime = System.nanoTime();
558 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800559
560 //
561 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700562 // Right now every new flow entry gets a new flow entry ID
563 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800564 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800565 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700566 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800567 flowEntry.setFlowEntryId(new FlowEntryId(id));
568 }
569
570 IFlowPath flowObj = null;
571 try {
572 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
573 != null) {
574 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
575 flowPath.flowId().toString());
576 } else {
577 flowObj = conn.utils().newFlowPath(conn);
578 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
579 flowPath.flowId().toString());
580 }
581 } catch (Exception e) {
582 // TODO: handle exceptions
583 conn.endTx(Transaction.ROLLBACK);
584 log.error(":addFlow FlowId:{} failed",
585 flowPath.flowId().toString());
586 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700587 if (flowObj == null) {
588 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800589 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700590 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800591
592 //
593 // Set the Flow key:
594 // - flowId
595 //
596 flowObj.setFlowId(flowPath.flowId().toString());
597 flowObj.setType("flow");
598
599 //
600 // Set the Flow attributes:
601 // - flowPath.installerId()
602 // - flowPath.dataPath().srcPort()
603 // - flowPath.dataPath().dstPort()
604 //
605 flowObj.setInstallerId(flowPath.installerId().toString());
606 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
607 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
608 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
609 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
610
611 // Flow edges:
612 // HeadFE
613
614
615 //
616 // Flow Entries:
617 // flowPath.dataPath().flowEntries()
618 //
619 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
620 IFlowEntry flowEntryObj = null;
621 boolean found = false;
622 try {
623 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
624 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
625 flowEntry.flowEntryId().toString());
626 found = true;
627 } else {
628 flowEntryObj = conn.utils().newFlowEntry(conn);
629 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
630 flowEntry.flowEntryId().toString());
631 }
632 } catch (Exception e) {
633 // TODO: handle exceptions
634 conn.endTx(Transaction.ROLLBACK);
635 log.error(":addFlow FlowEntryId:{} failed",
636 flowEntry.flowEntryId().toString());
637 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700638 if (flowEntryObj == null) {
639 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800640 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700641 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800642
643 //
644 // Set the Flow Entry key:
645 // - flowEntry.flowEntryId()
646 //
647 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
648 flowEntryObj.setType("flow_entry");
649
650 //
651 // Set the Flow Entry attributes:
652 // - flowEntry.flowEntryMatch()
653 // - flowEntry.flowEntryActions()
654 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800655 // - flowEntry.flowEntryUserState()
656 // - flowEntry.flowEntrySwitchState()
657 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700658 // - flowEntry.matchInPort()
659 // - flowEntry.matchEthernetFrameType()
660 // - flowEntry.matchSrcIPv4Net()
661 // - flowEntry.matchDstIPv4Net()
662 // - flowEntry.matchSrcMac()
663 // - flowEntry.matchDstMac()
664 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800665 //
666 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700667 if (flowEntry.flowEntryMatch().matchInPort())
668 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
669 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
670 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
671 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
672 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
673 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
674 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
675 if (flowEntry.flowEntryMatch().matchSrcMac())
676 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
677 if (flowEntry.flowEntryMatch().matchDstMac())
678 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
679
680 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
681 if (fa.actionOutput() != null)
682 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
683 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800684 // TODO: Hacks with hard-coded state names!
685 if (found)
686 flowEntryObj.setUserState("FE_USER_MODIFY");
687 else
688 flowEntryObj.setUserState("FE_USER_ADD");
689 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
690 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800691 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800692 // and FlowEntryErrorState.
693 //
694
695 // Flow Entries edges:
696 // Flow
697 // NextFE
698 // InPort
699 // OutPort
700 // Switch
701 if (! found)
702 flowObj.addFlowEntry(flowEntryObj);
703 }
704 conn.endTx(Transaction.COMMIT);
705
706 //
707 // TODO: We need a proper Flow ID allocation mechanism.
708 //
709 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700710
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800711 return true;
712 }
713
714 /**
715 * Delete a previously added flow.
716 *
717 * @param flowId the Flow ID of the flow to delete.
718 * @return true on success, otherwise false.
719 */
720 @Override
721 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700722 if (flowId.value() == measurementFlowId) {
723 modifiedMeasurementFlowTime = System.nanoTime();
724 }
725
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800726 IFlowPath flowObj = null;
727 //
728 // We just mark the entries for deletion,
729 // and let the switches remove each individual entry after
730 // it has been removed from the switches.
731 //
732 try {
733 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
734 != null) {
735 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
736 flowId.toString());
737 } else {
738 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
739 flowId.toString());
740 }
741 } catch (Exception e) {
742 // TODO: handle exceptions
743 conn.endTx(Transaction.ROLLBACK);
744 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
745 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700746 if (flowObj == null) {
747 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800748 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700749 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800750
751 //
752 // Find and mark for deletion all Flow Entries
753 //
754 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
755 boolean empty = true; // TODO: an ugly hack
756 for (IFlowEntry flowEntryObj : flowEntries) {
757 empty = false;
758 // flowObj.removeFlowEntry(flowEntryObj);
759 // conn.utils().removeFlowEntry(conn, flowEntryObj);
760 flowEntryObj.setUserState("FE_USER_DELETE");
761 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
762 }
763 // Remove from the database empty flows
764 if (empty)
765 conn.utils().removeFlowPath(conn, flowObj);
766 conn.endTx(Transaction.COMMIT);
767
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800768 return true;
769 }
770
771 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700772 * Clear the state for a previously added flow.
773 *
774 * @param flowId the Flow ID of the flow to clear.
775 * @return true on success, otherwise false.
776 */
777 @Override
778 public boolean clearFlow(FlowId flowId) {
779 IFlowPath flowObj = null;
780 try {
781 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
782 != null) {
783 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
784 flowId.toString());
785 } else {
786 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
787 flowId.toString());
788 }
789 } catch (Exception e) {
790 // TODO: handle exceptions
791 conn.endTx(Transaction.ROLLBACK);
792 log.error(":clearFlow FlowId:{} failed", flowId.toString());
793 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700794 if (flowObj == null) {
795 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700796 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700797 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700798
799 //
800 // Remove all Flow Entries
801 //
802 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
803 for (IFlowEntry flowEntryObj : flowEntries) {
804 flowObj.removeFlowEntry(flowEntryObj);
805 conn.utils().removeFlowEntry(conn, flowEntryObj);
806 }
807 // Remove the Flow itself
808 conn.utils().removeFlowPath(conn, flowObj);
809 conn.endTx(Transaction.COMMIT);
810
811 return true;
812 }
813
814 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800815 * Get a previously added flow.
816 *
817 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800818 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800819 */
820 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800821 public FlowPath getFlow(FlowId flowId) {
822 IFlowPath flowObj = null;
823 try {
824 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
825 != null) {
826 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
827 flowId.toString());
828 } else {
829 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
830 flowId.toString());
831 }
832 } catch (Exception e) {
833 // TODO: handle exceptions
834 conn.endTx(Transaction.ROLLBACK);
835 log.error(":getFlow FlowId:{} failed", flowId.toString());
836 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700837 if (flowObj == null) {
838 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800839 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700840 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800841
842 //
843 // Extract the Flow state
844 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800845 FlowPath flowPath = extractFlowPath(flowObj);
846 conn.endTx(Transaction.COMMIT);
847
848 return flowPath;
849 }
850
851 /**
852 * Get all previously added flows by a specific installer for a given
853 * data path endpoints.
854 *
855 * @param installerId the Caller ID of the installer of the flow to get.
856 * @param dataPathEndpoints the data path endpoints of the flow to get.
857 * @return the Flow Paths if found, otherwise null.
858 */
859 @Override
860 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
861 DataPathEndpoints dataPathEndpoints) {
862 //
863 // TODO: The implementation below is not optimal:
864 // We fetch all flows, and then return only the subset that match
865 // the query conditions.
866 // We should use the appropriate Titan/Gremlin query to filter-out
867 // the flows as appropriate.
868 //
869 ArrayList<FlowPath> allFlows = getAllFlows();
870
871 if (allFlows == null) {
872 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
873 return null;
874 }
875
876 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
877 for (FlowPath flow : allFlows) {
878 //
879 // TODO: String-based comparison is sub-optimal.
880 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800881 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800882 //
883 if (! flow.installerId().toString().equals(installerId.toString()))
884 continue;
885 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
886 continue;
887 }
888 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
889 continue;
890 }
891 flowPaths.add(flow);
892 }
893
894 if (flowPaths.isEmpty()) {
895 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
896 flowPaths = null;
897 } else {
898 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
899 }
900
901 return flowPaths;
902 }
903
904 /**
905 * Get all installed flows by all installers for given data path endpoints.
906 *
907 * @param dataPathEndpoints the data path endpoints of the flows to get.
908 * @return the Flow Paths if found, otherwise null.
909 */
910 @Override
911 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
912 //
913 // TODO: The implementation below is not optimal:
914 // We fetch all flows, and then return only the subset that match
915 // the query conditions.
916 // We should use the appropriate Titan/Gremlin query to filter-out
917 // the flows as appropriate.
918 //
919 ArrayList<FlowPath> allFlows = getAllFlows();
920
921 if (allFlows == null) {
922 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
923 return null;
924 }
925
926 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
927 for (FlowPath flow : allFlows) {
928 //
929 // TODO: String-based comparison is sub-optimal.
930 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800931 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800932 //
933 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
934 continue;
935 }
936 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
937 continue;
938 }
939 flowPaths.add(flow);
940 }
941
942 if (flowPaths.isEmpty()) {
943 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
944 flowPaths = null;
945 } else {
946 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
947 }
948
949 return flowPaths;
950 }
951
952 /**
953 * Get all installed flows by all installers.
954 *
955 * @return the Flow Paths if found, otherwise null.
956 */
957 @Override
958 public ArrayList<FlowPath> getAllFlows() {
959 Iterable<IFlowPath> flowPathsObj = null;
960
961 try {
962 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
963 log.debug("Get all FlowPaths: found FlowPaths");
964 } else {
965 log.debug("Get all FlowPaths: no FlowPaths found");
966 }
967 } catch (Exception e) {
968 // TODO: handle exceptions
969 conn.endTx(Transaction.ROLLBACK);
970 log.error(":getAllFlowPaths failed");
971 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700972 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
973 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800974 return null; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700975 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800976
977 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
978 for (IFlowPath flowObj : flowPathsObj) {
979 //
980 // Extract the Flow state
981 //
982 FlowPath flowPath = extractFlowPath(flowObj);
983 flowPaths.add(flowPath);
984 }
985
986 conn.endTx(Transaction.COMMIT);
987
988 return flowPaths;
989 }
990
991 /**
992 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
993 *
994 * @param flowObj the object to extract the Flow Path State from.
995 * @return the extracted Flow Path State.
996 */
997 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800998 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800999
1000 //
1001 // Extract the Flow state
1002 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001003 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
1004 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
1005 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
1006 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
1007 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
1008 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
1009
1010 //
1011 // Extract all Flow Entries
1012 //
1013 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1014 for (IFlowEntry flowEntryObj : flowEntries) {
1015 FlowEntry flowEntry = new FlowEntry();
1016 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
1017 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001018
1019 //
1020 // Extract the match conditions
1021 //
1022 FlowEntryMatch match = new FlowEntryMatch();
1023 Short matchInPort = flowEntryObj.getMatchInPort();
1024 if (matchInPort != null)
1025 match.enableInPort(new Port(matchInPort));
1026 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1027 if (matchEthernetFrameType != null)
1028 match.enableEthernetFrameType(matchEthernetFrameType);
1029 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1030 if (matchSrcIPv4Net != null)
1031 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1032 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1033 if (matchDstIPv4Net != null)
1034 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1035 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1036 if (matchSrcMac != null)
1037 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1038 String matchDstMac = flowEntryObj.getMatchDstMac();
1039 if (matchDstMac != null)
1040 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1041 flowEntry.setFlowEntryMatch(match);
1042
1043 //
1044 // Extract the actions
1045 //
1046 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1047 Short actionOutputPort = flowEntryObj.getActionOutput();
1048 if (actionOutputPort != null) {
1049 FlowEntryAction action = new FlowEntryAction();
1050 action.setActionOutput(new Port(actionOutputPort));
1051 actions.add(action);
1052 }
1053 flowEntry.setFlowEntryActions(actions);
1054
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001055 String userState = flowEntryObj.getUserState();
1056 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1057 String switchState = flowEntryObj.getSwitchState();
1058 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1059 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001060 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001061 // and FlowEntryErrorState.
1062 //
1063 flowPath.dataPath().flowEntries().add(flowEntry);
1064 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001065
1066 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001067 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001068}